6.7 KiB
6.7 KiB
tags, updated, permalink
| tags | updated | permalink | ||
|---|---|---|---|---|
|
2026-05-29 | 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 —float2Move/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.DeltaTimeonly);PlayerInputGatherSystem(client,GhostInputSystemGroup);GoInGameClientSystem(client) /GoInGameServerSystem(server — spawns the owner-predicted ghost, stampsGhostOwner,LinkedEntityGroupauto-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.PlayerInputgainsFire(InputEvent). - Systems:
AbilityFireSystem(predicted;IsFirstTimeFullyPredictingTick-gated predict-spawn; server branch appliesAutoTarget);ProjectileMoveSystem(predicted);ProjectileClassificationSystem(client; predicted-spawn match bySpawnId; non-Burst);ProjectileDamageSystem(server; swept segment-vs-sphere hit);HealthApplyDamageSystem(server; DamageEvent → Health, dummy death-despawn);TrainingDummySpawnSystem(server; one-shot). Input:PlayerInputGatherSystemrewritten as managedSystemBaseover the generatedProjectMInputaction-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.Directionreplicate. 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(singletonBlobAssetReference<AbilityDatabaseBlob>;AbilityDefBlob/CharacterStatsBlobkeyed byAbilityId/CharacterIdbyte) +AbilityPrefabElement(companion entity-ref buffer for projectile prefabs);AbilityRef([GhostField]id) /CharacterStatsRef;StatModifier(replicated[GhostField]buffer,OwnerSendType.All, raw-byteStatTarget/ModOp);EffectiveAbilityStats/EffectiveCharacterStats(derived, not replicated);UpgradePickup/UpgradePickupSpawner.StatMath(pure fold). Removed M2'sAbilityStats/PlayerMoveStats. - Systems:
StatRecomputeSystem(predicted,[UpdateBefore]Aim/Move; folds blob base + modifier buffer →Effective*every tick — rollback-correct);AbilityFireSystemrerouted (effective stats + prefab-by-id + snapshot-at-fire);PlayerMoveSystem→ effective move;UpgradePickupSpawnSystem/UpgradePickupSystem(server; overlap-grant viaAppendToBuffer);DebugModifierInjectionSystem(editor-only, server world);HealthApplyDamageSystemclamps to effective MaxHealth. Authoring:AbilityDefinition/CharacterStatsDefinitionSOs +AbilityDatabaseAuthoringblob 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) +StorageOpconsts;StorageMath(deposit-merge / withdraw-clamp-drop, unit-tested). - Systems:
SharedStorageSpawnSystem(server one-shot — instantiate the container ghost atCellToWorld(cell), destroy spawner);StorageOpReceiveSystem(serverSimulationSystemGroup, NOT predicted — apply the RPC to the singleton container's buffer viaStorageMath);StorageOpSendSystem(client managedSystemBase— E/Q keyboard + editor-onlyDeposit/Withdrawstatics →StorageOpRequestRPC).GoInGameServerSystemre-rooted ontoBaseGridMath.PlotCenter(BaseAnchor)(with aTryGetSingletonfallback). - Netcode shape: base config = baked, ghost-free, identical both worlds (not replicated). Storage container = ownerless interpolated server-spawned ghost; its
StorageEntrybuffer is a[GhostField](noOwnerSendType/GhostOwner) so server mutations replicate to all clients. Deposit/withdraw = server-authoritativeIRpcCommandresolved 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 onBaseGridMath+ the runtime-ghost-into-cell spawn path.
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.