e362aaeb43
Add BefourStudios SciFi environment packs, Gabriel Aguiar VFX, and the ShaderCrew Toon Shader embedded packages, plus combat/enemy/wave/death gameplay systems and supporting vault docs/screenshots. Rename 11 vendor textures from uppercase .PNG/.HDR to lowercase so the case-sensitive Git LFS filters (*.png/*.hdr) match on case-sensitive filesystems (Linux CI, case-sensitive macOS), not just locally where core.ignorecase=true masks the gap. Each .meta moved with its asset so GUID references are preserved. All ~1000 binaries tracked via LFS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.0 KiB
7.0 KiB
date, type, tags, permalink
| date | type | tags | permalink | |||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 2026-06-02 | session |
|
gamevault/07-sessions/2026/2026-06-02-gamefeel-deepening |
Session 2026-06-02 — Game-feel deepening (waves, variety, invuln, auto-target)
Goal
Continue the 2026-06-02_GameFeel_Identity slice's suggested next steps — turn the flat Husk swarm into a sustaining combat loop: (1) auto-target on Husks, (2) respawn safety (invulnerability), (3) enemy variety + a wave/threat director. Same constraints (server-authoritative, deterministic, ctx7-verified, adversarially reviewed). Decisions extend DR-009_GameFeel_Identity_FirstBlood.
Done
- Auto-target on Husks:
AbilityFireSystemsoft auto-target candidate query.WithAll<TrainingDummyTag>()→.WithAny<TrainingDummyTag, EnemyTag>()— Husks are now aim-assist targets (they were already raw-aim hittable). - Respawn invulnerability: new replicated
RespawnInvuln { [GhostField] uint UntilTick }+RespawnState.InvulnTicks.PlayerRespawnSystem(server) sets the window on recovery;HealthApplyDamageSystem(server, predicted group) nullifies player damage while active;HudSystem(client) shows a cyan health bar + "SHIELDED". Stops instant re-death into the swarm. - Wave/threat director:
WaveDirector(baked config) +WaveEnemyPrefab(buffer pool) +WaveState(runtime singleton) +WaveSystem(server state machine): Lull → SpawningBaseCount + (wave-1)*CountPerWaveHusks, one everySpawnIntervalTicksat a deterministic ring, round-robin over the prefab pool → wait for the field clear (noEnemyTag) → Lull(LullTicks). Replaced the flatEnemySpawnersustain (deletedEnemySpawner/EnemySpawnSystem/EnemySpawnerAuthoring). Tick gating usesTickUtil.NonZero+ wrap-safeNetworkTick. - Husk variety: 3 interpolated-ghost variants spawned round-robin — Grunt (
Enemy, 30 HP), Swarmer (EnemySwarmer, 15 HP, fast/weak, small), Brute (EnemyBrute, 80 HP, slow/tanky/hard-hitting, large) — each = different bakedEnemyStats+ its own emissive material (M_HuskSwarmeryellow,M_HuskBrutedeep-red) + scale. SubsceneEnemySpawnerGameObject swapped toWaveDirector(wired to all three). - Cleanup (from runtime):
EnemyAISystem[UpdateBefore(PredictedSimulationSystemGroup)]→[UpdateAfter(...)]— the predicted group is OrderFirst, soUpdateBeforewas silently ignored (console warning); contact damage now intentionally drains the following tick (~16ms melee latency, accepted). Removed a spuriousParticleSystem.durationset (warning).
Validation
- EditMode 74/74 green (no new pure-math helpers; wave logic is stateful/integration-validated at runtime). Console clean of compile errors.
- Runtime (single in-editor client, 6.4.7):
- Wave director: wave 1 spawned 4 Husks (BaseCount), replicated server↔client (4==4); cleared the field → Lull → wave 2 escalated to 6 Husks (BaseCount + CountPerWave). Full spawn→clear→lull→bigger-wave cycle confirmed.
- Variety: distinct baked
maxHP30 / 15 / 80 among live Husks (Grunt/Swarmer/Brute), round-robin from the pool; distinct materials + scales confirmed by screenshot (yellow Swarmers, orange Grunts, a large red Brute). - Invulnerability:
RespawnInvuln.UntilTickset on the player's respawn (server-authoritative, replicated for the HUD cue).
- Adversarial review (7 agents): verified the wave director, variety, invuln replication, and auto-target correct — the "wave deadlock", "escalation overflow", and "0-sentinel conflation" suspicions all came back not-a-bug (the empty-server stall self-heals on respawn + Husks teleport-seek so can't wall-stick; overflow needs wave ~1 billion; writes are
TickUtil.NonZero-guarded). 1 confirmed low-severity finding:RespawnMath.IsDueused a rawnow >= respawnTickcompare — the lone wrap-safety holdout (the slice's tick writes were guarded byTickUtil.NonZero, but this read-side compare was missed). Fixed with a wrap-safe signed-delta(int)(now - respawnTick) >= 0(kept pure-uint, so the 5RespawnMathunit tests stay valid). EditMode 74/74 after the fix.
Diagnosis notes (for future me)
[UpdateBefore(PredictedSimulationSystemGroup)]is IGNORED — the predicted group is OrderFirst inSimulationSystemGroup, and OrderFirst/OrderLast outrankUpdateBefore/After(Unity logs "Ignoring invalid UpdateBefore… because OrderFirst/OrderLast has higher precedence"). A plain-SimulationSystemGroupserver system therefore always runs after the predicted group; to read this tick's post-predicted state use[UpdateAfter(PredictedSimulationSystemGroup)](and accept that anything it appends for the predicted group drains next tick). This corrects the "same-tick" claim in DR-009_GameFeel_Identity_FirstBlood —EnemyAISystemcontact damage is a 1-tick-late (~16ms, imperceptible for melee) event, NOT same-tick. The runtime warning caught what the first review missed.- Wave state machine — avoid the deadlock: only re-enter Lull when
RemainingToSpawn==0AND the field is clear (EnemyTagcount 0). The headless (input-less) player can't kill Husks, so the field never clears and the cycle stalls in Spawning — that's a test-harness artifact, not a bug (a real player clears it; validated by killing Husks viaexecute_code→ the director advanced to wave 2). - Editing a subscene authoring component in code: open the subscene additively,
GameObject.GetComponent/DestroyImmediatethe old authoring +AddComponentthe new + set fields (incl.GameObject[]prefab arrays, which the MCP property setter handles awkwardly) →EditorSceneManager.MarkSceneDirty+SaveScene→ close.AssetDatabase.DeleteAssetis blocked byexecute_codesafety checks — guard duplicate-creates with aLoadAssetAtPath != nullcheck instead. - Server tick-batching warnings in-editor are the known perf artifact (multiple worlds in one process + presentation + earlier unfocused throttle), not a code bug — reliable server state (wave director, RPCs) is robust to it; only one-shot predicted
InputEvents drop under batching.
Open / deferred
- Ranged Husk (Spitter): a server-spawned enemy projectile subsystem for tactical (dodge) depth — the next variety step (melee-only today).
- Wave number on the HUD: needs a replicated game-state ghost (
WaveStateis server-only); the live "HUSKS N" count conveys threat for now. - Boss / mini-boss + per-wave composition weighting (brutes later, swarms early) instead of flat round-robin.
- Server performance: investigate the in-editor tick-batching under the wave load (Burst cache health, world count); validate in a real build.
Next
Add the ranged Spitter (enemy projectile) for combat depth, or resume the milestone track at M6 — server-authoritative grid build placement (DR-008_M5_HomeBase_BaseLayer_Storage). The wave director + variety pool make adding new enemy types data-cheap.