Skip to content

架构总览

Emaki Series 的架构可以按一句话理解:CoreLib 提供通用能力,业务模块只写自己的玩法规则。模块之间通过静态 API 门面、可选模块桥接、PDC 数据和 namespace layer 协作,避免直接改彼此内部状态。

总体分层

mermaid
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 等)EmakiItemApiemaki.jiuwu.craft.item.api.preview已删除,CoreLib 不再提供该扩展点
装备技能 PDC key 与编解码EmakiSkillsProtocolEquipmentSkillPdcCodecSkillPdcGateway 仅为 @Deprecated(forRemoval = true) 委托适配器
属性 PDC 与属性服务契约EmakiAttributeApiemaki.jiuwu.craft.attribute.api.PdcAttributeApi 与完整 PdcAttributePayloadPdcAttributeGateway 与 CoreLib 镜像 PdcAttributeApi 均已 @Deprecated(forRemoval = true),且镜像是有损的

CoreLib 侧的上述适配器仅为一个同步发行窗口保留,新代码不应再依赖它们。

业务模块如何协作

通过硬依赖和软依赖

  • 所有业务模块硬依赖 EmakiCoreLibpaper-plugin.yml 中声明为 required: trueload: 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 导致顺序混乱。

典型装备数据流

mermaid
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、展示和状态

典型等级数据流

mermaid
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,不需要直接修改玩家数据文件。

典型技能数据流

mermaid
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 与装备线不同,它更关注世界状态:

  1. 玩家与工位方块交互。
  2. Cooking 识别工位类型,例如砧板、炒锅、研磨机、蒸锅。
  3. 读取玩家手持物、工位内部状态和配方条件。
  4. 更新工位状态,例如加入材料、翻炒、加水、加燃料。
  5. 满足配方后发放产物或执行动作。
  6. 将工位状态按世界坐标保存,重启后恢复。

典型图鉴数据流

Codex 把玩法目标映射为原版 Advancement:

  1. advancements/*.yml 定义成就页、根节点和子节点,节点 key 形如 emakicodex:<page>/<node>
  2. Codex 将节点注册为原版 Advancement。
  3. 节点通过命令、CoreLib 动作、公开 API 或 triggers.entries 中的 CoreLib 共享 gameplay 事件(击杀、合成、熔炉取出、钓鱼、酿造、驯服、破坏方块等)被授予。
  4. 节点首次完成时执行 actions.complete 中的 CoreLib 动作。
  5. 安装 PacketEvents 时,可额外向客户端注入成就树坐标。