Skip to content

Instantly share code, notes, and snippets.

@RisingInIris2017
Last active January 13, 2023 07:39
Show Gist options
  • Save RisingInIris2017/e795cac5b6686ea42532c61600522c02 to your computer and use it in GitHub Desktop.
Save RisingInIris2017/e795cac5b6686ea42532c61600522c02 to your computer and use it in GitHub Desktop.

This is a fork of #8522, Silverminer's custom datapack registries PR, with some improvements to documentation and error presentation and streamlining of userdev APIs.

这是 #8522,Silverminer 的自定义数据包注册表 PR 的 Fork,改进了文档说明和报错,简化了供开发者使用的 API。

Datapack Registries, what are they and why might modders want them

数据包注册表是什么,为什么 Modder 们需要它

Datapack registries (sometimes called dynamic registries or worldgen registries) are a system added by Mojang several major versions ago, neither static registries nor reloadable data, but a third system separate from the other two. Datapack registries are created by registering a loading codec and (optionally) a network codec (if the network codec exists, we consider the registry to be a Synced Datapack Registry). Examples of vanilla datapack registries include biomes, dimensiontypes, and placed features.

数据包注册表,或称为动态注册表/世界生成注册表,是一个由 Mojang 在几个大版本之前加入的系统,既非静态注册表,又非可重载的数据,而是第三个系统,独立于前述两者。

注册一个载入编解码器、一个可选的网络编解码器(若网络编解码器存在,我们称该注册表为“同步数据包注册表”),就可以创建数据包注册表。

原版 MC 的数据包注册表的示例,包括群系、维度类型、地形装饰 (biomes, dimensiontypes, and placed features)。

Features of datapack registries (relative to reloadable data)

相对于可重载的数据而言,数据包注册表具有如下特性:

  • Datapack registries have a simplified standard implementation for loading and optionally syncing (which cannot be changed, as opposed to reloadable data which provides lower-level access to data)

  • Datapack registries have half-builtin support for datagen, using their loading codecs and RegistryOps

  • Datapack registries cannot be reloaded with /reload, they can only be reloaded by rebooting the server

  • Datapack registries automatically support tag jsons

  • Unsynced datapack registries' elements can directly reference any other datapack registries' elements

  • 数据包注册表的载入机制和可选的同步机制(这是不可变的,作为对照,可重载的数据提供了更底层的数据访问权限),具有更简单的标准实现。

  • 数据包注册表具有半内置的 datagen 支持,基于其载入编解码器和 RegistryOps

  • 数据包注册表不能被 /reload 命令重载,它们只能通过重启服务端来重载

  • 数据包注册表自动地支持标签 JSON

  • 非同步的数据包注册表的元素,可以直接引用任何其他的数据包注册表元素。

Lifecycle of datapack registries:

数据包注册表的生命周期:

  • The datapack registry and its codec(s) are registered (custom datapacks can be registered via the NewRegistryEvent or DeferredRegisters)

  • "Builtin" objects can optionally be registered in java (via DeferredRegister/RegistryObjects). This is required to datagen objects using RegistryOps.

  • When the server starts, using the registries' loading codecs, builtin objects are deep-copied and pasted into the server's personal RegistryAccess, and then json data from datapacks is loaded and pasted into the server's RegistryAccess (possibly overriding builtin objects).

  • When a client logs in, any synced datapack registries and their contents are sent to the client using the network codecs, and stored in the client's personal RegistryAccess (which is stored in the client's connection). Clients do not have to have any of the server's registrables pre-registered (and any builtin registrables are ignored on the client), but the synced registries themselves are required to have been registered on the client.

  • 数据包注册表和它的编解码器被注册(自定义数据包可以通过 NewRegistryEvent 或 DeferredRegisters 来注册)

  • “内置”的对象可以可选地通过 DeferredRegister/RegistryObjects 用 Java 代码来注册。如果用 RegistryOps 来 datagen 生成对象,则需要完成此步骤。

  • 服务端启动时,利用注册表的载入编解码器,内置的对象被深拷贝,并粘贴到服务端的个人 RegistryAccess 中,然后数据包中的 JSON 数据被载入并粘贴到服务端的 RegistryAccess,这有可能覆盖内置的对象。

  • 有客户端登录时,所有同步数据包注册表及其内容通过网络编解码器被发送给客户端,并存储在客户端的个人 RegistryAccess 中,这存储在客户端的连接中。客户端无需取得任何服务端预先注册的可注册项,且客户端忽略任何内置的可注册项,但同步数据包注册表本身则必须在客户端处注册。

