原文:MinecraftForge/Documentation · 目标版本:Forge 1.20.1
组织你的模组¶
良好的模组结构有利于维护、贡献,也能让你更清晰地理解底层代码。以下列出了一些来自 Java、Minecraft 和 Forge 的推荐做法。
Note
你不必严格遵循以下建议,可以按自己认为合适的方式组织模组结构。不过仍然强烈建议你参考这些实践。
包结构¶
在组织模组时,请选择唯一的顶级包结构。许多程序员会为不同的类、接口等使用相同的名称。Java 允许类名相同,只要它们位于不同的包中即可。因此,如果两个类拥有相同的包名和类名,只有一个会被加载,这很可能导致游戏崩溃。
在模块加载方面,这个问题更加突出。如果不同模块中存在两个同名的包,模组加载器会在启动时直接崩溃,因为模组模块会导出到游戏和其他模组中。
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 |
下一级包则应为你的模组 ID(例如 com.example.examplemod,其中 examplemod 是模组 ID)。这样可以保证,除非你有两个相同 ID 的模组(这不应该发生),你的包不会有任何加载问题。
你可以在 Oracle 的教程页面上找到更多命名规范。
子包组织¶
除了顶级包之外,还强烈建议将模组的类拆分到不同的子包中。主要有两种组织方式:
- 按功能分组:为具有共同用途的类创建子包。例如,方块(Block)放在
block或blocks下,实体(Entity)放在entity或entities下,以此类推。Mojang 使用的就是这种结构,采用单词的单数形式。 - 按逻辑分组:为具有共同逻辑的类创建子包。例如,如果你正在创建一种新的工作台,你可以将它的方块、菜单(Menu)、物品等统一放在
feature.crafting_table下。
客户端、服务端与数据生成包¶
通常,仅用于特定逻辑端(Logical Sides)或运行时的代码应与其他类隔离,放在单独的子包中。例如,与数据生成(DataGen)相关的代码应放在 data 包中,而仅在专用服务器上运行的代码应放在 server 包中。
不过,强烈建议将仅客户端代码隔离到 client 子包中。这是因为专用服务器无法访问 Minecraft 中任何仅客户端可用的包。因此,设置一个专门的客户端包可以很好地帮助你验证模组中没有跨逻辑端调用的问题。
类命名规范¶
统一的类命名规范有助于更容易地理解类的用途,也便于快速定位特定的类。
通常,类名会以其类型作为后缀,例如:
- 一个名为
PowerRing的物品(Item)→PowerRingItem - 一个名为
NotDirt的方块(Block)→NotDirtBlock - 一个烤箱的菜单(Menu)→
OvenMenu
Note
Mojang 通常对除实体以外的所有类遵循类似的结构。实体类仅使用名称本身表示(如 Pig、Zombie 等)。
选择一种方式并保持一致¶
完成某项任务(如注册对象、监听事件等)往往有多种方式。通常建议保持一致,使用同一种方式来完成特定任务。这不仅能改善代码格式,还能避免可能出现的异常交互或冗余(例如你的事件监听器被执行两次)。