diff --git a/Assets/_Project/Scripts/Simulation/Player/CharacterProcessor.cs b/Assets/_Project/Scripts/Simulation/Player/CharacterProcessor.cs index 08b867f31..3862b41d4 100644 --- a/Assets/_Project/Scripts/Simulation/Player/CharacterProcessor.cs +++ b/Assets/_Project/Scripts/Simulation/Player/CharacterProcessor.cs @@ -34,6 +34,7 @@ namespace ProjectM.Simulation ref CharacterComponent characterComponent = ref CharacterComponent.ValueRW; ref KinematicCharacterBody characterBody = ref CharacterDataAccess.CharacterBody.ValueRW; ref float3 characterPosition = ref CharacterDataAccess.LocalTransform.ValueRW.Position; + float planeY = characterPosition.y; // authored movement plane — restored after the update (see below) KinematicCharacterUtilities.Update_Initialize( in this, ref context, ref baseContext, @@ -100,6 +101,14 @@ namespace ProjectM.Simulation KinematicCharacterUtilities.Update_ProcessStatefulCharacterHits( CharacterDataAccess.CharacterHitsBuffer, CharacterDataAccess.StatefulHitsBuffer); + + // Top-down planar lock: the world is one flat plane and gravity is zero, so any Y gained by + // step-handling/velocity-projection up a sloped collider (convex rock hulls etc.) would persist + // FOREVER — the character ends up floating and its shadow drifts away (07-09 field report). + // Restoring the pre-update Y forbids the CC update itself from ever changing the plane while + // spawn/teleport writes (made outside this update) stay honored. Deterministic + idempotent. + characterPosition.y = planeY; + characterBody.RelativeVelocity.y = 0f; } void HandleVelocityControl(ref CharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext)