3,417
个编辑
MCBBS Wiki欢迎您共同参与编辑!在参与编辑之前请先阅读Wiki方针。
如果在编辑的过程中遇到了什么问题,可以去讨论板提问。
为了您能够无阻碍地参与编辑 未验证/绑定过邮箱的用户,请尽快绑定/验证。
MCBBS Wiki GitHub群组已上线!
您可以在回声洞中发表吐槽!
服务器状态监控。点击进入
本站由MCBBS用户自行搭建,与MCBBS及东银河系漫游指南(北京)科技有限公司没有从属关系。点此了解 MCBBS Wiki 不是什么>>
无编辑摘要 |
无编辑摘要 |
||
| 第54行: | 第54行: | ||
Holder的意义在于更好地对注册对象进行管理,如:判断其是否属于某个标签(Tag)。 | Holder的意义在于更好地对注册对象进行管理,如:判断其是否属于某个标签(Tag)。 | ||
== 延迟注册(DeferredRegister) == | |||
上述介绍的都是属于原版的注册机制。对于可写注册表,我们用数据包的.json格式添加新元素即可,这个作者就不多说了。 | |||
那么固有注册表呢?NeoForge提供了2种方案:监听注册事件(RegisterEvent),与延迟注册(DeferredRegister)机制。推荐使用后者(如果你没有动态注册的需求的话),实际上延迟注册机制就是基于注册事件设计的,它能帮你避免很多因类加载顺序产生的错误,详见TeaCon的一篇文章:[https://blog.teacon.cn/static_init.html 为什么你不该在静态初始化块里创建游戏对象 - TeaCon Blog]。 | |||
具体地说,使用DeferredRegister注册注册项的流程是这样的: | |||
public class RegistryHandler { | |||
//这里T即为你的注册项类型,可以为Item、Block等等。 | |||
//DeferredRegister字段的命名一般习惯上是这样的:把注册项类型名称全大写,再加S,如DeferredRegister<Item>一般会被命名为ITEMS。 | |||
//create方法的第一个参数可以是ResourceKey<Registry<T>>、ResourceLocation或Registry<T>。 | |||
public static final DeferredRegister<T> DEFERRED_REGISTER_T = DeferredRegister.create(BuiltInRegistries.xxx, TutorialMod.MODID); | |||
//第一个参数为该注册对象的注册名,第二个参数可以是一个Function<ResourceLocation, ? extends S>,也可以是一个Supplier<? extends S>。 | |||
//一般而言填一个Supplier更为常见。 | |||
//这个lambda就是DeferredRegister的精髓所在了:实现游戏对象的惰性初始化,或许这个字段被加载得较早,但是lambda里的方法要到RegisterEvent被发布才被调用,这个DeferredHolder才真正可用。 | |||
public static final DeferredHolder<T, S extends T> MY_REGISTRY_OBJECT = DEFERRED_REGISTER_T.register("example_name", () -> ...); | |||
... | |||
//将我们的DeferredRegister注册进MOD总线,一般是在Mod主类构造器中调用它。 | |||
public static void register(IEventBus bus) { | |||
DEFERRED_REGISTER_T.register(bus); | |||
} | |||
} | |||
DeferredHolder是一种特殊的Holder,它用于弥补Holder的不足——Holder的泛型参数只能是该种注册项的上限类,如对于物品的Holder,泛型参数只能是Item而不能是PickaxeItem这种子类。我们看看DeferredHolder的类定义就知道:<code>public class DeferredHolder<R, T extends R> implements Holder<R>, Supplier<T></code>。因此一个DeferredHolder同时也是一个Supplier。 | |||
上述介绍的是注册注册对象的一般步骤,但实际上NeoForge考虑到物品(Item)、方块(Block)和物品堆叠组件类型(DataComponentType<?>)的注册非常常见,因此提供了DeferredRegister的三个子类:DeferredRegister.Items、DeferredRegister.Blocks和DeferredRegister.DataComponents,以及DeferredHolder的两个子类:DeferredItem和DeferredBlock。并以此为基础提供了很多便捷的方法。 | |||
但是注意,这些DeferredRegister子类的某些注册方法会把构建新对象时的某一部分移到lambda外边(以此来满足使用方法引用的条件),因此如果你的注册对象依赖于非原版的某些注册对象,这么做就炸了,这时候还是老老实实地用DeferredRegister#register为好,把初始化包进lambda。 | |||