Changes

7,858 bytes added ,  22:19, 7 January 2021
Rewrite registration, ObjectHolder section kept the same as its already quite detailed
Line 1: Line 1: −
Registration is the process of taking the objects of a mod (such as items, blocks, sounds, etc.) and making them known to the game. Registering things is important, as without registration the game will simply not know about these objects, which will cause unexplainable behaviors and crashes.
+
{{Under construction}}
   −
Most things that require registration in the game are handled by the Forge registries. A registry is an object similar to a map that assigns values to keys. Forge uses registries with [[Using Resources#ResourceLocation|ResourceLocation]] keys to register objects. This allows the <code>ResourceLocation</code> to act as the "registry name" for objects. The registry name for an object may be accessed with <code>#getRegistryName</code>/<code>#setRegistryName</code>. The setter can only be called once; calling it twice results in an exception.
+
Registration is the process of making an object (such as an item or block) known to the game during runtime. If some objects are not registered, this could cause crashes even before the game is fully loaded or arbitrary behaviors such as bottlenecking mod compatibility for world generation.
   −
Every type of registrable object has its own registry. To see all registries supported by Forge, see the <code>ForgeRegistries</code> class. All registry names within a registry always be unique; attempting to register with an already existing registry name will cause the newly registered object to override whatever was registered previously. However, names in different registries will not collide. For example, there's a <code>Block</code> registry, and an <code>Item</code> registry. A <code>Block</code> and an <code>Item</code> may be registered with the same name <code>example:thing</code> without colliding; however, if two different <code>Block</code>s or <code>Item</code>s were registered with the same exact name, the second object will override the first.
+
Most objects that are known within the game are handled by a <code>Registry</code>. Each registry uniquely defines each object through a "registry name" via a [[Using Resources#ResourceLocation|ResourceLocation]]. This "registry name" can be accessed with its respective getter and setter: <code>#getRegistryName</code> and <code>#setRegistryName</code>. You can only set the "registry name" of a given object once; otherwise, an exception will be thrown.
 +
 
 +
{{Tip|In a global context, each object is universally unique through its <code>RegistryKey</code>: a concatenation of its registry's id and the object's registry name.}}
 +
 
 +
Due to the inconsistent ordering and registration process vanilla uses, Forge wraps most vanilla registries using <code>IForgeRegistry</code>. This guarantees that the loading order for these wrapped registries will be <code>Block</code>, <code>Item</code>, and then the rest of the wrapped registries in alphabetical order. All registries supported by Forge can be found within the <code>ForgeRegistries</code> class. Since all registry names are unique to a specific registry, different registry objects within different registries can have the same name (e.g. a <code>Block</code> and an <code>Item</code> each hold a registry object named <code>examplemod:object</code>.
 +
 
 +
{{Tip/Warning|If two registry objects within the same registry have the same name, the second object will override the first. The only registry that will throw an <code>IllegalArgumentException</code> is the <code>DataSerializerEntry</code> registry.}}
    
== Methods for Registering ==
 
== Methods for Registering ==
   −
There are two proper ways to register objects: the <code>DeferredRegister</code> class, and the <code>RegistryEvent.Register</code> lifecycle event.
+
There are two proper ways to register objects within an associated wrapped Forge registry: the <code>DeferredRegister</code> class, and the <code>RegistryEvent$Register</code> lifecycle event.
 +
 
 +
For objects with '''no''' associated Forge registry, you can register the associated entry during the <code>FMLCommonSetupEvent</code> lifecycle event. In some cases, although not recommended, you may also statically initialize and register these entries.
    
=== DeferredRegister ===
 
=== DeferredRegister ===
   −
<code>DeferredRegister</code> is the newer and documented way to register objects. It allows the use and convenience of static initialisers while avoiding the issues associated with it. It simply maintains a list of suppliers for entries and registers the objects from those suppliers during the proper <code>RegistryEvent.Register</code> event.
+
<code>DeferredRegister</code> is an abstraction layer over the registry event used to register objects. It maintains a map of "registry name" to their associated suppliers and resolves those suppliers during the proper <code>RegistryEvent$Register</code> event. This method is the currently recommended, and documented, way to handle these objects as it provides convenience and safety for those who want to statically initialize objects while avoiding some issues associated with it.  
    
An example of a mod registering a custom block:
 
An example of a mod registering a custom block:
Line 18: Line 26:  
private static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MODID);
 
private static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MODID);
   −
public static final RegistryObject<Block> ROCK_BLOCK = BLOCKS.register("rock", () -> new Block(Block.Properties.create(Material.ROCK)));
+
public static final RegistryObject<Block> EXAMPLE_BLOCK = BLOCKS.register("example_block", () -> new Block(Block.Properties.create(Material.ROCK)));
    
public ExampleMod() {
 
public ExampleMod() {
Line 25: Line 33:  
</syntaxhighlight>
 
</syntaxhighlight>
   −
=== RegistryEvent.Register ===
+
{{Tip|When using a <code>DeferredRegister</code> to register any object, the name inputted will be automatically prefixed with the mod id passed in, giving the above object a "registry name" of <code>examplemod:example_block</code>.}}
   −
The <code>RegistryEvent</code>s are the second and more flexible way to register objects. These [[Events|events]] are fired after the mod constructors and before the loading of configs.
+
=== RegistryEvent$Register ===
   −
The event used in registering objects is the <code>RegistryEvent.Register<T></code>, where the type parameter <code>T</code> is the type of the object being registered. Calling <code>#getRegistry</code> will return the registry, upon which objects are registered with <code>#register</code> (pass it a single object that you want to register) or <code>#registerAll</code> (pass it a list of objects).
+
The <code>RegistryEvent</code>s are another, more slightly flexible way to register objects. These [[Events|events]] are fired synchronously after <code>FMLConstructModEvent</code> and before the configs are loaded.
   −
The latter is very useful for minimising calls to <code>#register</code>.
+
The event used to register objects is <code>RegistryEvent$Register<T></code>, where the type parameter <code>T</code> is the object type being registered. You can grab the associated registry using <code>#getRegistry</code> and register the objects within using either <code>#register</code> (pass in a single object) or <code>#registerAll</code> (pass in ''varargs'' or an array of objects). The latter is useful for minimizing calls to <code>#register</code>, although it provides no benefit time-complexity wise.
   −
Here is an example: (the event handler is registered on the *mod event bus*)
+
{{Tip/Important|The type parameter specified must be the exact class used within the Forge registry, not its superclass nor its subclass. If the class specified is not referenced as a type parameter within the associated Forge registries, then the event will not be called.}}
 +
 
 +
Here is an example: (the event handler is registered on the '''mod event bus''')
    
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
@SubscribeEvent
 
@SubscribeEvent
 
public void registerBlocks(RegistryEvent.Register<Block> event) {
 
public void registerBlocks(RegistryEvent.Register<Block> event) {
     event.getRegistry().registerAll(new Block(...), new Block(...), ...);
+
     event.getRegistry().registerAll(new Block(...).setRegistryName(new ResourceLocation(MODID, "example_block1")), new Block(...).setRegistryName(new ResourceLocation(MODID, "example_block2")), ...);
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
   −
{{Tip/Important|Some classes cannot by themselves be registered; instead, <code>*Type</code> classes are registered, and used in the formers' constructors. For example, [[Tile_Entities|<code>TileEntity</code>]] has <code>TileEntityType</code>, and <code>Entity</code> has <code>EntityType</code>. These <code>*Type</code> classes are factories that simply create the containing type on demand.
+
{{Tip/Important|Since all objects registered must be singleton, some classes cannot by themselves be registered. Instead, <code>*Type</code> classes are registered and used in the formers' constructors to wrap the flyweight objects. For example, a [[Basics_of_Tile_Entities|<code>TileEntity</code>]] is wrapped via <code>TileEntityType</code>, and <code>Entity</code> is wrapped via <code>EntityType</code>. These <code>*Type</code> classes hold factories that simply create the containing type on demand.
   −
These factories are created through the use of their <code>*Type.Builder</code> classes. An example: (<code>REGISTER</code> here refers to a <code>DeferredRegister<TileEntityType<?>></code>)
+
These factory holders are created through the use of their <code>*Type$Builder</code> classes. An example: (<code>REGISTER</code> here refers to a <code>DeferredRegister<TileEntityType<?>></code>)
    
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
Line 51: Line 61:  
);
 
);
 
</syntaxhighlight>}}
 
</syntaxhighlight>}}
 +
 +
=== Non-Forge Registries ===
 +
 +
Not all vanilla registries are wrapped as a Forge registry. This is because the registry is fully independent from any other registry, completely data driven, or just has not been wrapped yet.
 +
 +
These registries include:
 +
* Custom Stats (a <code>ResourceLocation</code> registry)
 +
* <code>IRuleTestType</code>
 +
* <code>IPosRuleTests</code>
 +
* <code>IRecipeType</code>
 +
* <code>VillagerType</code>
 +
* <code>LootPoolEntryType</code>
 +
* <code>LootFunctionType</code>
 +
* <code>LootConditionType</code>
 +
* <code>IStructurePieceType</code>
 +
* <code>TrunkPlacerType</code>
 +
* <code>FeatureSizeType</code>
 +
* <code>BiomeProvider</code> (A <code>Codec</code> registry)
 +
* <code>ChunkGenerator</code> (A <code>Codec</code> registry)
 +
* <code>IStructureProcessorType</code>
 +
* <code>IJigsawDeserializer</code>
 +
* All registries within <code>WorldGenRegistries</code> excluding <code>Biome</code>
 +
 +
To register objects to any one of these registries, you will need to call <code>Registry::register(Registry, ResourceLocation, T)</code> where the type parameter <code>T</code> is the object instance being registered. The method can then be called and registered during the highest priority of <code>FMLCommonSetupEvent</code>. We can also utilize a <code>Lazy</code> above to store the result on first access and use within our code.
 +
 +
Here is an example: (the event handler is registered on the '''mod event bus''')
 +
 +
<syntaxhighlight lang="java">
 +
public static final Lazy<ConfiguredFeature<?, ?>> EXAMPLE_CONFIGURED_FEATURE = Lazy.of(() ->
 +
    register("example_configured_feature",
 +
        Feature.NO_OP.withConfiguration(NoFeatureConfig.field_236559_b_)
 +
            .withPlacement(Placement.NOPE.configure(NoPlacementConfig.INSTANCE))
 +
    )
 +
);
 +
 +
@SubscribeEvent(priority = EventPriority.HIGHEST)
 +
public void register(FMLCommonSetupEvent event) {
 +
    event.enqueueWork(EXAMPLE_CONFIGURED_FEATURE::get);
 +
}
 +
 +
private static <T extends ConfiguredFeature<?, ?>> T register(String name, T value) {
 +
    return Registry.register(WorldGenRegistries.CONFIGURED_FEATURE, new ResourceLocation(MODID, name), value);
 +
}
 +
</syntaxhighlight>
 +
 +
{{Tip/Warning|Vanilla registry methods are not thread-safe, so they must be wrapped within the synchronous queue provided within the common setup event via <code>#enqueueWork</code>.}}
 +
 +
Besides the registries within <code>WorldGenRegistries</code>, all other '''non-forge''' wrapped registries can be statically initialized like so:
 +
 +
<syntaxhighlight lang="java">
 +
public static final IRecipeType<ExampleRecipe> EXAMPLE_RECIPE = IRecipeType.register(MODID + ":example_recipe");
 +
</syntaxhighlight>
 +
 +
If you attempt to make one of these instances require an instance of another registry object, you must use the lazy initialization method mentioned above to register the object in the correct order.
 +
 +
=== Data Driven Entries ===
 +
 +
Registries are considered to be data driven if they are located within <code>DynamicRegistries</code> with the exception of <code>Dimension</code>.
 +
 +
The following registries are data driven:
 +
* <code>ConfiguredSurfaceBuilder</code>
 +
* <code>ConfiguredCarver</code>
 +
* <code>ConfiguredFeature</code>
 +
* <code>StructureFeature</code>
 +
* <code>StructureProcessorList</code>
 +
* <code>JigsawPattern</code>
 +
* <code>Biome</code>
 +
* <code>DimensionSettings</code>
 +
* <code>DimensionType</code>
 +
* <code>Dimension</code>
 +
 +
These registry objects only need to be registered within code if they are to be used within a pre-existing registry object (e.g. a <code>ConfiguredFeature</code> for ore generation within an overworld <code>Biome</code>). Otherwise, their instance can be purely registered using a JSON file.
 +
 +
If a data driven registry object has to be registered within code, a dummy object should be supplied to hold a "registry name" and then constructed within a JSON file.
    
== Referencing Registered Objects ==
 
== Referencing Registered Objects ==
   −
Registered objects should not be stored in fields when they are created and registered. They are to be always newly created and registered whenever their respective <code>RegistryEvent.Register</code> event is fired. This is to allow dynamic loading and unloading of mods in a future version of Forge.
+
Each forge registered object should not be statically initialized nor reference another instance being registered. They must always be a new, singleton instance that is resolved during their respective <code>RegistryEvent$Register</code> event. This is to maintain a sane loading order for registries and their objects along with dynamic loading/unloading of mods.
   −
Registered objects must always be referenced through a <code>RegistryObject</code> or a field with <code>@ObjectHolder</code>.
+
Forge registered objects must always be referenced through a <code>RegistryObject</code> or a field with <code>@ObjectHolder</code>.
    
=== Using RegistryObjects ===
 
=== Using RegistryObjects ===
   −
<code>RegistryObject</code>s can be used to retrieve references to registered objects once they are available. These are used by <code>DeferredRegister</code> to return a reference to registered objects. Their references are updated after their corresponding registry's <code>RegistryEvent.Register</code> event is fired, along with the <code>@ObjectHolder</code> annotations.
+
<code>RegistryObject</code>s can be used to retrieve references to registered objects once they become available. Their references are updated along with all <code>@ObjectHolder</code> annotations after the associated <code>RegistryEvent$Register</code> has been dispatched and frozen.
   −
To get a <code>RegistryObject</code>, call <code>RegistryObject.of</code> with a <code>ResourceLocation</code> and the <code>IForgeRegistry</code> of the registrable object. Custom registries can also be used through giving a supplier of the custom object's class. Store the <code>RegistryObject</code> in a <code>public static final</code> field, and call <code>#get</code> whenever you need the registered object.
+
A <code>RegistryObject</code> can be retrieved as a result of using <code>DeferredRegister</code> or calling the static constructor <code>RegistryObject::of</code>. Each static constructor takes in the "registry name" of the object being referenced and either a <code>IForgeRegistry</code> or, if custom registries are used, a supplier of the object class implementing <code>IForgeRegistryEntry</code>. The <code>RegistryObject</code> can be stored within some field and retreive the registered object using <code>#get</code>.
 
  −
An example of using <code>RegistryObject</code>:
      +
An example using <code>RegistryObject</code>:
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
public static final RegistryObject<Item> BOW = RegistryObject.of(new ResourceLocation("minecraft:bow"), ForgeRegistries.ITEMS);
+
public static final RegistryObject<Item> EXAMPLE_ITEM = RegistryObject.of(new ResourceLocation("examplemod:example_item"), ForgeRegistries.ITEMS);
   −
// assume that ManaType is a valid registry, and 'neomagicae:coffeinum' is a valid object within that registry
+
// Assume that 'ExampleRegistry' is a valid registry, and 'examplemod:example_object' is a valid object within that registry
public static final RegistryObject<ManaType> COFFEINUM = RegistryObject.of(new ResourceLocation("neomagicae", "coffeinum"), () -> ManaType.class);  
+
public static final RegistryObject<ExampleRegistry> EXAMPLE_OBJECT = RegistryObject.of(new ResourceLocation("examplemod", "example_object"), () -> ExampleRegistry.class);  
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
{{Tip/Important|All vanilla objects are bootstrapped and registered before mods are loaded. As such, they can be referenced as is without any issues, assuming the entries are not replaced.}}
    
=== Using @ObjectHolder ===
 
=== Using @ObjectHolder ===
   −
Registered objects from registries can be injected into the <code>public static</code> fields by annotating classes or fields with <code>@ObjectHolder</code> and supplying enough information to construct a <code>ResourceLocation</code> to identify a specific object in a specific registry.
+
Forge registry objects can also be injected into <code>public static</code> fields with either their class or that field annotated with <code>@ObjectHolder</code>. There must be enough information to construct a <code>ResourceLocation</code> to identify a single object within a specific registry.
    
The rules for <code>@ObjectHolder</code> are as follows:
 
The rules for <code>@ObjectHolder</code> are as follows:
Line 82: Line 167:  
* If the class is annotated with <code>@Mod</code>, the modid will be the default namespace for all annotated fields within if not explicitly defined  
 
* If the class is annotated with <code>@Mod</code>, the modid will be the default namespace for all annotated fields within if not explicitly defined  
 
* A field is considered for injection if:
 
* A field is considered for injection if:
** it has at least the modifiers <code>public static</code>;
+
** it has at least the modifiers <code>public static</code>; and
 
** one of the following conditions are true:
 
** one of the following conditions are true:
 
*** the '''enclosing class''' has an <code>@ObjectHolder</code> annotation, and the field is <code>final</code>, and:
 
*** the '''enclosing class''' has an <code>@ObjectHolder</code> annotation, and the field is <code>final</code>, and:
 
**** the name value is the field's name; and
 
**** the name value is the field's name; and
 
**** the namespace value is the enclosing class's namespace
 
**** the namespace value is the enclosing class's namespace
**** _An exception is thrown if the namespace value cannot be found and inherited_
+
**** ''An exception is thrown if the namespace value cannot be found and inherited''
 
*** the '''field''' is annotated with <code>@ObjectHolder</code>, and:
 
*** the '''field''' is annotated with <code>@ObjectHolder</code>, and:
 
**** the name value is explicitly defined; and
 
**** the name value is explicitly defined; and
 
**** the namespace value is either explicitly defined or the enclosing class's namespace
 
**** the namespace value is either explicitly defined or the enclosing class's namespace
** the field type or one of its supertypes corresponds to a valid registry (e.g. <code>Item</code> or <code>ArrowItem</code> for the <code>Item</code> registry);
+
** the field type or one of its supertypes corresponds to a valid registry (e.g. <code>Item</code> or <code>ArrowItem</code> for the <code>Item</code> registry)
 
** ''An exception is thrown if a field does not have a corresponding registry.''
 
** ''An exception is thrown if a field does not have a corresponding registry.''
 
* ''An exception is thrown if the resulting <code>ResourceLocation</code> is incomplete or invalid (non-valid characters in path)''
 
* ''An exception is thrown if the resulting <code>ResourceLocation</code> is incomplete or invalid (non-valid characters in path)''
* If no other errors or exceptions occur, the field will be injected 7
+
* If no other errors or exceptions occur, the field will be injected
 
* If all of the above rules do not apply, no action will be taken (and a message may be logged)
 
* If all of the above rules do not apply, no action will be taken (and a message may be logged)
   −
<code>@ObjectHolder</code>-annotated fields are injected with their values after their corresponding registry's <code>RegistryEvent.Register</code> event is fired, along with the <code>RegistryObject</code>s.
+
<code>@ObjectHolder</code> annotated fields are injected with their associated object values after their corresponding registry's <code>RegistryEvent$Register</code> event is fired, along with <code>RegistryObject</code>s.
   −
{{Colored box|title=Informational|content=If the object does not exist in the registry when it is to be injected, a debug message will be logged and no value will be injected.}}
+
{{Tip/Warning|If the object does not exist in the registry when it is to be injected, a debug message will be logged, and no value will be injected. If the object is found, but the field cannot be set, a warning message will be logged instead.}}
    
As these rules are rather complicated, here are some examples:
 
As these rules are rather complicated, here are some examples:
Line 185: Line 270:  
== Creating Custom Registries ==
 
== Creating Custom Registries ==
   −
You might want to create a new registry for your mod. This might be usefull if you want other mods to add new things to your system. For example you might have magic spells and want to allow other mods to add new spells. For this you will want to make a registry (eg. "mymagicmod:spells"). This way other mods will be able to register things to that list and you won't have to do anything else.
+
Creating custom registries for your mod might be useful if you want other mods to add new things to your system. For example, you might have magic spells and want to allow other mods to add new spells. For this you will want to make a registry (eg. "mymagicmod:spells"). This way, other mods will be able to register things to that list, and you won't have to do anything else.
 +
 
 +
Just like with registering a new item or block you have two ways of making a new registry. Each method takes in a <code>RegistryBuilder</code> which is used to build an <code>IForgeRegistry</code> for an object class that implements <code>IForgeRegistryEntry</code>. Each builder should have its name and type set via <code>#setName</code> and <code>#setType</code> respectively before being created.
 +
 
 +
For the class that implements <code>IForgeRegistryEntry</code>, it is recommended in most cases to extend the default implementation of <code>ForgeRegistryEntry</code>. For interfaces, it should extend <code>IForgeRegistryEntry</code> with its implementations extending <code>ForgeRegistryEntry</code>.
 +
 
 +
=== With DeferredRegister ===
 +
 
 +
The first method involves the second static constructor: <code>DeferredRegister::create(Class, String)</code>. The class supplied must extend <code>IForgeRegistryEntry</code>. From there, we can construct the registry using <code>#makeRegistry</code>. This will already populate <code>#setName</code> and <code>#setType</code> for us. This method also returns a supplier of the registry which we can use after the <code>RegistryEvent$NewRegistry</code> event.
 +
 
 +
Here is an example:
   −
Just like with registering a new item or block you have 2 ways of making a new registry.
+
<syntaxhighlight lang="Java">
 +
public static final DeferredRegister<ExampleRegistry> EXAMPLE = DeferredRegister.create(ExampleRegistry.class, MODID);
   −
=== Using RegistryEvent.NewRegistry ===
+
public static final Lazy<IForgeRegistry<ExampleRegistry>> REGISTRY = Lazy.of(EXAMPLE.makeRegistry("example_registry", RegistryBuilder::new));
 +
</syntaxhighlight>
   −
Custom registries are created by using <code>RegistryBuilder</code> during the <code>RegistryEvent.NewRegistry</code> event. The class <code>RegistryBuilder</code> takes certain parameters (such as the registry name, the <code>Class</code> of its values, and various callbacks for different events happening on the registry). Calling <code>RegistryBuilder#create</code> will result in the registry being built, registered to the <code>RegistryManager</code>, and returned to the caller for additional processing.
+
=== Using RegistryEvent$NewRegistry ===
   −
The <code>Class</code> of the value of the registry must implement <code>IForgeRegistryEntry</code>, which defines that <code>#setRegistryName</code> and <code>#getRegistryName</code> can be called on the objects of that class. For most custom objects, is recommended to extend the default implementation of <code>ForgeRegistryEntry</code>, instead of implementing the interface directly. When <code>#setRegistryName(String)</code> is called with a string, and that string does not have an explicit namespace, its namespace will be set to the current modid.
+
The second method can be done during the <code>RegistryEvent$NewRegistry</code> event. This will call a new instance of the builder directly. From there, the registry can be built and stored via <code>RegistryBuilder#create</code>. This will cause the registry to be registered to the <code>RegistryManager</code> and returned to the caller for additional processing.
   −
The Forge registries can be accessed through the <code>ForgeRegistries</code> class. All registries, Forge-provided or custom, can be retrieved by calling <code>GameRegistry.findRegistry(Class)</code> with the appropriate class for the registry. For example, the registry for <code>Block</code>s can be retrieved by calling <code>GameRegistry.findRegistry(Block.class)</code>.
+
Here is an example: (the event handler is registered on the '''mod event bus''')
    
<syntaxhighlight lang="Java">
 
<syntaxhighlight lang="Java">
 +
public static IForgeRegistry<ExampleRegistry> registry = null;
 +
 
@SubscribeEvent
 
@SubscribeEvent
public static void onNewRegistry(RegistryEvent.NewRegistry registry){
+
public void onNewRegistry(RegistryEvent.NewRegistry event){
     RegistryBuilder<ArcaneFuelType> registryBuilder = new RegistryBuilder<ArcaneFuelType>();
+
     RegistryBuilder<ExampleRegistry> registryBuilder = new RegistryBuilder<>();
     registryBuilder.setName(ArcaneRituals.location("arcane_fuel"));
+
     registryBuilder.setName(new ResourceLocation(MODID, "example_registry");
     registryBuilder.setType(ArcaneFuelType.class);
+
     registryBuilder.setType(ExampleRegistry.class);
     registryBuilder.create();
+
     registry = registryBuilder.create();
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
   −
=== With DeferredRegister ===
+
== Handling Missing Entries ==
 +
 
 +
When loading a pre-existing world after removing mods or updating versions, there are cases where certain registry objects will cease to exist. In these cases, it is possible to specify actions to remove a mapping, prevent the world from loading, or remap the name as needed. This can be done through the third of the registry events: <code>RegistryEvent$MissingMappings<T></code>, where the type parameter <code>T</code> is the object type being registered. Within the event, you can grab an immutable list of missing mappings associated with a mod id via <code>#getMappings</code> or a list of all mappings via <code>#getAllMappings</code>.
 +
 
 +
For each <code>Mapping</code>, you can either execute one of the following methods:
 +
* <code>#ignore</code> which abandons the entry when loading
 +
* <code>#warn</code> which warns the user about the missing entry but continues loading
 +
* <code>#fail</code> which prevents the world from loading
 +
* <code>#remap</code> which remaps the entry to the specified non-null object in the same registry
 +
 
 +
If none of the above are specified, then the default action of notifying the user about the missing mappings occur.
 +
 
 +
Here is an example:  (the event handler is registered on the '''mod event bus''')
   −
TODO
+
<syntaxhighlight lang="Java">
 +
// This will ignore any missing test items from the specified world
 +
@SubscribeEvent
 +
public void onMissingItems(RegistryEvent.MissingMappings<Item> event){
 +
    event.getMappings(MODID).stream()
 +
        .filter(mapping -> mapping.key.getPath().contains("test"))
 +
            .forEach(Mapping::ignore);
 +
}
 +
</syntaxhighlight>