• Forums

Navigation

  • Home
  • Style Guide
  • Getting Started
    • Home
    • Structuring Your Mod
    • Forge Update Checker
  • Concepts
    • Sides
    • Resources
    • Registries
      • Registering Things
      • Creating Registries
      • Injecting Registry Values Into Fields
    • The Fingerprint Violation Event
  • Blocks
    • Home
    • Interaction
  • Blockstates
    • Intro to Blockstates
    • Intro to Blockstate JSONs
    • Forge Blockstate JSON
  • Tile Entities
    • Special Renderer
  • Items
    • Home
    • Loot Tables
  • Events
    • Basic Usage
  • Networking
    • Home
    • Overview
    • SimpleImpl
  • Data Storage
    • Capabilities
    • World Saved Data
    • Extended Entity Properties
  • Utilities
    • OreDictionary
  • Effects
    • Sounds
  • Conventions
    • Versioning
    • Locations
    • Loading Stages
  • Contributing to Forge
    • Getting Started
    • PR Guidlines

Registries

Registration is the process of taking the objects of a mod (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 in a mod and will exhibit great amounts of unexplainable behavior (and probably crash). Some examples of things that need to be registered are Blocks, Items, Biomes.

Most things that require registration in the game are handled by the Forge registries. A registry is a simple object similar to a map that assigns values to keys. Additionally, they automatically assign integer IDs to values. Forge uses registries with ResourceLocation keys to register objects. This allows the ResourceLocation to act like a “registry name” for the object. The registry name for an object may be accessed with get/setRegistryName. The setter can only ever be called once, and calling it twice results in an exception. Every type of registrable object has its own registry, and names in two different registries will not collide. (E.g. there’s a registry for Blocks, and a registry for Items, and a Block and an Item may be registered with the same name mod:example without colliding. However, if two blocks were registered with that name, an exception would be thrown.)

Registering Things

The recommended way to register things is through the RegistryEvents. These events are fired right after preinitialization, In RegistryEvent.NewRegistry, registries should be created. Later, RegistryEvent.Register is fired once for each registered registry. Because Register is a generic event, the event handler should set the type parameter to the type of the object being registered. The event will contain the registry to register things to (getRegistry), and things may be registered with register (or registerAll) on the registry. Here’s an example of an event handler that registers blocks:

@SubscribeEvent
public void registerBlocks(RegistryEvent.Register<Block> event) {
    event.getRegistry().registerAll(block1, block2, ...);
}

The order in which RegistryEvent.Register events fire is alphabetically, with the exception that Block will always fire first, and Item will always fire second, right after Block. After the Register<Block> event has fired, all ObjectHolder annotations are refreshed, and after Register<Item> has fired they are refreshed again. They are refreshed for a third time after all of the other Register events have fired.

RegistryEvents are currently supported for the following types: Block, Item, Potion, Biome, SoundEvent, PotionType, Enchantment, IRecipe, VillagerProfession, EntityEntry

There is another, older way of registering objects into registries, using GameRegistry.register. Anytime something suggests using this method, it should be replaced with an event handler for the appropriate registry event. This method simply finds the registry corresponding to an IForgeRegistryEntry with IForgeRegistryEntry::getRegistryType, and then registers the object to the registry. There is also a convenience overload that takes an IForgeRegistryEntry and a ResourceLocation, which is equivalent to calling IForgeRegistryEntry::setRegistryName, followed by a GameRegistry.register call.

Creating Registries

There’s a global registry where all the other registries are stored. By taking a Class that a registry is supposed to store or its ResourceLocation name, one can retrieve a registry from this registry. For example, one can use GameRegistry.findRegistry(Block.class) to get the registry for blocks. Any mod can create their own registries, and any mod can register things to registries from any other mod. Registries are created by using RegistryBuilder inside a RegistryEvent.NewRegistry event handler. This class takes certain parameters for the registry it will generate, such as the name. the Class of it’s values, and various callbacks for when the registry is changed. Upon calling RegistryBuilder::create, the registry is built, registered to the metaregistry, and returned to the caller.

In order for a class to have a registry, it needs to implement IForgeRegistryEntry. This interface defines getRegistryName(ResourceLocation), setRegistryName(ResourceLocation), and getRegistryType(). getRegistryType is the base Class of the registry the object is to be registered to. It is recommended to extend the default IForgeRegistryEntry.Impl class instead of implementing IForgeRegistryEntry directly. This class also provides two convenience implementations of setRegistryName: one where the parameter is a single string, and one where there are two string parameters. The overload that takes a single string checks whether the input contains a : (i.e. it checks whether the passed in stringified ResourceLocation has a domain), and if it doesn’t, it uses the current modid as the resource domain. The two argument overload simply constructs the registry name using the modID as the domain and name as the path.

Injecting Registry Values Into Fields

It is possible to have Forge inject values from registries into public static final fields of classes. This is done by annotating classes and fields with @ObjectHolder. If a class has this annotation, all the public static final fields within are taken to be object holders too, and the value of the annotation is the domain of the holder (i.e. every field uses it as the default domain for the registry name of the object to inject). If a field has this annotation, and the value does not contain a domain, the domain is chosen from the surrounding class’s @ObjectHolder annotation. If the class is not annotated in this situation, the field is ignored with a warning. If it does contain a domain, then the object to inject into the field is the object with that name. If the class has the annotation and one of the public static final fields does not, then the resource path of the object’s name is taken to be the field’s name. The type of the registry is taken from the type of the field.

Note

If an object is not found, either because the object itself hasn’t been registered or because the registry does not exist, a debug message is logged and the field is left unchanged.

As these rules are rather complicated, here are some examples:

@ObjectHolder("minecraft") // Resource domain "minecraft"
class AnnotatedHolder {
    public static final Block diamond_block = null; // public static final is required.
                                                    // Type Block means that the Block registry will be queried.
                                                    // diamond_block is the field name, and as the field is not annotated it is taken to be the resource path.
                                                    // As there is no explicit domain, "minecraft" is inherited from the class.
                                                    // Object to be injected: "minecraft:diamond_block" from the Block registry.

    @ObjectHolder("ender_eye")
    public static final Item eye_of_ender = null;   // Type Item means that the Item registry will be queried.
                                                    // As the annotation has the value "ender_eye", that overrides the field's name.
                                                    // As the domain is not explicit, "minecraft" is inherited from the class.
                                                    // Object to be injected: "minecraft:ender_eye" from the Item registry.

    @ObjectHolder("neomagicae:coffeinum")
    public static final ManaType coffeinum = null;  // Type ManaType means that the ManaType registry will be queried. This is obviously a registry made by a mod.
                                                    // As the annotation has the value "neomagicae:coffeinum", that overrides the field's name.
                                                    // The domain is explicit, and is "neomagicae", overriding the class's "minecraft" default.
                                                    // Object to be injected: "neomagicae:coffeinum" from the ManaType registry.

    public static final Item ENDER_PEARL = null;    // Note that the actual name is "minecraft:ender_pearl", not "minecraft:ENDER_PEARL".
                                                    // However, since constructing a ResourceLocation lowercases the value, this will work.
}

class UnannotatedHolder { // Note lack of annotation on this class.
    @ObjectHolder("minecraft:flame")
    public static final Enchantment flame = null;   // No annotation on the class means that there is no preset domain to inherit.
                                                    // Field annotation supplies all the information for the object.
                                                    // Object to be injected: "minecraft:flame" from the Enchantment registry.

    public static final Biome ice_flat = null;      // No annotation on the class or the field.
                                                    // Therefore this just gets ignored.

    @ObjectHolder("levitation")
    public static final Potion levitation = null;   // No resource domain in annotation, and no default specified by class annotation.
                                                    // Therefore, THIS WILL FAIL. The field annotation needs a domain, or the class needs an annotation.
}
Previous Next
Built with MkDocs using a custom theme. Hosted by Read the Docs.