package net.minecraftforge.registries; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.collect.Sets.SetView; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.common.FMLLog; import net.minecraftforge.registries.ForgeRegistry.Snapshot; import net.minecraftforge.registries.IForgeRegistry.*; public class RegistryManager { public static final RegistryManager ACTIVE = new RegistryManager("ACTIVE"); public static final RegistryManager VANILLA = new RegistryManager("VANILLA"); public static final RegistryManager FROZEN = new RegistryManager("FROZEN"); BiMap>> registries = HashBiMap.create(); private BiMap>, ResourceLocation> superTypes = HashBiMap.create(); private Set persisted = Sets.newHashSet(); private final String name; public RegistryManager(String name) { this.name = name; } public String getName() { return this.name; } @SuppressWarnings("unchecked") public > Class getSuperType(ResourceLocation key) { return (Class)superTypes.inverse().get(key); } @SuppressWarnings("unchecked") public > ForgeRegistry getRegistry(ResourceLocation key) { return (ForgeRegistry)this.registries.get(key); } public > IForgeRegistry getRegistry(Class cls) { return getRegistry(superTypes.get(cls)); } public > ResourceLocation getName(IForgeRegistry reg) { return this.registries.inverse().get(reg); } public > ForgeRegistry getRegistry(ResourceLocation key, RegistryManager other) { if (!this.registries.containsKey(key)) { ForgeRegistry ot = other.getRegistry(key); if (ot == null) return null; this.registries.put(key, ot.copy(this)); this.superTypes.put(ot.getRegistrySuperType(), key); if (other.persisted.contains(key)) this.persisted.add(key); } return getRegistry(key); } > ForgeRegistry createRegistry(ResourceLocation name, Class type, ResourceLocation defaultKey, int min, int max, @Nullable AddCallback add, @Nullable ClearCallback clear, @Nullable CreateCallback create, @Nullable ValidateCallback validate, boolean persisted, boolean allowOverrides, boolean isModifiable, @Nullable DummyFactory dummyFactory, @Nullable MissingFactory missing) { Set> parents = Sets.newHashSet(); findSuperTypes(type, parents); SetView> overlappedTypes = Sets.intersection(parents, superTypes.keySet()); if (!overlappedTypes.isEmpty()) { Class foundType = overlappedTypes.iterator().next(); FMLLog.log.error("Found existing registry of type {} named {}, you cannot create a new registry ({}) with type {}, as {} has a parent of that type", foundType, superTypes.get(foundType), name, type, type); throw new IllegalArgumentException("Duplicate registry parent type found - you can only have one registry for a particular super type"); } ForgeRegistry reg = new ForgeRegistry(type, defaultKey, min, max, create, add, clear, validate, this, allowOverrides, isModifiable, dummyFactory, missing); registries.put(name, reg); superTypes.put(type, name); if (persisted) this.persisted.add(name); return getRegistry(name); } private void findSuperTypes(Class type, Set> types) { if (type == null || type == Object.class) { return; } types.add(type); for (Class interfac : type.getInterfaces()) { findSuperTypes(interfac, types); } findSuperTypes(type.getSuperclass(), types); } public Map takeSnapshot(boolean savingToDisc) { Map ret = Maps.newHashMap(); Set keys = savingToDisc ? this.persisted : this.registries.keySet(); keys.forEach(name -> ret.put(name, getRegistry(name).makeSnapshot())); return ret; } //Public for testing only public void clean() { this.persisted.clear(); this.registries.clear(); this.superTypes.clear(); } }