Files
Project-M/Docs/Vault/02_Game_Design/Systems_Index.md
T
2026-06-04 21:49:03 -07:00

53 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags:
- design
- index
updated: 2026-06-04
permalink: gamevault/02-game-design/systems-index
---
# Systems Design — Index
One design doc per gameplay system, linked here. Each should state: purpose, components (`IComponentData`), systems (`ISystem`), netcode shape (ghost? predicted vs interpolated? inputs / RPCs), and open questions.
## Systems
### M1 — Player (twin-stick predicted movement) · [[2026-05-30_M1_Player_Slice]]
- **Components** (`ProjectM.Simulation`): `PlayerTag`; `PlayerInput` (IInputComponentData — `float2` Move/Aim, `[GhostField]`, flows via AutoCommandTarget); `PlayerMoveStats` (baked tunables); `PlayerFacing` (`[GhostField]` Direction); `PlayerSpawner` (baked prefab singleton); `GoInGameRequest` (IRpcCommand).
- **Systems:** `PlayerMoveSystem`, `PlayerAimSystem` (`PredictedSimulationSystemGroup`, `.WithAll<Simulate>()`, deterministic — `SystemAPI.Time.DeltaTime` only); `PlayerInputGatherSystem` (client, `GhostInputSystemGroup`); `GoInGameClientSystem` (client) / `GoInGameServerSystem` (server — spawns the owner-predicted ghost, stamps `GhostOwner`, `LinkedEntityGroup` auto-despawn).
- **Netcode shape:** player = **owner-predicted** ghost; client sends input only; server is authoritative. Status: **code-complete + EditMode-verified**; live runtime blocked by [[DR-002_Unity66_Alpha_Netcode_Transport]].
### M2 — Combat (predicted projectile, server damage) · [[2026-05-31_M2_Combat]]
- **Components** (`ProjectM.Simulation`): `Health` (`[GhostField]` Current; baked Max); `HitRadius`; `DamageEvent` (IBufferElementData); `AbilityStats` (auto-target range/cone, cooldown ticks — baked); `AbilityCooldown` (`[GhostField]` NextFireTick); `Projectile` (`[GhostField]` Direction + SpawnId; baked Speed/Damage/Range); `ProjectileSpawner` / `TrainingDummySpawner` (baked singletons); `TrainingDummyTag`. `PlayerInput` gains `Fire` (`InputEvent`).
- **Systems:** `AbilityFireSystem` (predicted; `IsFirstTimeFullyPredictingTick`-gated predict-spawn; server branch applies `AutoTarget`); `ProjectileMoveSystem` (predicted); `ProjectileClassificationSystem` (client; predicted-spawn match by `SpawnId`; **non-Burst**); `ProjectileDamageSystem` (server; **swept** segment-vs-sphere hit); `HealthApplyDamageSystem` (server; DamageEvent → Health, dummy death-despawn); `TrainingDummySpawnSystem` (server; one-shot). Input: `PlayerInputGatherSystem` rewritten as managed `SystemBase` over the generated `ProjectMInput` action-map wrapper.
- **Netcode shape:** projectile = **owner-predicted** ghost, client predict-spawns + classifies against server truth by `SpawnId=(ownerNetId<<16)|absoluteFireCount`; **auto-target & damage server-authoritative**; `Health.Current`/`Projectile.Direction` replicate. Status: **foundation built + runtime-validated** (server loop + replication); live keypress-fire pending an interactive test. Decisions: [[DR-003_M2_Combat_Netcode_Architecture]].
### M3 — Data-driven abilities & modifiers · [[2026-05-31_M3_Data_Driven_Abilities]]
- **Components** (`ProjectM.Simulation`): `AbilityDatabase` (singleton `BlobAssetReference<AbilityDatabaseBlob>`; `AbilityDefBlob`/`CharacterStatsBlob` keyed by `AbilityId`/`CharacterId` byte) + `AbilityPrefabElement` (companion entity-ref buffer for projectile prefabs); `AbilityRef` (`[GhostField]` id) / `CharacterStatsRef`; `StatModifier` (replicated `[GhostField]` buffer, `OwnerSendType.All`, raw-byte `StatTarget`/`ModOp`); `EffectiveAbilityStats` / `EffectiveCharacterStats` (derived, not replicated); `UpgradePickup` / `UpgradePickupSpawner`. `StatMath` (pure fold). **Removed** M2's `AbilityStats` / `PlayerMoveStats`.
- **Systems:** `StatRecomputeSystem` (predicted, `[UpdateBefore]` Aim/Move; folds blob base + modifier buffer → `Effective*` **every tick** — rollback-correct); `AbilityFireSystem` rerouted (effective stats + prefab-by-id + snapshot-at-fire); `PlayerMoveSystem` → effective move; `UpgradePickupSpawnSystem` / `UpgradePickupSystem` (server; overlap-grant via `AppendToBuffer`); `DebugModifierInjectionSystem` (editor-only, server world); `HealthApplyDamageSystem` clamps to effective MaxHealth. Authoring: `AbilityDefinition`/`CharacterStatsDefinition` SOs + `AbilityDatabaseAuthoring` blob baker.
- **Netcode shape:** definitions = baked config (not replicated, identical both worlds); modifiers = **replicated ghost buffer** on the player → both worlds recompute identical effective stats (prediction-correct, validated under tick-batching); pickup = **interpolated** server-authoritative ghost. Status: **built + runtime-validated** (EditMode 38/38). Decisions: [[DR-004_M3_DataDriven_Abilities_Modifiers]].
### M5 — Home base: base-layer + shared storage · [[2026-06-02_M5_HomeBase_BaseLayer]]
- **Components** (`ProjectM.Simulation/HomeBase`): `BaseAnchor` (baked singleton — `AnchorPos`, `GridOrigin`, `CellSize`, `int2 GridDims`; flat/blittable, no entity refs); `BaseGridMath` (pure static — WorldToCell/CellToWorld/IsCellInPlot/IsPointInPlot/ClampCell/PlotCenter; corner-origin, center-returning, half-open, floor); `StorageEntry` (`[GhostField]` buffer — `ushort ItemId`, `int Count`); `SharedStorageContainer` (tag); `StorageSpawner` (baked singleton — prefab + `int2 Cell`); `StorageOpRequest` (`IRpcCommand` — byte Op/ItemId/Count) + `StorageOp` consts; `StorageMath` (deposit-merge / withdraw-clamp-drop, unit-tested).
- **Systems:** `SharedStorageSpawnSystem` (server one-shot — instantiate the container ghost at `CellToWorld(cell)`, destroy spawner); `StorageOpReceiveSystem` (server `SimulationSystemGroup`, NOT predicted — apply the RPC to the singleton container's buffer via `StorageMath`); `StorageOpSendSystem` (client managed `SystemBase` — E/Q keyboard + editor-only `Deposit`/`Withdraw` statics → `StorageOpRequest` RPC). `GoInGameServerSystem` re-rooted onto `BaseGridMath.PlotCenter(BaseAnchor)` (with a `TryGetSingleton` fallback).
- **Netcode shape:** base config = **baked, ghost-free, identical both worlds** (not replicated). Storage container = **ownerless interpolated** server-spawned ghost; its `StorageEntry` buffer is a `[GhostField]` (no `OwnerSendType`/`GhostOwner`) so server mutations replicate to all clients. Deposit/withdraw = **server-authoritative `IRpcCommand`** resolved against the single container singleton, applied outside the predicted loop (no rollback double-apply). Status: **built + runtime-validated** (server == client buffer; EditMode 62/62). Decisions: [[DR-008_M5_HomeBase_BaseLayer_Storage]]. M6 (grid placement) + M7 (production) build on `BaseGridMath` + the runtime-ghost-into-cell spawn path.
### M5.5 — Game feel & identity ("First Blood") · [[2026-06-02_GameFeel_Identity]]
- **Components** (`ProjectM.Simulation`): `EnemyTag`/`EnemyStats`/`EnemyAttackCooldown`/`EnemySpawner` + pure `EnemyAIMath`; `Dead` (enableable, **derived**) + `RespawnState` + pure `RespawnMath`; `TickUtil.NonZero` (the cooldown 0-sentinel guard).
- **Systems:** `EnemyAISystem` (server-only, **plain `SimulationSystemGroup`**, `[UpdateAfter(PredictedSimulationSystemGroup)]` — the interpolated Husk ghost seeks the nearest living player, deals contact `DamageEvent`) + the `WaveSystem` threat director (escalating waves of Husk variants Grunt/Swarmer/Brute — replaced the flat sustain; see [[2026-06-02_GameFeel_Deepening]]); `HealthApplyDamageSystem` +`EnemyTag` death; `PlayerDeathStateSystem` (both worlds, predicted — derives `Dead` from `Health<=0`, gates movement/aim/fire via `.WithDisabled<Dead>()`); `PlayerRespawnSystem` (server-only — schedule + refill + reposition). Client presentation (managed, `PresentationSystemGroup`): `CombatFeedbackSystem` (damage numbers / VFX / procedural SFX / camera shake by edge-detecting replicated Health) + `HudSystem` (code-built uGUI health / cooldown / threat / DOWNED) + `PrototypeCameraRig.AddShake`.
- **Netcode shape:** Husk = **ownerless interpolated** server-driven ghost (stock `LocalTransform` replication; `Health` `[GhostField]`); `Dead` = **local derived** enableable (NOT replicated — pure function of replicated Health); juice/HUD **observe** replicated state only (client world, never the sim). Identity: [[Identity]] (sci-fi frontier colony). Status: **built + runtime-validated** (Husks spawn(6)/replicate/chase/strike; death→respawn loop; HUD; emissive dark-sci-fi look); EditMode **74/74**. Decisions: [[DR-009_GameFeel_Identity_FirstBlood]].
### Post-M8 — World-space cohesion pass (clearing + buildable Wall/Pylon + Blightfield dressing) · [[2026-06-04_World_Space_Cohesion_Pass]]
- **Components** (`ProjectM.Simulation`): `BlightClutter` (ownerless-interpolated ghost — `[GhostField]` Remaining+Variant, server-only ScrapResourceId/ScrapPerHit; RegionTag{Expedition} **sibling of `ResourceNode`**) + `ClutterFieldSpawner` (optional baked singleton); `StructureType.Wall=5`/`Pylon=6` (byte consts; 24 stay reserved for M7).
- **Systems:** `ResourceHarvestSystem` **unified** to sweep nodes AND clutter in one best-target loop (required — two separate sweeps would double-destroy an overlapping projectile at ECB playback; `math.max(1,(int)yield)` guards the immortal-sink); `ExpeditionFieldSystem` scatters/clears clutter beside the node field (distinct seed); `BuildPlaceSystem` **unchanged** (already type-generic) — new generic `StructureAuthoring{byte Kind}` + two additive `StructureCatalog` rows + `BuildSendSystem` V/N keys. Client: `WorldFeedbackSystem` (observe-only `PresentationSystemGroup` — chip/shatter juice, proximity-gated so region-transit stays silent) + live-tunable `WorldFeelConfig`.
- **Netcode/world shape:** clutter = ownerless interpolated, region-scoped via GhostRelevancy (like nodes); Wall/Pylon = ownerless interpolated structure ghosts (`PlacedStructure.Type` byte-additive → **no re-bake**); Wall carries a `PhysicsCollider` (CC-blocking), Pylon cosmetic. Visual: `M_Aether_Wild`/`M_Aether_Ordered` palette materials + a classic-URP Blightfield rock basin in `Game.unity` (relief via props, **no terrain**). Status: **built + validated** (EditMode **142/142**; in-editor Play introspected via execute_code; 4-lens adversarial review → 4 findings fixed). Decisions: [[DR-018_World_Space_Cohesion_Pass]] (builds on the M6 region split / build pipeline + M8 persistent base — those systems are documented in their DRs).
## Conventions
DOTS/ECS conventions live in repo `CLAUDE.md` and the `dots-dev` skill's `dots-conventions.md`. Don't duplicate volatile API details here — link to context7-derived notes instead.