Userdev APIs

开发者 API

When using a RegistryBuilder to register a registry (either via DeferredRegister or NewRegistryEvent), the userdev may invoke RegistryBuilder#dataPackRegistry(Codec<Tcodec, @Nullable Codec<TnetworkCodec), which marks the registry as a datapack registry and registers codecs for it. An overload that only takes the loading codec is also provided (using null for the network codec). If the network codec is non-null, the registry is considered to be a synced registry. Unsynced datapack registries registered on the server do not need to be registered on clients, but synced registries do. RegistryBuilder#disableSync is ignored as datapack registries use the presence of the network codec (or lack thereof) to determine whether to sync the registry.

使用 RegistryBuilder 来注册一个注册表时,无论通过 DeferredRegister 还是 NewRegistryEvent,开发者都有可能调用 RegistryBuilder#dataPackRegistry(Codec<Tcodec, @Nullable Codec<TnetworkCodec),这将该注册表标记为一个数据包注册表,并为其注册了编解码器。一个只需要载入编解码器的重载也一并提供,此时网络编解码器为 null。 若网络编解码器非空,该注册表即为同步注册表。注册于服务端的非同步数据包注册表,无需在客户端注册,但同步注册表则需要。RegistryBuilder#disableSync 被忽略,因为数据包注册表依据是否存在网络编解码器来确定是否同步此注册表。

Registries that are named modid:folder cause data to be loaded from data/<datapack_namespace>/modid/folder/. The folder path can include / for subdirectorying, e.g. worldgen/biome.

命名为 modid:folder 的注册表会从 data/<datapack_namespace>/modid/folder/ 载入数据。文件夹路径可以包含带有 / 的子目录,例如 worldgen/biome

Network API Changes

网络 API 的修改

  • Bump netversion from 2 to 3.

  • The S2CModList packet now may or may not contain a list of synced non-vanilla datapack registry IDs at the end of the packet bytestream.

  • Backwards-compatibility is kept for clients on netversion 2, see below. This backwards-compatibility may be dropped in 1.19 (sending an empty list instead of nothing).

  • 将 netversion 从 2 改为 3

  • S2CModList 网络包现在可能在该网络包的比特流末尾处,包含一张非原版的同步数据包注册表的 ID 列表,也有可能不包含。

  • 对 netversion 为 2 的客户端保持向后兼容,详见下文。该向后兼容性可能在 1.19 版本被舍弃,从原来的不做任何事,改为发送一张空列表。

End-User Concerns

考虑终端用户

If no changes are made to login netcode, then if a client were to attempt to connect to a server when the server has syncable datapack registries that don't exist on the client, the login packet fails to decode and the client is presented with an unreadable error message (due to the decoder dumping the entire contents of all synced datapack registries into the login error screen).

若登录的 netcode 未作修改,而又有客户端尝试连接服务端,且此时服务端有客户端处不存在、可以同步的数据包注册表,则登录网络包解码失败,客户端弹出一条不可读的报错信息。这是由于解码器将所有已同步的数据包注册表的全部内容都导出到登录失败的界面了。

To avoid this, we validate the syncability of custom datapack registries in these ways:

为避免此种情况,我们通过下述手段,验证自定义数据包注册表的可同步性:

Forge clients on netversion 2 will experience an "incompatible server" warning in the server list menu due to the netcode version mismatch, however they can still join the server if the server has no syncable custom datapack registries..

netversion 为 2 的 Forge 客户端将在服务器列表菜单中看到“incompatible server”警告,因为其 netcode 的版本不匹配。但它们仍然可以在服务端没有自定义数据包注册表的情况下,加入此服务器。

Summary of Patches

对所有补丁的总结

  • RegistryAccess has a hook patched into its codec registry so forge can add custom datapack registries' codecs later

  • RegistryResourceAccess has a patch to include the registry namespace in the directory (like tags) if namespace isn't "minecraft" and the registry was created via the RegistryBuilder API

  • 向 RegistryAccess 的编解码器注册表加入了一个钩子。从而,Forge 稍后可以添加自定义数据包注册表的编解码器。

  • 修改了 RegistryResourceAccess,若其命名空间不是 minecraft,则它会像标签一样,在路径中包含注册表的命名空间,同时该注册表会通过 RegistryBuilder API 创建。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment