KH2 Three-Client Co-op Design (Working Draft)
Partly superseded 2026-10-01 by
docs/ONLINE_COOP_PLAN.md. Replaced: the authority model (host simulates all players from forwarded input → owner-authoritative avatars, host-authoritative world, D2/D4) and the actor model (canonical slots on every machine → local-primary with friend-slot puppets, D3, pending spike VUH-1489). Still valid background: no lockstep, host owns enemies/story/transitions, MVP scope cuts, GoA-first testing.
Goal
Build a true 3-client Kingdom Hearts II Final Mix co-op prototype where:
- each player runs their own KH2 client,
- each player has their own local camera,
- all three players share one authoritative world/battle/session,
- the roster can be either:
- normal-party style (Sora + two party members), or
- keyblade-trio style (Sora / Roxas / Riku or similar).
Non-goals for MVP
- deterministic lockstep networking,
- full campaign support,
- split-screen,
- cross-version support,
- perfect parity for Drive/Summon/Limit/cutscene systems.
Platform target
- Kingdom Hearts II Final Mix PC release
- OpenKH Mod Manager + Panacea + Lua Backend for setup/prototyping
- native runtime hook for the final hot path
Chosen architecture
1) One authoritative host, three local cameras
- The host owns room state, enemy state, story flags, transitions, rewards, and save/session truth.
- Every client keeps its own local camera and HUD.
- Camera is never network-synced except for forced event/cutscene states.
2) Canonical slot simulation
Use one shared slot mapping across all machines:
- Slot 0 = PLAYER
- Slot 1 = FRIEND_1
- Slot 2 = FRIEND_2
Ownership is assigned per human:
- Player A owns Slot 0
- Player B owns Slot 1
- Player C owns Slot 2
Important: on every machine, the underlying slot identity stays the same. We do not change the simulation role per client.
Why:
- keeps all clients closer to the same world model,
- fits KH2's native PLAYER / FRIEND_1 / FRIEND_2 layout,
- reduces desync risk compared with making "self" be PLAYER on every machine.
3) Local presentation remap, not simulation remap
Each client locally binds:
- camera follow target -> owned slot
- lock-on target UI -> owned slot
- input injection -> owned slot
- local HUD -> owned slot
This gives each player a personal-feeling camera without rewriting the world simulation identity.
Runtime components
A. Asset mod package
Used for:
- roster definitions,
- member table changes,
- object entry edits,
- battle parameter edits,
- spawn/script edits,
- optional custom models/movesets/animations.
B. Injected runtime hook (kh2coop.dll)
Used for:
- memory reads/writes,
- camera retargeting,
- input interception/injection,
- state capture,
- replica/authority mode switching,
- packet encode/decode,
- desync detection.
C. Host server (kh2coop-server.exe)
Used for:
- lobby/session ownership,
- authoritative state relay,
- connect/reconnect,
- logging,
- optional spectator/admin tools.
Game-side actor model
Session actor table
Stable across the whole session:
ActorId 0-> canonical slot PLAYERActorId 1-> canonical slot FRIEND_1ActorId 2-> canonical slot FRIEND_2
Each actor also has:
Archetype(Sora, Roxas, Riku, Donald, Goofy, etc.)MovesetPackageModelPackageAbilityLoadoutEquipmentLoadoutOwnerPeerId
Recommended MVP roster packs
Pack A: Vanilla-ish party
- PLAYER = Sora
- FRIEND_1 = Donald or Riku-friend package
- FRIEND_2 = Goofy or Roxas-friend package
Pack B: Keyblade trio
- PLAYER = Sora
- FRIEND_1 = Roxas friend-slot build
- FRIEND_2 = Riku friend-slot build
Simulation modes
Host mode
The host simulates:
- all three player slots,
- all enemies,
- all pickups/rewards,
- story/room progression,
- transitions/cutscene gates.
Replica mode (non-host clients)
On non-host clients:
- remote player slots are replica-driven,
- enemy AI is either disabled or heavily overridden,
- damage/rewards are applied only from host-confirmed events,
- transforms/motion states are corrected from snapshots.
This is the single hardest technical area.
Networking model
Principle
- input travels client -> host
- state travels host -> all clients
- important events use reliable delivery
- transforms/snapshots use unordered or sequence-numbered delivery
Client -> host packets
InputFrame
seqclientTimeownedActorIdbuttonsleftStickX,leftStickYrightStickX,rightStickYlockOnRequestspecial1,special2,magicSlot,guard,dodge, etc.
TransitionAck
- acknowledges room load / cutscene gate / resync step
Heartbeat
- latency and health tracking
Host -> client packets
SessionState
- game build hash
- mod hash
- current world/room/program
- canonical roster
- story flag hash
- save/session id
ActorSnapshot
For each player actor:
actorIdslotTypearchetypepositionrotationvelocitymotionIdactionStatecomboStephp/mp/drive/focus-like resourcestargetIdinvuln / stagger / airborne flags
EnemySnapshot
enemyNetIdobjectIdspawnGroupIdposition/rotationmotionIdaiStatehptargetActorIdalive/despawned
Event
Reliable. Examples:
- spawn enemy group
- kill enemy
- reward granted
- room transition begin
- room transition complete
- cutscene begin/end
- player KO
- revive
- force teleport / leash
- session resync required
Why not lockstep?
KH2 has too many hidden timers, stateful battle interactions, story-scripted transitions, and role-dependent behaviors. Host-authoritative snapshots plus reliable events are safer than trying to make three clients simulate identically.
Camera design
Normal gameplay
Every client uses a custom camera follow target equal to its owned actor.
Combat rules
- no camera sync between peers,
- local lock-on only affects local camera presentation,
- target selection request is still sent to host when target-dependent gameplay matters.
Cutscenes / forced cameras
- host sends
CinematicStart - all clients temporarily release local camera override
- remote actors may be hidden, frozen, or snapped to canonical cutscene positions
- host sends
CinematicEnd - clients restore owned-slot camera
HUD design
MVP
- Player 1 may keep more of the vanilla command experience
- Player 2 / 3 get custom overlay controls:
- HP/MP/Drive bars
- lock-on status
- revive prompt
- mapped combat specials
- cooldown indicators
Long-term
A fully custom 3-player HUD would be better than forcing every player through the vanilla command stack.
Combat control plan
Slot 0 (PLAYER)
Can initially keep closer-to-vanilla behavior.
Slot 1 / 2 (FRIENDs)
Use direct mapped controls:
- Attack
- Jump
- Guard
- Dodge
- Lock-on
- Magic 1
- Magic 2
- Team skill / Limit trigger
This avoids depending on the full PLAYER-only command stack for every human.
Progression / save policy
MVP
Host save is canonical. Clients join the host session and do not attempt to merge full campaign saves.
Use a session manifest for:
- world
- room
- spawn program
- story hash
- roster
- loadouts
Later
Add optional persistence for:
- levels
- equipment
- ability loadouts
- cosmetics
Scope cuts for MVP
Disable or postpone:
- Drive forms
- Summons
- Limits beyond a tiny curated subset
- guest-party worlds
- lion / carpet / Atlantica forms
- minigames
- gummi travel
- save syncing
- open campaign joining at arbitrary progress
First playable milestone
"GoA Arena 3P"
Use Garden of Assemblage as the first real target.
Requirements:
- 3 clients connect to one host
- fixed room only
- fixed roster only
- movement / jump / attack / guard / dodge
- one enemy pack or one boss room
- host-authoritative enemy HP and KO handling
- own-camera on every client
- reconnect disabled
- no cutscenes
Success condition: All three players can enter the same room, see each other, fight the same enemies, and finish one encounter without a fatal desync.
Milestones
See IMPLEMENTATION_BACKLOG.md for the detailed milestone breakdown (M0-M8)
with task lists, deliverables, exit criteria, and completion status.
Biggest technical risks
- Friend-slot control and camera override may fight vanilla systems.
- Non-host enemy replica mode may still diverge unless AI is suppressed hard.
- Spawn limits / actor swaps can crash maps.
- Cutscenes and story flags can desync clients immediately.
- Mods/version mismatch between players will cause invalid state.
Immediate next tasks
- Prove camera follow retarget for FRIEND_1 and FRIEND_2 on separate clients.
- Prove client-owned input injection into friend slots.
- Prove host-authoritative transform replication for 3 actors in one room.
- Freeze or override non-host enemy AI cleanly.
- Build the GoA Arena 3P vertical slice.
Relationship to scope expansion
This document describes Product A: Campaign Co-op — the 3-player shared-party mode.
The project now also plans Product B: Public Realm — a persistent-character, public-hub, instanced-adventure mode. Both products share infrastructure (transport, codec, identity, version gating) but diverge in their actor model and session architecture.
- For the full two-product analysis, see
docs/kh2_multiplayer_scope_expansion_review.md. - For the protocol v2 sketch supporting both modes, see
docs/kh2_realm_protocol_sketch.jsonc. - For the architecture breakdown, see
docs/ARCHITECTURE_MODES.md. - For the expanded milestone tree (Tracks A-D), see
docs/IMPLEMENTATION_BACKLOG.md.
Current priority remains this document's scope — finish the 3-player co-op vertical slice before branching into public-realm work. The stable identity types (PeerId, ActorNetId, etc.) and runtime mode enum are already in place in Types.hpp to support the eventual divergence.
