Phase 1.5 long-term #8, the LAST 1.5 item (design review wf_e14dd739-069:
both HIGHs + the distinct MEDs verified before the session limit ate the
duplicate verifiers; unverified leftovers reasoned-closed in the spec).
Cover = a BlightClutter ghost (Variant 4) with a baked Environment-layer
BoxCollider: the runtime ghost's collider joins BuildPhysicsWorld ->
blocks the player CC and the enemy sweep while alive, and the gap opens
the instant the entity dies. Both hit paths already break it (the
clutter chassis); 8 hits to carve.
Review folds:
- HIGH: the 07-07 anti-stuck nudge would phase enemies THROUGH cover
after ~1.5s (it exists to prevent room soft-locks). The nudge is now
COVER-AWARE: a SphereCast identifies the blocker; a live BlightClutter
ghost suppresses the phase (no soft-lock possible - the blocker is
destructible); static-geometry wedges still nudge.
- HIGH: yield==durability made tanky cover an economy faucet. Deposit
is DECOUPLED from the decrement at both hit sites: ScrapPerHit=0 =
breaks in Remaining hits, yields NOTHING; fractional POSITIVE yields
still credit >=1 (the B1 immortal-sink test pinned this - zero means
zero, positive floors to 1).
- MEDs: HitRadius 1.2 (visual core, not a shot-eating disc), NO cover
in Boss rooms (no boss depenetration backstop), scatter keep-out >=7u
from the room origin (player landing + portal), Variant=4 explicit
(the clutter block's explosive reroll cannot leak).
- Old static layer removed: 8 WorldColliders_RoomCover colliders
(subscene) + the RoomCover_Visuals root (Game.unity).
Verified live: 3 cover ghosts spawned with SOLID baked colliders;
BLOCK - NudgeUntilTick stayed 0 across 3.5s of forced zero-progress
(old code arms at 1.5s); DEPENETRATE - an enemy shoved inside a live
rock exited to 1.7u (backstop holds against ghost colliders); CARVE -
the rock died to the real sweep and the spot probed OPEN. 470/470
EditMode; console clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 1.5 environmental hazard v1 (design-review wf_2cb10454-fdf: 13
findings confirmed + folded; Build Spec in the vault). ~25% of room
clutter seeds as EXPLOSIVE (Variant 3 on the existing replicated byte
- zero new GhostFields/prefabs/RPCs).
The FUSE is the review's fold - one mechanism closes both HIGHs:
- Pop sites (projectile sweep + isServer-gated melee harvest) do NOT
destroy an explosive: they zero the replicated Remaining + add a
server-only BarrelFuse (~36 ticks). The client sees Remaining=0 on a
still-alive barrel across snapshots -> unambiguous fuse cue, and
booms at despawn ONLY when cached Remaining<=0 - a teardown despawn
carries Remaining>0, so portal-advance teardowns can never fire
false booms (HIGH #1).
- HazardExplosionSystem (server, plain group, presence-gated on
BarrelFuse, never lifecycle-gated) detonates at ExplodeTick: radius
damage to LIVING enemies AND players (boss-slam player filter
verbatim; friendly fire = the bait mechanic), SourceTick stamped at
detonation = the authoring moment (HIGH #2: the authored-tick
contract dash i-frames negate against), SourceNetworkId=-1 (the
environment convention - a player id would consume Charger
whiff-punish windows). Fuse rides the RoomTag'd barrel -> teardown
cleans lit barrels free.
- Lit barrels are unhittable at both snapshot sites (no double-pop).
- Client: WorldFeedback caches Variant -> boom-vs-puff split (big
burst + light flash + boom SFX vs the old puff); DynamicLightSystem
gives Variant-3 barrels a red danger glow that STROBES once fused.
Verified: 470/470 EditMode (4 new: fused pop instead of destroy +
unhittable, both-sides damage w/ -1 source + authored tick, dead-player
+ radius filters, unelapsed-fuse inert); live smoke - seeded 3/8
explosive, real-sweep pop, CLIENT observed the fuse cue on the live
ghost, pinned bait enemy took exactly 26 (30->4), walk-out escape
confirmed; console clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every enemy kind now has a unique read on the existing replicated
state (client-only, zero netcode):
- Telegraph COLOURS per EnemyTelegraph.Kind: grunt orange, charger
crimson (boss shares it - shapes already differ: cone/wedge/ring),
spitter toxic-green lane, swarmer yellow. Shapes were already
per-kind; they all rendered the same HDR red.
- Windup VOICES at the onset edge (the existing _prevWindup edge +
strike-beep distance gate): grunt low thud, charger rising roar,
spitter wet hiss, swarmer chitter - kinds read by EAR before the
telegraph ramps.
- Projectile light colour by ownership in DynamicLightSystem: owned
shots stay player-cyan, un-owned (Spitter spit) glows toxic green
(EnemyProjectileColor knob).
Verified live: 12 s combat histogram shows zones rendering with
EnemyDanger_K0 (grunt) + EnemyDanger_K1 (charger) materials keyed to
real windups (screenshot); 466/466 EditMode; console clean. Remaining
distinctness depth (per-kind anim clips, creature locomotion) rides
the parallel Blender workstream.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The BlightClutter destructible-ghost chain (per-room seeding, unified
DR-018-safe sweep, melee + projectile breaking, personal-inventory
drops) already existed end-to-end - the roadmap item's gap was FEEL:
- Visual: prefab Model mesh swapped SM_Env_Rock_Chunk_01 (read as
scenery) -> SM_Prop_Barrel_01 (FantasyKingdom, same proven atlas
material). Base-pivot barrel offset -1 on the Model child (scatter
y=1 is the capsule plane - the base-pivot float gotcha).
- One-hit pop: prefab Remaining 8 -> 2 (both hit paths decrement by
max(1,(int)ScrapPerHit)=2, so one swing/shot shatters); authoring
default kept in sync.
- Density: MaxClutterPerRoom 6 -> 8.
Verified live: 8 barrels seeded in a combat room, grounded (screenshot);
an injected projectile through the real ResourceHarvestSystem sweep
popped one barrel in ONE hit (8 -> 7) and credited 2 Biomass; 466/466
EditMode, console clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Art look LOCKED by the operator from the artlook_* side-by-sides:
clean dark-Synty; PixelOutline._MasterEnabled=0 shipped (feature stays
dev-toggleable via F3; other fullscreen effects remain backlog).
New AmbientMotionSystem (client-only PresentationSystemGroup, the
"world alive" anti-static beat, zero netcode):
- per-biome DRIFT particles from one world-space emitter following the
camera (meadow motes / arid wind-blown dust / cavern motes / blight
spores; palette keys on camera-X region + replicated room biome,
mirroring WorldAtmosphereSystem's switch)
- idle SWAY on the ACTIVE cosmetic flora prop roots near the camera
(LOD children follow the root; probed: none static-batched)
- walk-through RUSTLE: flora brushed by the local player
(GhostOwnerIsLocal idiom) gets a decaying energy shake
Rotations write around a cached base (lossless when toggled off);
knobs in AmbientMotionConfig (scene object, code defaults when absent).
Verified live: drift palettes exact in both regions (meadow
0.62/0.85/0.60 -> arid 0.85/0.68/0.45 on region cross), flora beside
the player rocked (0,0)->(-4.0,+5.0) deg within the rustle+sway
envelope, 466/466 EditMode, console clean. Discovery for follow-up:
the BASE biome's flora props are authored INACTIVE (84 bushes etc.) -
the base has no sway targets until some are re-enabled.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dark-ambient, dynamic-light-first look (RoR2/Death Scourges reference),
built filter-agnostic so the pixel style composes on top:
- New DynamicLightSystem (client-only, PresentationSystemGroup): pooled
point lights follow projectile ghosts; pulsing portal light during
RoomExplore (same ExpeditionPortalPos authority as the beacon); soft
resource-node glow that fades with harvest-shrink; short impact
FLASHES fed by CombatFeedbackSystem's burst funnel (EmitColored +
SpawnVfx -> RequestFlash). Knobs in DynamicLightConfig (scene object,
code defaults when absent).
- Atmosphere darkened: WorldAtmosphereConfig/System palettes moved to
the dark set (base cool dusk, arid burnt dusk, per-room biome consts
darkened); scene fog switched Linear -> ExponentialSquared (the
system's per-region DENSITY writes were dead in Linear mode);
trilight ambient lowered; directional 1.9 -> 1.05 slightly warm.
- 6 landmark mood lights (warpgate cyan, artefact violet x2, survey
camp warm x2, cabin warm); URP additional-lights-per-object 4 -> 8
(was starving the existing Aether lights).
- Art-look gate material: Assets/Screenshots/artlook_{base,room}_
pixel{ON,OFF}.png over the lit scene.
Verified: lights live in Play (20 static at base incl. new landmarks;
pooled dynamics active in-room: node glows + impact flashes), fog/
ambient values confirmed live, 466/466 EditMode, console clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Field report: walking onto hilly-looking colliders (the new convex rock
hulls are ramps) raised the character's Y, and with gravity zero +
SnapToGround off nothing ever brought it back down - the character
floated and its shadow drifted away.
Fix inside CharacterProcessor.PhysicsUpdate: capture the pre-update Y
and restore it (plus zero RelativeVelocity.y) after the CC sequence -
the character update itself can never change the movement plane, while
spawn/teleport writes made outside the update stay honored.
Deterministic + idempotent (rollback-safe), identical on server +
predicted client.
Verified live: player shoved into a cover-hull sloped edge decollided
~1 u horizontally with Y bit-exact at 1.0000 (the case that previously
rode up the slope); 466/466 EditMode, console clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 1.5 stabilize #2 (gate-approved incl. missing-collider adds + the
07-09 height/solid-sweep directive). New ColliderFitTools (Editor,
audit/apply, idempotent) refits the subscene Environment colliders to
the Game.unity render meshes:
- Boundary rings rebuilt 16/24/24 -> 54/82/82 segments (~3.5-4 u arcs)
around the DESIGN radii (30/52 - fitting from the current segments
ratchets inward on re-runs), inner faces fitted to ankle-band
(0.45-2.5) cliff vertices so the wall stops the player before any
visibly rising skirt.
- 8 room cover boxes -> convex MeshColliders of the actual CoverRock_*
meshes (needed Read/Write on 2 PNB rock meshes: a MeshCollider bakes
ONLY if the mesh is readable - InvalidOperationException per bake,
classic scene view still shows the collider).
- 11 landmarks: hint-matched claim-once OBB fits (cabin/tent walk-into
fixed; well/sign/artefact invisible walls removed).
- 85 adds: generic solid sweep (>=0.5 u tall, non-flora, walk-band
geometry, gated by the LOCAL fitted wall radius) - cacti, succulents,
boulders, bone piles, small rocks, craters (full set-piece blocks),
crates, tree trunk, turbine poles, dish, solar rigs. Collider tops
pinned to the visual top (cap 3): nothing solid-looking is
walk-through or walk-over. Elevated-only geometry (rotors, panels)
excluded - no phantom ground walls.
Verified: baked-CollisionWorld probes (ring closure 32/32/region, 10/10
solidity samples across base + both room slots, open ground free,
server==client parity at 323 static bodies), enemy backstop live smoke
(enemy embedded in the new crater block depenetrated out and re-engaged
across ~12 u; 4 others converged normally through ~40 obstacles),
466/466 EditMode, console clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Session log Part C (execution + validation evidence), roadmap stabilize #2
ticked, CLAUDE.md gains the MeshCollider-bakes-only-if-Read/Write gotcha
(38.4 KB, in budget), validation-harness.md gains the EditorApplication.update
guardian + EditorPrefs handoff pattern.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- New Server/PlayerResolve.TryResolve single-sources the RPC
SourceConnection -> NetworkId -> conn->player map resolve (3 sites:
ClassSelectReceive, PrepPurchase, DebugCommandReceive); EntityManager
reads keep it source-gen-safe from Bursted receivers.
- ecb.Dispose() after Playback in 9 Temp-ECB systems (explicit-lifetime
hygiene).
- The TuningConfig.GetOrDefault(ref state) variant of this tail was
REVERTED: state.GetEntityQuery in OnUpdate trips the Entities
"creates a query during OnUpdate" diagnostic per system per world
(caught in Play smoke) - the SystemAPI.TryGetSingleton idiom is
already source-gen-optimal, confirming the original B4 deferral.
Verified: 466/466 EditMode green on the final tree, console clean,
Play smoke 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 10 EditMode files: every bare trailing world.Dispose() now inside using(world){} (single-world) or a [TearDown]+List<World> (the multi-world reject-matrix tests in BoonApplyTests/RouteSelectSystemTests) — an assertion failure can no longer leak the World and mask the true first failure. No test logic changed.
- HudSystem: collapse the blank-line run before the class close; trim the extracted route-map clause from the READY-panel comment.
466/466 EditMode tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract 7 sibling PresentationSystemGroup systems (client-only, observe-only), faithfully relocating methods+fields so behavior is preserved by construction:
- HudSystem (2129->1588L): BoonModalHudSystem, RouteMapHudSystem, MetaShopHudSystem, ClassPrepPortalHudSystem — each owns its own runtime UIDocument (MenuUi.LoadPanelSettings + own sortingOrder + EnsureEventSystem), the proven EnemyMarkerSystem/OnboardingSystem pattern; no shared root, no new static bridge.
- CombatFeedbackSystem (1300->914L): RoomPortalBeaconSystem, EnemyHealthBarSystem, EnemyDangerTelegraphSystem — each owns its FX-root + mats (via FeedbackFx), self-queries enemies + self-detects its edge (health-bar LastHp; danger _prevWindup), prunes its caches each frame.
Verified: compiles clean (0 errors), 466/466 EditMode tests pass, Play world-creation clean (no ComponentSystemSorter cycle, no OnCreate exception, 0 console errors). NOTE: the final VISUAL smoke (panels appear at the right lifecycle; enemy health bars / danger telegraphs / portal beacon render; buttons live) needs a FOCUSED Play pass — the play-mode transition throttles while Unity is unfocused, so I could not drive live frames headlessly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The byte-identical ResolveCamera() (Camera.main -> PrototypeCameraRig fallback) in PlayerInputGatherSystem, BuildSendSystem, and AimReticleSystem now call one CameraResolver.Resolve(); camera-resolution policy lives in one place. Behaviour-identical; compiles clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7 plain-Entities tests: phase-1/2 HP gating, expedition-only targeting (idle on no valid target), telegraphed radial-slam AoE + radius boundary, the B4 lunge-vs-slam windup disambiguation (a lunge elapse must not slam), and knockback immunity. Values pinned to Tuning.Boss* so they track tuning. Closes the last missing-coverage gap from the audit.
466/466 EditMode tests pass (7 new).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New FeedbackFx static (MakeClip/MakeParticleMaterial/MakeBurst/PlayClip/EmitTinted/EmitAt); the 3 *FeedbackSystem copies + AmbientAudio.MakeSting now route through it via 'using static'. MakeBurst takes the FX-root + the per-use gravity/radius/sizeTail that were the only diffs between copies; MakeClip folds in noise + decay. Behaviour-identical by construction (every particle/clip param preserved exactly).
459/459 EditMode tests pass; compiles clean. VFX are presentation-only (no EditMode coverage) -> wants a Play-mode smoke to eyeball hit/death/harvest/structure bursts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- CycleDirectorSpawnSystem: drop the dangling <see cref="CyclePhase.ExpeditionTicks"/> (deleted const in B2) -> plain 'initial phase delay'.
- BuildSendSystem: remove the stale '(Conveyor uses s_ConveyorDir for facing)' comment (field + hotkey deleted in B2).
Comment-only; 459/459 EditMode tests pass. Adversarial verification round (2 agents over the full diff) found no behavior regressions and no false-confidence tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Repoint CLAUDE.md testing example from the deleted HeartbeatSystemTests to HealthApplyDamageSystemTests.
- Stale deleted-system refs: ResourceFieldSpawner/ClutterFieldSpawner(+Authoring) now cite RoomFieldSystem (was ExpeditionFieldSystem); BuildPlaceRequest drops the deleted RegionTransitRequest from its 'mirrors' list.
- Stale package version: 'Netcode 1.13.2' -> 'Netcode 1.x' in ProjectileClassificationSystem + BuildPlaceRequest.
- WorldCollisionComponents: remove the duplicated EnvironmentMask summary line; FeelConfig: fix the mangled 'is hitmap)' sentence.
Comment/doc only; compiles clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- TestWorld: shared plain-Entities fixture (Make/Make<T>/SetTick reconciling the two SetServerTick variants + Player/Enemy builders). Additive; new tests consume it (40-file migration of existing tests deliberately deferred as pure churn).
- TestAttributeGuardTests: scans *Tests.cs and fails on any parameterless public-void method missing a runner attribute — guards the swallowed-[Test] bug (B0). Confirms the suite has no other dead tests.
- PrepPurchaseSystemTests (6): the previously-untested RPC economy — afford, reject-when-broke, once-per-run, non-Staging reject, unknown-id drop, and DR-014 same-tick atomicity.
- SystemOrderingCycleTests: registers the real run/cycle/combat system set and asserts SortSystems() has no circular dependency (invisible to single-system fixtures; only throws at Play) — also de-risks the B5 splits.
459/459 EditMode tests pass. (BossAISystemTests remains queued — the most complex to author faithfully; the boss stays Play-validated meanwhile.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- StructureCatalogAuthoring: WallCostOre -> WallCostBiomass (it bakes a Biomass cost; [FormerlySerializedAs] preserves the scene value).
- Harvester/Fabricator authoring: resource-id byte defaults reference ResourceId.Ore/.Charge instead of magic 2/4.
- RegionMath.RegionBoundaryX (= ExpeditionOffsetX*0.5) single-sources the region-flip X used by HudSystem + OnboardingSystem (was 500f in 3 places).
- CharacterComponent.DefaultGroundedSharpness single-sources the CC sharpness 15f (GetDefault, DashSystem, PlayerDeathStateSystem, PlayerCharacterAuthoring).
- InventorySlot [InternalBufferCapacity] references Tuning.InventoryMaxSlots.
- ConnectionMode enum -> byte-const class (project convention; removes the latent enum-in-Burst trap); field + one Seed() param become byte.
- Tuning.ChargerWindupTicks single-sources the Charger telegraph windup (EnemyBaker + TuningConfig.Defaults; was a bare 30 that could drift).
- (TicksPerSecond deliberately NOT added: no seconds->ticks conversion site exists; the tick-count fields are per-authoring designer tunables, so a const would be unreferenced.)
451/451 EditMode tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Delete (unreferenced in any scene, per operator decision):
- TrainingDummy* chain (authoring/spawner/system/components/prefab) + UpgradePickup* chain (authoring/spawner/systems/components/prefab); remove TrainingDummyTag from the 3 live combat queries (AbilityFire/Melee/HealthApplyDamage now key on EnemyTag) and repoint HealthApplyDamageSystemTests to EnemyTag.
- Dead RPC RegionTransitSystem + RegionTransitRequest (no sender, ungated) + its test.
- Heartbeat + HeartbeatSystem (no WorldSystemFilter, ran no-op every tick) + its test.
- BuildSendSystem dead conveyor/pylon dev hooks (s_ConveyorDir, [/] rotation, Place{Pylon,Harvester,Conveyor} statics).
- Deprecated CyclePhase alias consts (Expedition/Defend/Build/*Ticks); repoint WaveSystemTests to Siege/Calm.
- Unread FeelConfig fields (HitFlashDurationMs, RumbleHeavy) + dangling HudUi doc-comments + stale crefs.
451/451 EditMode tests pass. CLAUDE.md HeartbeatSystemTests example ref to be repointed in B7.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Restore swallowed [Test] on EnemyAIMathTests.SlideVelocity_DegenerateNormal_DeflectsToTangent (dead regression guard for the shipped enemy-stuck-on-cover fix; now runs + passes).
- Extract shared HarvestMath.DepositYield used by ResourceHarvestSystem + MeleeComboSystem; fixes melee mining silently ignoring per-item StackMax (it hard-coded DefaultStackMax) and hoists the melee ledger-buffer fetch out of the per-target loop.
- StatMath.Apply switches on the raw byte (case (byte)ModOp.X) instead of casting to the enum inside the Bursted fold — removes the latent cross-assembly enum-in-Burst ICE trap.
- Add [Min] guards on CycleDirectorAuthoring loss-critical ints (CoreIntegrityMax>=1 so a mis-authored 0 can't bake an instant-loss core; siege sizes >=0).
456/456 EditMode tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Serena dropped from .mcp.json + .serena/ untracked (unused in practice,
flaky on Unity per CLAUDE.md's own caveat); memory stack is now three
layers. Standing auths recorded in the skill: docs auto-commit + auto-push
main->gitea (origin stays ask-first).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MenuUi FindAnyObjectByType; GA prefabAssetPath->assetPath x2; Synty sample
FindObjectsByType overload; dead death_b field removed. Real bug caught by
the sweep: the F3 pixel-art toggle used legacy Input.GetKeyDown under
Input System-only handling -> InvalidOperationException every frame in Play.
Suite green (455).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 07-07 knob edit to WorldFeelConfig replaced the attribute line above
ResetDefaults(), so Enabled/ChipBurstCount/Node* all stayed C# defaults and
NodeFeedbackSystem + WorldFeedbackSystem chips/SFX/micro-punch never ran.
Live-verified: root PTM 0.783 -> child LTW 1.723 (= 2.2 x 0.783), 455/455.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Full-screen URP post effect on the active PC renderer that pixelates the
scene to a fixed low-res grid and draws depth + normal edge-detection
outlines, with color posterization and tone controls, for a stylized
"3D pixel art" look. Runs via Unity's built-in Full Screen Pass feature
(no custom C#); reads camera depth/normals so it applies to DOTS entities
and GameObjects identically.
- PixelOutline.shader/.mat: pixel-snap fill + gamma-space posterize +
brightness/contrast/saturation + depth/normal outlines. Normal
threshold tuned high so outlines don't flood small characters.
- PC_Renderer.asset: FullScreenPassRendererFeature (Depth|Normal, after
post-processing).
- PostFX_Daylight.asset: tonemapping ACES -> Neutral (poppier color).
- Game.unity: brighter base atmosphere (ambient + fog pushed back) and a
stronger directional key light so the fill reads under the effect.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
BLENDER (5 new/re-authored clips, all full-body, mirrored-left-arm axes
FIXED - Synty L shoulders mirror X/twist vs R, verified by axis probes):
- A_Swing_R2L / A_Swing_L2R (0.47s): horizontal slash + backhand with real
anticipation (torso wound 25 deg), 2-frame strikes, follow-through past
the target.
- A_Swing_Finisher (0.60s): overhead crash with a crouch drop into impact.
- A_Special_Slam (0.53s): two-handed ground slam - the Warrior cone finally
LOOKS like a cone attack.
- A_Fire_OneHand re-authored punchier (cock -> full-extension thrust with
torso commit -> recoil kick).
Export lesson: Blender 4.4 slotted actions - reassigning animation_data.
action does NOT bind the slot; force animation_data.action_slot before
export/render or you bake a stale pose.
CONTROLLER: MeleeSwing (one clip for everything) replaced by Swing1/2/3
keyed on new ComboStep int param (replicated MeleeCombo.Step); Fire gated
!IsCone (Ranger shot), new SpecialSlam state on IsFiring+IsCone (Warrior).
DRIVE SYSTEM: writes ComboStep from the replicated combo step and IsCone
from the replicated AbilityRef -> AbilityDatabase blob archetype (works for
remote teammates too).
SWORD: SM_Wep_Sword_01 (SciFiSpace - same pack/atlas as the soldier) as a
mesh-sub-asset child of Hand_R, grip rot (90,0,0) tuned live against the
running entity. Required RigDefinitionAuthoring boneEntityStrippingMode
Automatic -> None so the hand bone entity exists + is posed (stripped bones
never animate attachments). Play-verified: the energy blade rides the fist.
456/456 EditMode.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 'Synty share one Generic skeleton' note was WRONG - the pipeline is
HUMANOID (CharactersAvatar isHuman, muscle-curve clips). Corrected + the
Blender clip recipe added; paid for by archiving Aim-controls, the URP
m_AssetVersion blocker, VolumeProfile persistence, HDRP-convert and the
HudTheme bullets (verbatim in the gotchas archive, 2026-07-06 section).
39,959 bytes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Four clips authored programmatically in Blender on the PolygonSyntyCharacter
skeleton (full-body keys per pose, numeric world-space verification of the
fall: hips 0.88->0.14m) and exported per-action FBX (Key All Bones, Force
Start/End Keying, FBX Units Scale). Imported as HUMANOID - the project's
pipeline is Human rigs (CharactersAvatar isHuman=true; CLAUDE.md's 'Generic'
note was stale), so muscle-space retargeting plays these on the player AND
every monster rig with zero bone-path matching. CopyFromOther failed on the
Blender-added 'Armature' node (hierarchy mismatch) -> CreateFromThisModel;
root motion fully baked into pose (the CC owns the transform).
- A_Death_FallBack (0.90s = exactly the 54-tick corpse window): recoil ->
fall -> flat on the back -> settle. Wired as the Death state on BOTH
controllers, replacing the crouch-idle placeholder.
- A_Fire_OneHand (0.4s): new IsFiring param + Fire state on the player
controller; PlayerAnimationDriveSystem routes FireActive to it (melee owns
IsAttacking again).
- A_Dash_Lean (0.33s): new IsDashing param + Dash state; driven from the
local player's predicted DashState window (not replicated -> remotes skip).
- A_HitReact (0.27s): imported + avatar'd, wiring deferred (needs a
replicated hit-tick source; body flash covers the read today).
456/456 EditMode; Play-validated: forced IsDead renders the soldier flat on
the ground in-game (Blender->FBX->Humanoid->Rukhanka chain proven), Fire
state enters and plays; console clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
B1 SEPARATION: pairwise soft-collision pass INSIDE EnemyAISystem (sole
enemy-Position writer preserved; O(n^2) fine at MaxAlive<=14). Knocked/
lunging enemies keep committed motion but still push neighbours; the boss is
never pushed; enemies yield a small personal radius around players (below
melee range per review B1-1); displacement goes through the swept move so
nothing shoves through walls. SeparationMaxSpeed = live knob.
B2 POISE: the windup-cancel lived in the knockback CONTINUE branches (grunt/
charger/spitter). Threshold on the EXISTING KnockbackState.Speed channel:
light melee (6) nudges without interrupting; the finisher (10.8) and cone
(8) stagger as before. StaggerKnockbackSpeed = live knob (default 7).
B4 BOSS LUNGE: a telegraphed gap-closer on its own cooldown when the target
sits outside slam reach (repositioning - the slam stays the damage beat).
BossState.PendingAttack (server-only byte) disambiguates the shared windup
elapse (review-confirmed: naive reuse would SLAM on a lunge elapse);
LungeState.UntilTick spans windup+travel so the existing IsLunging ghost bit
replicates the tell, and the client draws a travel wedge instead of the slam
ring while it is set.
B5 PARTY HP SCALE: boss Health x(1 + 0.75/extra LIVING expedition player) at
spawn (not RunParticipant - dead-respawned members park at base). Max is a
GhostField so the bar stays truthful.
B6 RUN-FAILED BANNER: silent wipes used to land players home with zero
explanation. Client detects the (in-run)->Staging edge with a launch-cached
Charge (NEVER Returning - a 1-tick transient that precedes the bank by a
tick) and shows EXPEDITION FAILED for 6 s.
B7 FIRE ANIM: the class ability finally moves the body - a stateless window
from replicated AbilityCooldown.NextFireTick minus derived CooldownTicks
(works for predicted local + interpolated remotes, no cached edges).
456/456 EditMode; live Play smoke: launch -> 5 kills credit the room clear
through the corpse window -> boon window opens -> corpses expire clean, no
exceptions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Server: HealthApplyDamageSystem marks EnemyTag Dying{UntilTick} (TickUtil.
NonZero, ~54 ticks) on the lethal 0-crossing instead of instant destroy,
zeroes every live cue (replicated AttackWindup, LungeState + IsLunging bit,
KnockbackState), destroys on expiry; plain-world tests keep instant destroy
(no NetworkTime) so the suite's assertions stay meaningful.
Every consumer now ignores corpses (all confirmed entity-count/unfiltered by
the design review): EnemyAISystem all 4 passes, BossAISystem brain + summon
cap, RoomEnemyDirector room-clear + MaxAlive fit, WaveSystem cap + cleared,
CyclePhaseSystem breach wipe + DefendCleared, ThreatDirector timeout cull,
TurretFire targeting, CoreDamage drain, ProjectileDamage snapshot (corpses
are not shields), AbilityFire auto-aim candidates, debug cull + telemetry.
Wipe passes skip Dying to avoid cross-ECB double-destroys.
Client: EnemyAnimationDriveSystem finally drives the controller's IsDead
param (Health.Current<=0 is the replicated death read; corpse locomotion
zeroed); CombatFeedbackSystem moves the kill CRUNCH to the 0-crossing (the
prune-edge timing would land it ~1 s late) - the prune keeps a small
dissolve puff for corpses and the legacy full read for alive-vanish culls.
456/456 EditMode.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
'sand 1' shipped pure-white BaseColor - the whole desert washed out and
characters/telegraphs sat on a bright field. Project-owned copy
(Mat_Ground_Arid_Dark, 0.72/0.68/0.63) assigned to both room-slot grounds;
the Synty pack asset stays pristine. Clarity doctrine: ground darker +
lower-detail than characters.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SLICE A - rooms become places: ExpeditionBiome duplicated to sub-slot 1
(X+1500) - ground, 205 decor children, rim cliffs, ambience; collider ring +
3 landmark colliders duplicated in the subscene; NEW in-room cover at BOTH
slots (4 collidable rocks each: Environment-layer box colliders in the
subscene + matching Synty rock meshes in Game.unity, placed clear of the
landing point, portal spot, spawn ring and boss spawn). Half of all rooms
previously played on a literal void.
SLICE C - owned FX wired: VFXConfig gains Portal + EnemySpawn slots
(FX_Portal_Round_01 / FX_Dust_Big_01 from PolygonParticleFX); the portal
beacon prefers the authored effect (procedural pillar stays as fallback);
enemies get a spawn-emerge cue on the ghost add-edge (primed-scan guard
skips the connect flood).
SLICE D (teaching) - the two undiscoverable verbs are now taught: dash on
the Move step, class ability + attack on the Rooms step (scheme-aware
glyphs); How-to-Play Controls adds Class ability + Dash rows and fixes the
wrong RT glyph; Loop step 1 mentions class pick + prep; the stale '50
starting Ore' now interpolates Tuning.StartingOre.
456/456 EditMode.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>