Files
AIC-Project/docs/superpowers/plans/2026-08-10-fighter3d-networked-minigame.md

159 lines
6.3 KiB
Markdown

# Fighter3D Networked MiniGame Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Build a first playable server-authoritative Fighter3D networked mini game in the existing hot-update mini game framework.
**Architecture:** Follow the existing RockPaperScissors mini game layout. Put deterministic combat rules and snapshot codec in `Fighter3D.Core`, room authority in `Fighter3D.Server`, and Unity-only UI/input in `Fighter3D.Client`.
**Tech Stack:** C# 9, .NET `netstandard2.1` hot-update projects, xUnit server tests, Unity runtime APIs only inside the client hot-update assembly.
## Global Constraints
- Do not hand-edit Unity `.meta`, `.prefab`, `.unity`, `.mat`, `.asset`, `.controller`, or `.anim` files.
- Core must not reference `UnityEngine`.
- Client must send gameplay messages only through `IGameClientCtx.Send`.
- Client assets must load through `ctx.Assets.Load`.
- Server is authoritative for damage, block, KO, winner, and settlement.
- First playable scope excludes jump, crouch, command specials, supers, polished 3D assets, and replay tooling.
---
### Task 1: Core Combat Model
**Files:**
- Create: `Client/Assets/MiniGames/Fighter3D/scripts~/Core/FighterTypes.cs`
- Create: `Client/Assets/MiniGames/Fighter3D/scripts~/Core/FighterLogic.cs`
- Create: `Server/games-src/Fighter3D/Fighter3D.Core/Fighter3D.Core.csproj`
- Modify: `Server/Server.Host.Tests/Server.Host.Tests.csproj`
- Test: `Server/Server.Host.Tests/Fighter3DLogicTests.cs`
**Interfaces:**
- Produces: `Fighter3D.Core.FighterLogic.CreateInitial(RoomConfig, IRandom) : FighterState`
- Produces: `Fighter3D.Core.FighterLogic.Step(FighterState, FighterInput, IRandom) : StepResult<FighterState, FighterEvent>`
- Produces: `Fighter3D.Core.FighterLogic.Encode(FighterState) : byte[]`
- Produces: `Fighter3D.Core.FighterLogic.Decode(byte[]) : FighterState`
- [ ] **Step 1: Write failing core tests**
Create tests that assert initial state, movement clamp, light hit damage/stun, guard block, timeout winner, and codec round-trip.
- [ ] **Step 2: Run tests and verify red**
Run: `dotnet test Server/Server.Host.Tests/Server.Host.Tests.csproj --filter Fighter3DLogicTests`
Expected: compile failure because `Fighter3D.Core` does not exist.
- [ ] **Step 3: Implement minimal core**
Implement two fighters, fixed 60 Hz step accumulation, stage bounds, facing, horizontal movement, light/heavy attacks, attack active collision by range, guard-away block, hit/block stun, HP, KO, timeout, and packet codec.
- [ ] **Step 4: Run tests and verify green**
Run: `dotnet test Server/Server.Host.Tests/Server.Host.Tests.csproj --filter Fighter3DLogicTests`
Expected: all Fighter3D core tests pass.
### Task 2: Server Room Authority
**Files:**
- Create: `Server/games-src/Fighter3D/Fighter3D.Server/Fighter3D.Server.csproj`
- Create: `Server/games-src/Fighter3D/Fighter3D.Server/FighterServerRoom.cs`
- Modify: `Server/Server.Host.Tests/Server.Host.Tests.csproj`
- Test: `Server/Server.Host.Tests/Fighter3DServerRoomTests.cs`
**Interfaces:**
- Consumes: `FighterLogic`, `FighterInput`, `FighterState`
- Produces: `Fighter3D.Server.FighterServerRoom : IGameServerRoom`
- Produces: `FighterServerRoom.InputOpcode = 1`
- Produces: `FighterServerRoom.SnapshotOpcode = 100`
- [ ] **Step 1: Write failing room tests**
Create tests that start a two-player room, assert initial broadcast, send attack input from player 1, tick until KO, and assert `EndRoom` winner is player 1.
- [ ] **Step 2: Run tests and verify red**
Run: `dotnet test Server/Server.Host.Tests/Server.Host.Tests.csproj --filter Fighter3DServerRoomTests`
Expected: compile failure because `Fighter3D.Server` does not exist.
- [ ] **Step 3: Implement minimal room**
Map `PlayerInfo.PlayerId` to seats, decode input messages, feed Core, broadcast snapshots each room tick, and call `EndRoom(RoomEndResult)` exactly once when Core is finished.
- [ ] **Step 4: Run tests and verify green**
Run: `dotnet test Server/Server.Host.Tests/Server.Host.Tests.csproj --filter Fighter3DServerRoomTests`
Expected: all Fighter3D server room tests pass.
### Task 3: Client Hot-Update Shell
**Files:**
- Create: `Client/Assets/MiniGames/Fighter3D/scripts~/Client/FighterGameClient.cs`
- Create: `Client/HotUpdateGames/Fighter3D.Client/Fighter3D.Client.csproj`
**Interfaces:**
- Consumes: `FighterLogic.Decode(byte[])`
- Produces: `Fighter3D.Client.FighterGameClient : IGameClient`
- [ ] **Step 1: Implement client shell**
Load `Assets/MiniGames/Fighter3D/res/UI/Prefab/UI_Fighter3D.prefab` through `ctx.Assets.Load`, fallback to a generated Canvas if it is missing, bind no-prefab UI labels, send input frames, and update HUD from snapshots.
- [ ] **Step 2: Build client project**
Run: `dotnet build Client/HotUpdateGames/Fighter3D.Client/Fighter3D.Client.csproj -c Release`
Expected: build succeeds.
### Task 4: MiniGame Publish Metadata
**Files:**
- Create: `Client/Assets/MiniGames/Fighter3D/README.md`
- Create: `Client/Assets/MiniGames/Fighter3D/publish.json`
**Interfaces:**
- Produces: `gameId = "fighter3d"`
- Produces: `clientEntryType = "Fighter3D.Client.FighterGameClient"`
- Produces: `serverEntryType = "Fighter3D.Server.FighterServerRoom"`
- [ ] **Step 1: Add publish metadata**
Create `publish.json` matching the existing RPS fields with `playerCount` 2 and `tickRateHz` 20.
- [ ] **Step 2: Build server and client projects**
Run: `dotnet build Server/games-src/Fighter3D/Fighter3D.Server/Fighter3D.Server.csproj -c Release`
Run: `dotnet build Client/HotUpdateGames/Fighter3D.Client/Fighter3D.Client.csproj -c Release`
Expected: both builds succeed.
### Task 5: Verification
**Files:**
- No new files.
**Interfaces:**
- Verifies all earlier outputs.
- [ ] **Step 1: Run focused tests**
Run: `dotnet test Server/Server.Host.Tests/Server.Host.Tests.csproj --filter Fighter3D`
Expected: all Fighter3D tests pass.
- [ ] **Step 2: Run full server host tests if focused tests pass**
Run: `dotnet test Server/Server.Host.Tests/Server.Host.Tests.csproj`
Expected: pass, or document unrelated existing failures.
- [ ] **Step 3: Check working tree**
Run: `git status --short`
Expected: only intended Fighter3D files plus pre-existing unrelated user changes.