架构总览
Emaki Series 的架构可以按一句话理解:CoreLib 提供通用能力,业务模块只写自己的玩法规则。模块之间通过静态 API 门面、可选模块桥接、PDC 数据和 namespace layer 协作,避免直接改彼此内部状态。
总体分层
graph TB
Server[Paper / Bukkit 1.21.8+]
Core[EmakiCoreLib]
Attribute[EmakiAttribute]
Item[EmakiItem]
Forge[EmakiForge]
Strengthen[EmakiStrengthen]
Gem[EmakiGem]
Level[EmakiLevel]
Skills[EmakiSkills]
Cooking[EmakiCooking]
Codex[EmakiCodex]
Storage[EmakiStorage]
Protocol[EmakiSkillsProtocol<br/>编译期嵌入,非插件]
Mythic[MythicMobs]
PAPI[PlaceholderAPI]
Economy[Vault / ExcellentEconomy]
Craft[CraftEngine / ItemsAdder / Nexo]
Core --> Server
Attribute --> Core
Item --> Core
Forge --> Core
Strengthen --> Core
Gem --> Core
Level --> Core
Skills --> Core
Cooking --> Core
Codex --> Core
Storage --> Core
Protocol -.装备技能 PDC 契约.-> Core
Protocol -.装备技能 PDC 契约.-> Item
Protocol -.装备技能 PDC 契约.-> Skills
Forge -.属性写入.-> Attribute
Strengthen -.属性写入.-> Attribute
Gem -.属性写入.-> Attribute
Item -.属性/技能.-> Attribute
Skills -.资源/属性检查.-> Attribute
Level -.等级属性贡献.-> Attribute
Level -.Mythic经验来源.-> Mythic
Skills -.技能效果.-> Mythic
Core -.占位符.-> PAPI
Core -.经济.-> Economy
Cooking -.方块/物品来源.-> Craft
Codex -.gameplay 事件.-> Core图中
EmakiSkillsProtocol是纯编译期协议构件,不是服务器插件,不要放进plugins/。它被 CoreLib、Item、Skills、Forge、Gem、Strengthen 在构建时嵌入并 relocate。
CoreLib 的职责
CoreLib 是共享基础设施层。它不承载某个玩法的核心规则,也不再持有领域协议,只提供所有模块都会用到的能力:
- 调度与线程所有权:统一的执行调度入口与线程归属约束,并适配 Paper 与 Folia 两种平台后端。
- 异步文件服务:异步任务调度、文件读写与并发数据存储。
- YAML 配置:配置加载、预检与安全迁移底座。
- 通用 PDC 工具:在物品、实体或玩家上保存结构化数据的底层读写能力。
- GUI 系统:统一菜单模板、槽位按钮、点击处理和会话状态。
- 动作系统:发送消息、执行命令、播放声音、发放物品、扣费、延迟、概率、条件控制。
- 脚本引擎:基于 GraalVM 的 JavaScript 执行能力与限制策略。
- 表达式与条件:在 YAML 中编写数值公式、条件判断和概率规则。
- 物品来源系统:识别 Vanilla、MMOItems、ItemsAdder、Nexo、Oraxen、EcoItems、CraftEngine、NeigeItems 等来源的物品。
- 经济桥接:统一调用 Vault、ExcellentEconomy 等经济系统。
- 权重与随机:加权随机选择等通用数学工具。
- 共享注册表:动作、命名空间、层编解码、GUI 后端等注册中心。
- 结构化物品装配与展示协调:把多个模块写入的物品层合并成最终名称、Lore 和属性展示。
- 运行库准备:运行期依赖库的加载与准备。
不再由 CoreLib 持有的契约
领域协议与扩展点已迁回各业务模块,改写配置或做二次开发时应以新归属为准:
| 契约 | 当前唯一权威 | CoreLib 现状 |
|---|---|---|
物品层预览 SPI(ItemLayerPreviewProvider / ItemLayerPreviewRequest 等) | EmakiItemApi 的 emaki.jiuwu.craft.item.api.preview | 已删除,CoreLib 不再提供该扩展点 |
| 装备技能 PDC key 与编解码 | EmakiSkillsProtocol 的 EquipmentSkillPdcCodec | SkillPdcGateway 仅为 @Deprecated(forRemoval = true) 委托适配器 |
| 属性 PDC 与属性服务契约 | EmakiAttributeApi 的 emaki.jiuwu.craft.attribute.api.PdcAttributeApi 与完整 PdcAttributePayload | PdcAttributeGateway 与 CoreLib 镜像 PdcAttributeApi 均已 @Deprecated(forRemoval = true),且镜像是有损的 |
CoreLib 侧的上述适配器仅为一个同步发行窗口保留,新代码不应再依赖它们。
业务模块如何协作
通过硬依赖和软依赖
- 所有业务模块硬依赖
EmakiCoreLib(paper-plugin.yml中声明为required: true、load: BEFORE)。 - Attribute、Forge、Strengthen、Gem、Level、Skills、Item、Codex 之间大多使用软依赖、静态 API 门面或内部桥接。
- 软依赖不存在时,插件主体可以加载,但对应桥接功能不可用。
通过静态 API 门面和桥接
Level、Gem、Skills、Item 等公开 API 采用静态门面加 bridge 的方式:业务插件启用时安装 bridge,停用时卸载 bridge;外部插件先调用 available() 或对应 Provider 辅助类判断可用性,再使用 API。Attribute 当前公开的开发者入口是 EmakiAttributeApi 中的 emaki.jiuwu.craft.attribute.api.PdcAttributeApi(配合 PdcAttributeApiProvider),玩家资源和战斗状态更多通过模块内部桥接与事件协作。
这种方式的优点:
- 可选模块未安装时,其他模块可以降级运行。
- API 门面比内部实现更稳定。
- 减少外部插件直接依赖实现类的风险。
通过 PDC 和 namespace layer
装备成长系统最重要的规则是分层写入。每个模块只写自己的 layer:
- Item 写入基础物品 ID、套装、基础属性。
- Forge 写入锻造结果、品质或材料贡献。
- Strengthen 写入强化星级、阶段和加成。
- Gem 写入插槽、宝石和升级状态。
这些状态不能只拼进最终 Lore。它们应以结构化数据保存,由 CoreLib 读取各 layer 后统一重建名称、Lore、属性 payload 和展示状态。
这样可以避免:
- 强化刷新时把宝石 Lore 覆盖掉。
- 锻造修改名称时丢失自定义物品 ID。
- 宝石提取后属性残留。
- 多插件都在操作同一段 Lore 导致顺序混乱。
典型装备数据流
sequenceDiagram
participant Player as 玩家
participant Item as EmakiItem
participant Forge as EmakiForge
participant Str as EmakiStrengthen
participant Gem as EmakiGem
participant Core as CoreLib Assembly
participant Attr as EmakiAttribute
Player->>Item: 获取自定义装备
Item->>Core: 写入基础 layer
Player->>Forge: 使用图纸和材料锻造
Forge->>Core: 写入 forge layer
Forge->>Attr: 可选写入属性 payload
Player->>Str: 强化装备
Str->>Core: 写入 strengthen layer
Str->>Attr: 可选写入强化属性
Player->>Gem: 开孔/镶嵌/升级
Gem->>Core: 写入 gem layer
Gem->>Attr: 可选写入宝石属性
Core-->>Player: 重建名称、Lore、展示和状态典型等级数据流
sequenceDiagram
participant Player as 玩家
participant Level as EmakiLevel
participant Source as 经验来源
participant Attr as EmakiAttribute
participant PAPI as PlaceholderAPI
Player->>Source: 击杀、采集、合成、钓鱼或 Mythic Drop
Source->>Level: 写入指定等级类型经验
Level->>Level: 计算需求、自动升级、奖励和动作
Level->>Attr: 可选刷新等级属性贡献
Level->>PAPI: 提供等级、经验、进度和排行榜占位符Level 负责“玩家为什么获得经验、经验进入哪条成长线、是否升级、升级后执行什么奖励”。其他插件可以通过 CoreLib Action 或 Level API 把经验写入 Level,不需要直接修改玩家数据文件。
典型技能数据流
sequenceDiagram
participant Player as 玩家
participant Skills as EmakiSkills
participant Attr as EmakiAttribute Bridge
participant Mythic as MythicMobs
Player->>Skills: 触发主动/被动技能
Skills->>Skills: 检查冷却、条件、槽位、等级
Skills->>Attr: 检查或消耗资源/属性
Attr-->>Skills: 返回检查结果
Skills->>Mythic: 调用 Mythic 技能
Mythic-->>Player: 执行实际技能效果Skills 负责“能不能放、什么时候放、谁触发、消耗什么”,MythicMobs 负责“技能实际产生什么效果”。这种分工能让服主继续使用熟悉的 MythicMobs 技能配置,同时把 RPG 技能管理交给 EmakiSkills。
典型烹饪数据流
Cooking 与装备线不同,它更关注世界状态:
- 玩家与工位方块交互。
- Cooking 识别工位类型,例如砧板、炒锅、研磨机、蒸锅。
- 读取玩家手持物、工位内部状态和配方条件。
- 更新工位状态,例如加入材料、翻炒、加水、加燃料。
- 满足配方后发放产物或执行动作。
- 将工位状态按世界坐标保存,重启后恢复。
典型图鉴数据流
Codex 把玩法目标映射为原版 Advancement:
advancements/*.yml定义成就页、根节点和子节点,节点 key 形如emakicodex:<page>/<node>。- Codex 将节点注册为原版 Advancement。
- 节点通过命令、CoreLib 动作、公开 API 或
triggers.entries中的 CoreLib 共享 gameplay 事件(击杀、合成、熔炉取出、钓鱼、酿造、驯服、破坏方块等)被授予。 - 节点首次完成时执行
actions.complete中的 CoreLib 动作。 - 安装 PacketEvents 时,可额外向客户端注入成就树坐标。