用户:MashKJo/1.12.2模组开发教程/2.基础概念:修订间差异

 
第60行: 第60行:
注册表是什么?那要先从“注册项”这个概念说起。
注册表是什么?那要先从“注册项”这个概念说起。


Minecraft原版中有着各种游戏元素,如物品、方块、状态效果、实体等等,这些游戏要素的很多行为(包括方块的“长按左键挖掘”这种通用行为,以及实体的“靠近玩家会尝试爆炸”这种仅在苦力怕这种生物上会体现的特殊行为),显然,是必须要在游戏初始化时完成设置的——不然游戏初始化有什么意义?干脆就在遇到某个游戏要素的时候读取相关逻辑不就好了?——显然,这种设计是很不好的。
Minecraft原版中有着各种游戏元素,如物品、方块、状态效果、实体等等,游戏需要以某种方式知道总共都有什么游戏元素,以方便管理。


所以在这种情况下,显然就需要一种东西来统筹这些游戏元素的逻辑的初始化,被统筹的游戏元素都是'''注册项''',而统筹者则是'''注册表'''。一般而言,注册项会在FMLPreInitialization阶段被注册。想想看:如果没有注册表,就拿物品(Item)这一注册项举例,MC如何能获取到你想要添加到游戏中的所有物品呢?难不成还要用黑科技读取你的项目中的所有继承了Item类的类,再用<code>Class#newInstance</code>手动构造实例?或者自动检索所有Item的实例?这根本不可行。所以注册表应运而生。
所以在这种情况下,注册表应运而生'。一般而言,注册项会在FMLPreInitialization阶段被注册。想想看:如果没有注册表,就拿物品(Item)这一注册项举例,MC如何能获取到你想要添加到游戏中的所有物品呢?难不成还要用黑科技读取你的项目中的所有继承了Item类的类,再用<code>Class#newInstance</code>手动构造实例?或者自动检索所有Item的实例?这根本不可行。所以注册表应运而生。


Minecraft原版就有一套注册表系统,不过它的实现太过于丑陋,也根本就存在很多问题——如,你会发现使用它注册注册项时,你还需要显式指定每个实例的数字ID。那么请问你如何保证你的模组的注册项的数字ID不会和其他模组的发生冲突呢?实际上Minecraft在1.13也弃用了这种注册模式。
Minecraft原版就有一套注册表系统,不过它的实现太过于丑陋,也根本就存在很多问题——如,你会发现使用它注册注册项时,你还需要显式指定每个实例的数字ID。那么请问你如何保证你的模组的注册项的数字ID不会和其他模组的发生冲突呢?实际上Minecraft在1.13也弃用了这种注册模式。
第70行: 第70行:
所有注册项的类都实现了IForgeRegistryEntry<V>这一接口,这个接口主要规定了关于注册名的一些规范,实际上这个接口有个静态内部类:Impl<T> implements IForgeRegistryEntry<T>,所以实际上所有注册项的类是继承了这个类,这个类提供了IForgeRegistryEntry<V>的默认实现。也就是说,理论上你可以通过T extends IForgeRegistryEntry.Impl<T>来设定:可以用Forge的注册表系统给你的某个自定义的游戏元素进行注册,不过一般没必要这么做。
所有注册项的类都实现了IForgeRegistryEntry<V>这一接口,这个接口主要规定了关于注册名的一些规范,实际上这个接口有个静态内部类:Impl<T> implements IForgeRegistryEntry<T>,所以实际上所有注册项的类是继承了这个类,这个类提供了IForgeRegistryEntry<V>的默认实现。也就是说,理论上你可以通过T extends IForgeRegistryEntry.Impl<T>来设定:可以用Forge的注册表系统给你的某个自定义的游戏元素进行注册,不过一般没必要这么做。


使用原版的注册表时,没有“注册名”这一说——但是我们用的是Forge的注册表,所以必须在注册对象前,设定该对象的注册名:通过setRegistryName这个方法设定。这个方法可以接受一个ResourceLocation,但也可以接受这样两种形参列表:<code>(String name)</code>和<code>(String modid, String name)</code>,用法可以类比ResourceLocation的那两个构造方法,笔者这里就不细说了。如果你尝试注册未设定注册名的注册项对象(即注册名为null),则肯定会崩游戏,抛NullPointerException。
使用原版的注册表时,没有“注册名”这一说——但是我们用的是Forge的注册表,所以必须在注册对象前,设定该对象的注册名:通过setRegistryName这个方法设定。这个方法可以接受一个ResourceLocation,但也可以接受这样两种形参列表:<code>(String name)</code>和<code>(String modid, String name)</code>,用法可以类比ResourceLocation的那两个构造方法,作者这里就不细说了。如果你尝试注册未设定注册名的注册项对象(即注册名为null),则肯定会崩游戏,抛NullPointerException。
=== @ObjectHolder ===
=== @ObjectHolder ===
利用<code>@GameRegistry.ObjectHolder</code>这个注解,我们可以自动给某个类型为<T extends IForgeRegistryEntry<T>>的变量赋值。
利用<code>@GameRegistry.ObjectHolder</code>这个注解,我们可以自动给某个类型为<T extends IForgeRegistryEntry<T>>的变量赋值。
行政员、​优秀编辑者、​界面管理员、​监督员、​管理员、​小部件编辑者
3,430

个编辑