Eclipse Core Client

Eclipse Core Client

Cobblmeon Eclipse服务器客户端增强模组

Eclipse Core Client

一个用于 Cobblemon 的客户端伴侣模组,支持高级多人对战格式,包括合作突袭战。

功能特性

  • 多人突袭支持 - 支持 1-4 名玩家合作对抗单个强大对手
  • 目标选择系统覆盖 - 允许在非标准对战格式中正确选择目标
  • 对战阵营整理 - 在对战界面中正确显示盟友和敌人
  • 双打/三打特殊机制修复 - 防止在单个回合内多次使用相同的对战特殊机制(Mega 进化、太晶化、Z 招式、极巨化)

环境要求

  • Minecraft 1.21.1
  • Fabric Loader 0.16.5+
  • Fabric API
  • Fabric Language Kotlin
  • Cobblemon 1.7.1+

安装方法

  1. 下载并将其放入客户端的 mods 文件夹
  2. 此模组仅限客户端 - 它通过自定义数据包与兼容的服务器模组进行通信

面向模组开发者

有兴趣为 Cobblemon 创建自己的突袭或多人对战模组吗?以下是你需要了解的信息:

核心挑战

Cobblemon 的对战系统是为 1v1 和 2v2 格式设计的。要创建突袭战(4v1、3v1 等),你需要解决几个问题:

  1. 对战创建 - 如何开始一场一方有 4 名玩家的对战?
  2. 目标选择 - 当相邻规则不允许时,玩家如何瞄准单个 Boss?
  3. 阵营显示 - 当客户端期望标准格式时,如何正确显示盟友?
  4. Showdown 兼容性 - 如何让 Showdown 接受非标准的队伍配置?

服务器端:开始多人对战

查看 Cobblemon 的 BattleBuilder 和 BattleRegistry。关键类:

  • BattleBuilder - 使用参与者和对战格式创建对战
  • BattleActor - 代表参与者(玩家或 NPC)
  • BattleFormat - 定义对战规则(单打、双打等)
  • PokemonBattle - 当前对战的实例

对于突袭战,你将需要在一侧放置多个 BattleActor 实例。研究 Cobblemon 如何处理双打 - 这是多人对战的基础。

Showdown 层

Cobblemon 使用 Pokemon Showdown 来处理对战逻辑。对战通过以下方式创建:

BattleRegistry.startBattle(format, side1Actors, side2Actors)

Showdown 以“pack strings”的形式接收队伍数据 - 这是 Pokemon 的紧凑表示形式。该格式在 Showdown 的源码中有文档记录。关键要点:Showdown 的 fPokemon 格式包括种族、等级、招式、特性等。

对于突袭 Boss,请考虑:

  • 如何给一只 Pokemon 更多有效生命值?
  • 如何让一只 Pokemon 承受多个攻击者的攻击?
  • 当 Showdown 计算对“缩放”目标造成的伤害时会发生什么?

客户端:目标选择问题

在标准双打中,Pokemon 只能瞄准相邻的槽位。在 4v1 突袭战中,所有玩家都需要瞄准单个 Boss。

客户端使用 ActiveClientBattlePokemon.getAdjacent() 来确定有效目标。此方法会检查位置并根据对战格式返回有效目标。

Eclipse Core Client 通过以下方式解决此问题:

  • 拦截目标请求
  • 覆盖突袭格式的相邻性计算
  • 通过自定义数据包通信突袭配置

数据包通信

Fabric 网络允许在服务器和客户端之间发送自定义数据包:

// 服务器端:注册并发送
PayloadTypeRegistry.playS2C().register(...)
ServerPlayNetworking.send(player, payload)

// 客户端:注册接收器 ClientPlayNetworking.registerGlobalReceiver(...)

你的数据包应告知客户端:

  • 这是突袭战吗?
  • 有多少玩家参与?
  • Boss 在哪一方?

客户端需要在对战界面渲染之前获取此信息,以便正确组织阵营。

Showdown 修改(高级)

Cobblemon 将 Showdown 解压到 ./showdown/。位于 sim/ 目录中的 JavaScript 文件控制对战机制:

  • battle.js - 主对战循环和回合处理
  • pokemon.js - Pokemon 状态、HP、PP 管理
  • side.js - 阵营管理和槽位处理
  • battle-actions.js - 招式执行和伤害计算

对于突袭机制,你可能需要修改以下内容:

  • 对 Boss 的伤害计算方式
  • PP 的追踪方式(Boss 拥有无限 PP?)
  • 多目标招式的结算方式
  • Boss 针对多个目标执行行动的方式

使用 Mixin 混入 GraalShowdownUnbundler.attemptUnbundle() 可以在解压后修补文件。

Mixin 目标参考

客户端(用于目标选择和显示修复):

  • ActiveClientBattlePokemon - 目标选择和相邻性
  • BattleMoveSelection - 招式选择界面
  • ClientBattle - 阵营组织

服务器端(用于对战创建):

  • BattleBuilder - 对战初始化
  • BattleActor - 参与者行为
  • NPCBattleActor - NPC 特定逻辑

开始开发

  1. 创建一个基本的服务器模组,能够开始一场双打对战
  2. 在一方添加第三个玩家 - 观察会出现什么问题
  3. 研究错误以理解限制条件
  4. 逐层实现修复(Showdown → 服务器 → 客户端)

从“双打可用”到“4v1 突袭可用”的旅程将让你全面了解 Cobblemon 的对战系统。


Eclipse 数据包协议

希望你的服务器模组与 Eclipse Core Client 兼容?请实现以下数据包:

数据包 1:客户端握手(客户端 → 服务器)

频道: eclipse_raids:client_handshake

当安装 Eclipse Core Client 的玩家加入你的服务器时,他们会发送此数据包。

字段 类型 描述
protocolVersion Int 客户端协议版本(当前为 2)

Kotlin 编解码器:

buf.writeInt(protocolVersion)
// 读取:buf.readInt()

使用此信息来追踪哪些玩家已安装客户端模组。阻止未安装模组的玩家参与突袭。

数据包 2:握手确认(服务器 → 客户端)

频道: eclipse_raids:handshake_ack

发送此数据包以确认客户端已被识别。

字段 类型 描述
raidsEnabled Boolean 此服务器是否启用了突袭功能
message String 状态消息(显示在客户端日志中)

Kotlin 编解码器:

buf.writeBoolean(raidsEnabled)
buf.writeString(message)

数据包 3:突袭阵营配置(服务器 → 客户端)

频道: eclipse_raids:raid_side_config

这是关键数据包。在开始突袭后发送此数据包,告知客户端哪些参与者是盟友,哪些是敌人。

字段 类型 描述
battleId UUID 来自 PokemonBattle.battleId 的对战 UUID
allyShowdownIds List<String> 玩家方的 Showdown ID(例如 ["p1", "p3", "p5", "p7"])
enemyShowdownIds List<String> Boss 方的 Showdown ID(例如 ["p2"])

Kotlin 编解码器:

// 写入
buf.writeUuid(battleId)
buf.writeInt(allyShowdownIds.size)
allyShowdownIds.forEach { buf.writeString(it) }
buf.writeInt(enemyShowdownIds.size)
enemyShowdownIds.forEach { buf.writeString(it) }

// 读取 val battleId = buf.readUuid() val allyCount = buf.readInt() val allyIds = (0 until allyCount).map { buf.readString() } val enemyCount = buf.readInt() val enemyIds = (0 until enemyCount).map { buf.readString() }

Showdown ID 命名规则

Showdown 根据对战位置分配 ID:

  • p1, p3, p5, p7 - 一方使用奇数(用于玩家)
  • p2, p4, p6, p8 - 另一方使用偶数(用于 Boss)

在 4v1 突袭中:

  • 玩家 1 → p1
  • 玩家 2 → p3
  • 玩家 3 → p5
  • 玩家 4 → p7
  • Boss → p2

何时发送 RaidSideConfig

时机至关重要。请在以下时机发送数据包:

  1. 在 BattleRegistry.startBattle() 返回之后
  2. 在玩家打开对战界面之前(他们有大约 1-2 秒的时间)

建议:立即发送,然后在 3 秒(60 tick)后再次发送作为安全措施,以防客户端当时未准备好。

// 对战开始后立即发送
for (player in players) {
    ServerPlayNetworking.send(player, RaidSideConfigPayload(battle.battleId, allyIds, enemyIds))
}

// 安全措施 - 3 秒后重新发送 Scheduler.schedule(60) { for (player in players) { ServerPlayNetworking.send(player, RaidSideConfigPayload(battle.battleId, allyIds, enemyIds)) } }

客户端的处理方式

当 Eclipse Core Client 接收到 RaidSideConfigPayload 时:

  1. 找到与 battleId 匹配的活动 ClientBattle
  2. 从双方收集所有 ClientBattleActor
  3. 重新组织它们:盟友 → side1,敌人 → side2
  4. 设置 isInRaidBattle = true(启用目标选择覆盖)

这样修复了:

  • Pokemon 出现在错误的视觉侧
  • 玩家无法瞄准 Boss(相邻性覆盖生效)

Payload 类(Fabric 1.21.1)

// 在你的模组初始化器中注册
PayloadTypeRegistry.playC2S().register(ClientHandshakePayload.ID, ClientHandshakePayload.CODEC)
PayloadTypeRegistry.playS2C().register(HandshakeAckPayload.ID, HandshakeAckPayload.CODEC)
PayloadTypeRegistry.playS2C().register(RaidSideConfigPayload.ID, RaidSideConfigPayload.CODEC)

// 处理传入的握手 ServerPlayNetworking.registerGlobalReceiver(ClientHandshakePayload.ID) { payload, context -> val player = context.player() // 追踪该玩家已安装客户端模组 // 发送确认数据包 }

没有此客户端模组时

如果玩家没有安装 Eclipse Core Client:

  • 普通的 1v1 和 2v2 对战可以正常工作
  • 突袭对战会出现目标选择问题(玩家无法选择 Boss)
  • Pokemon 可能在视觉上出现在错误的阵营

通过检查你的握手追踪记录,阻止未安装客户端模组的玩家参与突袭。

兼容性

此模组旨在与实现 Eclipse 数据包协议的服务器端突袭模组配合使用。如果没有兼容的服务器模组,它会在双打/三打对战中充当被动的特殊机制修复工具。

支持

此模组按现状提供,用于与兼容的 Eclipse 服务器模组配合使用。