This project's core functionality is to enable double battle gimmicks in cobblemon clients, it servers other purposes as well to enable 4v1 raids on servers that create their own mods. Additional functionality will eventually be added.
A client-side companion mod for Cobblemon that enables advanced multi-player battle formats, including cooperative raid battles.
mods folderInterested in creating your own raid or multi-battle mod for Cobblemon? Here's what you need to know:
Cobblemon's battle system is designed for 1v1 and 2v2 formats. To create raids (4v1, 3v1, etc.), you need to solve several problems:
Look at Cobblemon's BattleBuilder and BattleRegistry. Key classes:
BattleBuilder - Creates battles with actors and formatBattleActor - Represents a participant (player or NPC)BattleFormat - Defines the battle rules (singles, doubles, etc.)PokemonBattle - The active battle instanceFor raids, you'll need multiple BattleActor instances on one side. Study how Cobblemon handles doubles - it's the foundation for multi-player.
Cobblemon uses Pokemon Showdown for battle logic. Battles are created via:
BattleRegistry.startBattle(format, side1Actors, side2Actors)
Showdown receives team data as "pack strings" - compact representations of Pokemon. The format is documented in Showdown's source. Key insight: Showdown's fPokemon format includes species, level, moves, ability, etc.
For raid bosses, consider:
In standard doubles, Pokemon can only target adjacent slots. In a 4v1 raid, ALL players need to target the single boss.
The client uses ActiveClientBattlePokemon.getAdjacent() to determine valid targets. This method checks positions and returns valid targets based on battle format.
Eclipse Core Client solves this by:
Fabric networking allows custom packets between server and client:
// Server-side: Register and send
PayloadTypeRegistry.playS2C().register(...)
ServerPlayNetworking.send(player, payload)
// Client-side: Register receiver
ClientPlayNetworking.registerGlobalReceiver(...)
Your packet should tell the client:
The client needs this info BEFORE the battle UI renders to correctly organize sides.
Cobblemon extracts Showdown to ./showdown/. The JavaScript files in sim/ control battle mechanics:
battle.js - Main battle loop and turn handlingpokemon.js - Pokemon state, HP, PP managementside.js - Side management and slot handlingbattle-actions.js - Move execution and damageFor raid mechanics, you might need to modify how:
Mixin into GraalShowdownUnbundler.attemptUnbundle() to patch files after extraction.
Client-side (for targeting/display fixes):
ActiveClientBattlePokemon - Target selection and adjacencyBattleMoveSelection - Move selection UIClientBattle - Side organizationServer-side (for battle creation):
BattleBuilder - Battle initializationBattleActor - Actor behaviorNPCBattleActor - NPC-specific logicThe journey from "doubles work" to "4v1 raids work" will teach you everything about Cobblemon's battle system.
Want your server mod to work with Eclipse Core Client? Implement these packets:
Channel: eclipse_raids:client_handshake
When a player with Eclipse Core Client joins your server, they send this packet.
| Field | Type | Description |
|---|---|---|
| protocolVersion | Int | Client protocol version (currently 2) |
Kotlin Codec:
buf.writeInt(protocolVersion)
// Read: buf.readInt()
Use this to track which players have the client mod installed. Block raid participation for players without it.
Channel: eclipse_raids:handshake_ack
Send this back to confirm the client is recognized.
| Field | Type | Description |
|---|---|---|
| raidsEnabled | Boolean | Whether raids are enabled on this server |
| message | String | Status message (shown in client logs) |
Kotlin Codec:
buf.writeBoolean(raidsEnabled)
buf.writeString(message)
Channel: eclipse_raids:raid_side_config
This is the critical packet. Send this after starting a raid battle to tell the client which actors are allies vs enemies.
| Field | Type | Description |
|---|---|---|
| battleId | UUID | The battle's UUID from PokemonBattle.battleId |
| allyShowdownIds | List<String> | Showdown IDs for player side (e.g., ["p1", "p3", "p5", "p7"]) |
| enemyShowdownIds | List<String> | Showdown IDs for boss side (e.g., ["p2"]) |
Kotlin Codec:
// Write
buf.writeUuid(battleId)
buf.writeInt(allyShowdownIds.size)
allyShowdownIds.forEach { buf.writeString(it) }
buf.writeInt(enemyShowdownIds.size)
enemyShowdownIds.forEach { buf.writeString(it) }
// Read
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 assigns IDs based on battle position:
In a 4v1 raid:
Timing is critical. Send the packet:
BattleRegistry.startBattle() returnsRecommended: Send immediately, then send again after 3 seconds (60 ticks) as a safety net in case the client wasn't ready.
// Immediately after battle starts
for (player in players) {
ServerPlayNetworking.send(player, RaidSideConfigPayload(battle.battleId, allyIds, enemyIds))
}
// Safety net - resend after 3 seconds
Scheduler.schedule(60) {
for (player in players) {
ServerPlayNetworking.send(player, RaidSideConfigPayload(battle.battleId, allyIds, enemyIds))
}
}
When Eclipse Core Client receives RaidSideConfigPayload:
ClientBattle matching battleIdClientBattleActor from both sidesside1, enemies → side2isInRaidBattle = true (enables targeting override)This fixes:
// Register in your mod initializer
PayloadTypeRegistry.playC2S().register(ClientHandshakePayload.ID, ClientHandshakePayload.CODEC)
PayloadTypeRegistry.playS2C().register(HandshakeAckPayload.ID, HandshakeAckPayload.CODEC)
PayloadTypeRegistry.playS2C().register(RaidSideConfigPayload.ID, RaidSideConfigPayload.CODEC)
// Handle incoming handshakes
ServerPlayNetworking.registerGlobalReceiver(ClientHandshakePayload.ID) { payload, context ->
val player = context.player()
// Track that this player has the client mod
// Send acknowledgment back
}
If a player doesn't have Eclipse Core Client:
Block raid participation for players without the client mod by checking your handshake tracking.
This mod is designed to work with server-side raid mods that implement the Eclipse packet protocol. Without a compatible server mod, it functions as a passive gimmick fix for doubles/triples battles.
This mod is provided as-is for use with compatible Eclipse server mods.