Line 1: |
Line 1: |
− | 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. | + | Registration is the process of making an object (such as an item or block) known to the game during runtime with an attached <code>ResourceLocation</code> name. Unregistered objects are a likely cause of game loading crashes or bugs, so it is important to register objects correctly. |
| | | |
− | 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]]. | + | Most objects that are known within the game are handled by a Vanilla <code>Registry</code> or a Forge <code>IForgeRegistry</code>. Each registry uniquely defines each of its own objects through a "registry name" via a [[Using Resources#ResourceLocation|ResourceLocation]]. |
| + | Registries themselves have a name and are registered to the Vanilla root registry or <code>RegistryManager</code>. |
| + | It is important to keep these distinct; although both are called registry names. |
| | | |
| {{Tip|In a global context, each object is universally unique through its <code>ResourceKey</code>: a concatenation of its registry's id and the object's registry name.}} | | {{Tip|In a global context, each object is universally unique through its <code>ResourceKey</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>.
| + | Forge expands Vanilla's registries to add important features for modded environments, such as world saving of integer ids and network syncing of integer ids, to ensure consistency when different mods and entries are present. |
| | | |
− | {{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.}} | + | Forge registries preserves the same loading order of Vanilla registries, with all modded registries fired after Vanilla in alphabetical order by string comparing namespace then path. This loading order determines what order registries have their entries registered. All registries wrapped by Forge can be found within the <code>ForgeRegistries</code> class. |
| + | |
| + | {{Tip|All registries have their own set of names and objects, so the same name (e.g. <code>examplemod:object</code>) can be reused in multiple registries, like blocks and items.}} |
| + | |
| + | {{Tip/Warning|If two registry objects within the '''same''' registry have the same name, the second object will override the first.}} |
| | | |
| == Methods for Registering == | | == Methods for Registering == |
| | | |
− | There are two proper ways to register objects within an associated wrapped Forge registry: the <code>DeferredRegister</code> class, and the <code>RegisterEvent</code> lifecycle event. | + | There are two proper ways to register objects to a Forge registry or Vanilla registry: the <code>DeferredRegister</code> class, and the <code>RegisterEvent</code> lifecycle event. |
| | | |
| === DeferredRegister === | | === DeferredRegister === |
Line 158: |
Line 164: |
| === Using @ObjectHolder === | | === Using @ObjectHolder === |
| | | |
− | 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. | + | Forge registry objects can also be injected into <code>public static final</code> fields by annotating each field with <code>@ObjectHolder</code>. Note that using <code>RegistryObject</code>s is the preferred strategy as ObjectHolders are verbose, clunky, and easy to mess up. |
| + | |
| + | ObjectHolders can only be applied to fields and require 2 pieces of information: the registry name of your target registry and the name of your object entry inside the registry. |
| + | |
| + | The registry name can be found inside of <code>ForgeRegistries.Keys</code> or <code>Registry</code>. |
| + | For blocks, this would be <code>"minecraft:block"</code>. |
| + | For items, this would be <code>"minecraft:item"</code>, etc. |
| + | |
| + | The name of your entry is dependent on what you called it and requires your modid to be prefixed. |
| + | When using <code>@ObjectHolder</code> inside of your main mod class annotated with <code>@Mod</code>, the modid namespace can be omitted. |
| | | |
| The rules for <code>@ObjectHolder</code> are as follows: | | The rules for <code>@ObjectHolder</code> are as follows: |
| | | |
− | * If the class is annotated with <code>@ObjectHolder</code>, its value will be the default namespace for all 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 | | * 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>; and | + | ** it has at least the modifiers <code>public static</code> and optionally <code>final</code>, and |
| ** 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 entry name value is explicitly defined, and |
| *** the registry name value is explicitly defined | | *** the registry name value is explicitly defined |
− | ** ''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 | | * 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 associated object values after <code>RegisterEvent</code> is fired for their registry, along with <code>RegistryObject</code>s. | + | <code>@ObjectHolder</code> annotated fields are injected with their associated object values after <code>RegisterEvent</code> is fired for their registry, the same time that <code>RegistryObject</code>s are filled. ObjectHolders will remain empty if the associated registry does not exist. |
| | | |
| {{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.}} | | {{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.}} |
Line 184: |
Line 197: |
| <syntaxhighlight lang="java"> | | <syntaxhighlight lang="java"> |
| class Holder { | | class Holder { |
− | @ObjectHolder(registryName = "enchantment", value = "minecraft:flame") | + | @ObjectHolder(registryName = "minecraft:enchantment", value = "minecraft:flame") |
| public static final Enchantment flame = null; // Annotation present. [public static] is required. [final] is optional. | | public static final Enchantment flame = null; // Annotation present. [public static] is required. [final] is optional. |
| // Registry name is explicitly defined: "minecraft:enchantment" | | // Registry name is explicitly defined: "minecraft:enchantment" |
Line 194: |
Line 207: |
| | | |
| @ObjectHolder("minecraft:creeper") | | @ObjectHolder("minecraft:creeper") |
− | public static Entity creeper = null; // Annotation present. [public static] is required. | + | public static final Entity creeper = null; // Annotation present. [public static] is required. [final] is optional. |
− | // The registry has not been specified on the field. | + | // The registry name has not been specified on the field. |
− | // Therefore, THIS WILL PRODUCE AN EXCEPTION. | + | // Therefore, this will not compile. |
| | | |
− | @ObjectHolder(registryName = "potion") | + | @ObjectHolder(registryName = "minecraft:potion") |
| public static final Potion levitation = null; // Annotation present. [public static] is required. [final] is optional. | | public static final Potion levitation = null; // Annotation present. [public static] is required. [final] is optional. |
| // Registry name is explicitly defined: "minecraft:potion" | | // Registry name is explicitly defined: "minecraft:potion" |
− | // Resource location is not specified on the field | + | // The entry's name value has not been specified on the field. |
− | // Therefore, THIS WILL PRODUCE AN EXCEPTION. | + | // Therefore, this will not compile. |
| } | | } |
| </syntaxhighlight> | | </syntaxhighlight> |