Highly Suspect Agency

Registry deep dive

Another notes page!


namespace, a string value, a string

These are "block ids", you're familiar with em


A bidirectional mapping from ResourceLocation to T.

DefaultedRegistry (subinterface)

When you call .get() on a ResourceLocation that isn't registered in the registry, you get the "default" object (think "pig spawners", "missing blocks being replaced with air")

WritableRegistry (subinterface)

Exposes a .register method.

Actually, all of the registries implement WritableRegistry. Not exposing the WritableRegistry interface is just a "casting away const" thing.





First, BuiltInRegistries is populated.

  1. In all initialization paths (client, server, datagen), Bootstrap.bootStrap() is called very early.
  2. Bootstrap classloads BuiltInRegistries (by referencing BuiltInRegistries.REGISTRY).
  3. BuiltInRegistries contains lots of fields, each defining a registry type. As the fields of the class are loaded, one by one:
  1. Bootstrap continues to call some miscellaneous functions, eventually calling BuiltInRegistries.bootStrap().
  2. This calls BuiltInRegistries.createContents(), which calls every LOADERS function in turn.
  1. Next, .freeze() is called on the root registry & all registries inside it.
  1. Next, .validate() is called, which just checks that no registries are empty & defaulted registries actually have a default item.

zomg when is forge??

Forge later unfreezes the registries, fires registry events, then freezes them again


A view into a collection of registries.

The operations are:

registry layers

Registry layers solve two problems:

Enter LayeredRegistryAccess. This is a Map<RegistryLayer, RegistryAccess> in disguise.

On the server, the LayeredRegistryAccess is kept in MinecraftServer.registries(), and on the client, ClientPacketListener.registryAccess. (There's a third one in PlayerList but it's just another reference to the one from MinecraftServer.)

On the server, there are four registry layers - STATIC, WORLDGEN, DIMENSIONS, and RELOADABLE. (Notice how things like configured features are placed in dimensions, dimensions consist of biomes and other worldgen stuff, and all that is built of built-in registry items - you can see how they form a hierarchy, where each layer builds on things registered in the previous layer.) On the client there are just two - STATIC and REMOTE.

The STATIC layer (on both sides) is composed of a RegistryAccess that exposes BuiltInRegistries. True to name, the contents of the STATIC layer can be accessed from anywhere. Deeper layers cannot be, because they require access to more state - you can't know the "list of configured features" in a context with no minecraft server to query datapacks from.

As far as I can tell, each layer consists of a nonoverlapping set of registries, i.e. every registry in the game belongs to, at most, one layer; you can't combine statically-registered blocks with dynamically-registered blocks. This is checked.

The operations on LayeredRegistryAccess are:

On the client, the REMOTE layer is populated in ClientboundPacketListener.handleLogin only. Registries in the REMOTE layer:

The contents of these registries are synced from server to client in the initial login packet. The client does not know about many registries that aren't pertinent to it (like the configured feature registry).

On the server, the WORLDGEN, DIMENSIONS, and RELOADABLE layers are all populated in WorldLoader.load. The RELOADABLE layer is also reloaded in MinecraftServer.reloadResources, of course.

Registries in the WORLDGEN layer on the server:

Registries in the DIMENSIONS layer on the server... just this one:

Registries in the RELOADABLE layer on the server: