规划你的模组结构
结构分明的模组有利于维护和做出贡献,并提供对底层代码库的更清晰理解。下面列举了由Java、Minecraft和Forge提出的一些建议。
!!! 注意 你不必遵循以下建议;你可以以任何你认为合适的方式规划你的模组。然而,我们仍强烈建议这样做。
程序包
在规划你的模组时,选择一个独特的、顶级的程序包结构。许多程序员会对不同的类、接口等使用相同的名称。Java允许类具有相同的名称,只要它们位于不同的包中。因此,如果两个类具有相同的名称和相同的包,则只有一个会被加载,这很可能导致游戏崩溃。
a.jar
- com.example.ExampleClass
b.jar
- com.example.ExampleClass // 这个类不会被正常加载
当涉及到加载模块时,这一点更为重要。如果在不同的模块中有两个同名包下的类文件,这将导致模组加载器在启动时崩溃,因为模组模块会被导出到游戏和其他模组中。
module A
- package X
- class I
- class J
module B
- package X // 此包将导致模组加载器崩溃,因为已经有一个模块将包X导出
- class R
- class S
- class T
正因如此,你的顶级程序包应该是你自己的东西:域名、电子邮件地址、网站的子域等。它甚至可以是你的名字或用户名,只要你能保证它在预期目标中是唯一可识别的。
类型 | 值 | 顶级程序包 |
---|---|---|
域名 | example.com | com.example |
子域名 | example.github.io | io.github.example |
电子邮箱地址 | example@gmail.com | com.gmail.example |
下一个级别的包应该是你的mod id(例如com.example.examplemod
,其中examplemod
是mod id)。这将保证,除非你有两个id相同的模组(这种情况永远不会发生),否则你的包在加载时不会出现任何问题。
你可以在Oracle的教程页面上找到一些其他命名约定。
子包的组织
除了顶级包以外,强烈建议将你的模组的类拆分为不同的子包。关于如何做到这一点,主要有两种方法:
- 按功能分组: 将具有共同目的的类归入同一个子包。例如,方块相关的类可被置于
block
或blocks
子包下,实体相关的类可被置于entity
或entities
子包下等等。Mojang就在使用这种结构,单词用的是单数形式(block
、entity
)。 - 按逻辑分组: 将具有共同逻辑的类归入同一个子包。例如,如果你正在创建一种新配方,你可以将它的方块、菜单、物品等等都放在
feature.crafting_table
子包下。
客户端、服务端和数据相关的子包
通常,仅用于给定端位或运行时的代码都应该在单独的子包中与其他类隔离。例如,与数据生成相关的代码应该放在data
子包中,而仅与dedicated服务器相关的代码应该在server
子包中。
然而,强烈建议在client
子包中隔离仅限客户端的代码。这是因为dedicated服务器不应有任何权限访问Minecraft中仅限客户端的包。因此,拥有一个专用的包将提供一个不错的健全性检查,以保证你的模组中的代码没有越过端位的行为。
类的命名规则
一个普适的类命名方案可以让你更容易地读懂类的目的或查找某个特定的类。
类的名称通常以其类型作为后缀,例如:
- 一个叫作
PowerRing
的Item
->PowerRingItem
。 - 一个叫作
NotDirt
的Block
->NotDirtBlock
。 - 为
Oven
设计的一个菜单 ->OvenMenu
。
!!! 注意
Mojang通常对除实体以外的所有类命名时都遵循类似的结构。而实体只用它们的名字来表示(例如Pig
、Zombie
等)。
选择仅用一个方法而非多个
执行特定任务的方法有很多:注册对象、监听事件等。通常建议使用单一方法来完成给定的任务以保持一致。这在改善了代码格式的同时,也避免了可能发生的任何奇怪的交互或冗余(例如,你的事件监听器执行了两次)。