组织 Mod 的结构
合理组织 Mod 有利于维护和接受贡献,也能让人更清楚地理解底层代码。以下列出 Java、Minecraft 和 Forge 的一些建议。
原创说明图,依据 Forge 1.21.x 官方文档 绘制。
这些建议并非强制要求,你可以按自己的方式组织 Mod,但文档仍强烈建议遵循它们。
包结构
选择唯一的顶层包结构。不同程序员可能给类或接口使用相同名称;Java 允许不同包中的类同名,但如果两个类的包名和类名完全相同,通常只会加载其中一个,很可能导致游戏崩溃。
a.jar
- com.example.ExampleClass
b.jar
- com.example.ExampleClass // 此类通常不会被加载
模块加载时这一点更加重要:不同模块中出现同名包会导致 Mod 加载器启动时崩溃,因为 Mod 模块会导出给游戏和其他 Mod。
module A
- package X
- class I
- class J
module B
- package X // 已有模块导出 package 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。只要不存在两个相同 ID 的 Mod,包加载就不应发生冲突。更多命名约定可参考 Oracle 教程。
子包组织
建议将类拆分到子包中,主要有两种方法:
- 按功能分组:将用途相同的类放在一起,例如方块放在
block或blocks,实体放在entity或entities。Mojang 使用单数形式。 - 按逻辑分组:将同一逻辑的类放在一起。例如,新工作台的方块、菜单、物品等可放在
feature.crafting_table中。
客户端、服务端与数据生成代码包
通常应将只用于特定端或运行环境的代码放在单独的子包中。例如,数据生成代码放在 data 包,仅用于独立服务器的代码放在 server 包。
强烈建议将仅客户端代码放在 client 子包。独立服务器无法访问 Minecraft 的仅客户端包;单独的包有助于检查 Mod 是否错误地跨端引用。
类命名方式
统一的命名方式有助于理解类的用途并定位类。类名通常以其类型作为后缀:
- 名为
PowerRing的Item:PowerRingItem。 - 名为
NotDirt的Block:NotDirtBlock。 Oven的菜单:OvenMenu。
Mojang 通常也采用类似结构,但实体类除外:实体通常直接使用名称,例如 Pig、Zombie。
从多种方式中选择一种
注册对象、监听事件等任务通常有多种实现方式。建议对同一任务始终使用一种方式,保持一致。这不仅能改善代码格式,也能避免意外的交互或重复操作,例如事件监听器执行两次。