diff --git a/src/main/java/net/minecraftforge/registries/ForgeRegistry.java b/src/main/java/net/minecraftforge/registries/ForgeRegistry.java index 1e06da1cd..947c5564c 100644 --- a/src/main/java/net/minecraftforge/registries/ForgeRegistry.java +++ b/src/main/java/net/minecraftforge/registries/ForgeRegistry.java @@ -70,6 +70,7 @@ public class ForgeRegistry> implements IForgeRe private final CreateCallback create; private final AddCallback add; private final ClearCallback clear; + private final ValidateCallback validate; private final MissingFactory missing; private final BitSet availabilityMap; private final Set dummies = Sets.newHashSet(); @@ -86,7 +87,7 @@ public class ForgeRegistry> implements IForgeRe private V defaultValue = null; boolean isFrozen = false; - ForgeRegistry(Class superType, ResourceLocation defaultKey, int min, int max, @Nullable CreateCallback create, @Nullable AddCallback add, @Nullable ClearCallback clear, RegistryManager stage, boolean allowOverrides, boolean isModifiable, @Nullable DummyFactory dummyFactory, @Nullable MissingFactory missing) + ForgeRegistry(Class superType, ResourceLocation defaultKey, int min, int max, @Nullable CreateCallback create, @Nullable AddCallback add, @Nullable ClearCallback clear, @Nullable ValidateCallback validate, RegistryManager stage, boolean allowOverrides, boolean isModifiable, @Nullable DummyFactory dummyFactory, @Nullable MissingFactory missing) { this.stage = stage; this.superType = superType; @@ -97,6 +98,7 @@ public class ForgeRegistry> implements IForgeRe this.create = create; this.add = add; this.clear = clear; + this.validate = validate; this.missing = missing; this.isDelegated = IForgeRegistryEntry.Impl.class.isAssignableFrom(superType); //TODO: Make this IDelegatedRegistryEntry? this.allowOverrides = allowOverrides; @@ -269,7 +271,7 @@ public class ForgeRegistry> implements IForgeRe ForgeRegistry copy(RegistryManager stage) { - return new ForgeRegistry(superType, defaultKey, min, max, create, add, clear, stage, allowOverrides, isModifiable, dummyFactory, missing); + return new ForgeRegistry(superType, defaultKey, min, max, create, add, clear, validate, stage, allowOverrides, isModifiable, dummyFactory, missing); } int add(int id, V value) @@ -464,6 +466,10 @@ public class ForgeRegistry> implements IForgeRe if (blockedIds.contains(id)) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, name %s, marked as dangling.", registryName, obj, id, name)); */ + + // registry-specific validation + if (this.validate != null) + this.validate.onValidate(this, this.stage, id, name, obj); } } diff --git a/src/main/java/net/minecraftforge/registries/GameData.java b/src/main/java/net/minecraftforge/registries/GameData.java index e9d7de8d9..afd6d8710 100644 --- a/src/main/java/net/minecraftforge/registries/GameData.java +++ b/src/main/java/net/minecraftforge/registries/GameData.java @@ -402,10 +402,22 @@ public class GameData } } - private static class RecipeCallbacks implements IForgeRegistry.MissingFactory + private static class RecipeCallbacks implements IForgeRegistry.ValidateCallback, IForgeRegistry.MissingFactory { static final RecipeCallbacks INSTANCE = new RecipeCallbacks(); + @Override + public void onValidate(IForgeRegistryInternal owner, RegistryManager stage, int id, ResourceLocation key, IRecipe obj) + { + if (stage != RegistryManager.ACTIVE) return; + // verify the recipe output yields a registered item + Item item = obj.getRecipeOutput().getItem(); + if (!stage.getRegistry(Item.class).containsValue(item)) + { + throw new IllegalStateException(String.format("Recipe %s (%s) produces unregistered item %s (%s)", key, obj, item.getRegistryName(), item)); + } + } + @Override public IRecipe createMissing(ResourceLocation key, boolean isNetwork) { diff --git a/src/main/java/net/minecraftforge/registries/IForgeRegistry.java b/src/main/java/net/minecraftforge/registries/IForgeRegistry.java index 767c7774d..dcab55d7d 100644 --- a/src/main/java/net/minecraftforge/registries/IForgeRegistry.java +++ b/src/main/java/net/minecraftforge/registries/IForgeRegistry.java @@ -94,6 +94,14 @@ public interface IForgeRegistry> extends Iterab void onCreate(IForgeRegistryInternal owner, RegistryManager stage); } + /** + * Callback fired when the registry contents are validated. + */ + interface ValidateCallback> + { + void onValidate(IForgeRegistryInternal owner, RegistryManager stage, int id, ResourceLocation key, V obj); + } + /** * Factory for creating dummy entries, allowing worlds to be loaded and keep the missing block references. */ diff --git a/src/main/java/net/minecraftforge/registries/RegistryBuilder.java b/src/main/java/net/minecraftforge/registries/RegistryBuilder.java index 667c27f98..b6f141613 100644 --- a/src/main/java/net/minecraftforge/registries/RegistryBuilder.java +++ b/src/main/java/net/minecraftforge/registries/RegistryBuilder.java @@ -38,6 +38,7 @@ public class RegistryBuilder> private List> addCallback = Lists.newArrayList(); private List> clearCallback = Lists.newArrayList(); private List> createCallback = Lists.newArrayList(); + private List> validateCallback = Lists.newArrayList(); private boolean saveToDisc = true; private boolean allowOverrides = true; private boolean allowModifications = false; @@ -83,6 +84,8 @@ public class RegistryBuilder> this.add((ClearCallback)inst); if (inst instanceof CreateCallback) this.add((CreateCallback)inst); + if (inst instanceof ValidateCallback) + this.add((ValidateCallback)inst); if (inst instanceof DummyFactory) this.set((DummyFactory)inst); if (inst instanceof MissingFactory) @@ -108,6 +111,12 @@ public class RegistryBuilder> return this; } + public RegistryBuilder add(ValidateCallback validate) + { + this.validateCallback.add(validate); + return this; + } + public RegistryBuilder set(DummyFactory factory) { this.dummyFactory = factory; @@ -141,7 +150,7 @@ public class RegistryBuilder> public IForgeRegistry create() { return RegistryManager.ACTIVE.createRegistry(registryName, registryType, optionalDefaultKey, minId, maxId, - getAdd(), getClear(), getCreate(), saveToDisc, allowOverrides, allowModifications, dummyFactory, missingFactory); + getAdd(), getClear(), getCreate(), getValidate(), saveToDisc, allowOverrides, allowModifications, dummyFactory, missingFactory); } @Nullable @@ -188,4 +197,19 @@ public class RegistryBuilder> cb.onCreate(owner, stage); }; } + + @Nullable + private ValidateCallback getValidate() + { + if (validateCallback.isEmpty()) + return null; + if (validateCallback.size() == 1) + return validateCallback.get(0); + + return (owner, stage, id, key, obj) -> + { + for (ValidateCallback cb : this.validateCallback) + cb.onValidate(owner, stage, id, key, obj); + }; + } } diff --git a/src/main/java/net/minecraftforge/registries/RegistryManager.java b/src/main/java/net/minecraftforge/registries/RegistryManager.java index a06ddeb70..3b7d915c9 100644 --- a/src/main/java/net/minecraftforge/registries/RegistryManager.java +++ b/src/main/java/net/minecraftforge/registries/RegistryManager.java @@ -75,7 +75,7 @@ public class RegistryManager } > ForgeRegistry createRegistry(ResourceLocation name, Class type, ResourceLocation defaultKey, int min, int max, - @Nullable AddCallback add, @Nullable ClearCallback clear, @Nullable CreateCallback create, + @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(); @@ -87,7 +87,7 @@ public class RegistryManager 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, this, allowOverrides, isModifiable, dummyFactory, missing); + 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) diff --git a/src/test/java/net/minecraftforge/debug/mod/RegistryOverrideTest.java b/src/test/java/net/minecraftforge/debug/mod/RegistryOverrideTest.java index 0f35529ba..33cd68bb3 100644 --- a/src/test/java/net/minecraftforge/debug/mod/RegistryOverrideTest.java +++ b/src/test/java/net/minecraftforge/debug/mod/RegistryOverrideTest.java @@ -24,6 +24,7 @@ import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.AxisAlignedBB; @@ -50,6 +51,20 @@ public class RegistryOverrideTest } } + @SubscribeEvent + public static void registerItems(RegistryEvent.Register event) + { + if (!ENABLED) return; + + event.getRegistry().register( + new Item() + .setFull3D() + .setUnlocalizedName("stick") + .setCreativeTab(CreativeTabs.MATERIALS) + .setRegistryName("minecraft:stick") + ); + } + private static class BlockReplacement extends Block { AxisAlignedBB BB = FULL_BLOCK_AABB.contract(0.1, 0, 0.1);