fix(physics): keep remote placement and targeting in one world frame

CreateObject positions are landblock-local, but Runtime first-entry previously submitted remotes with a zero world offset. Runtime now owns the accepted local-player world-frame center and converts remote placements before SetPosition. The local physics host also publishes body.Position rather than CellPosition's landblock-local origin, so TargetManager no longer directs monsters toward a phantom player position. User gate: monster/static placement, chase, and attacks accepted outside Tusker Barracks.
This commit is contained in:
Erik 2026-08-03 08:59:31 +02:00
parent 01f4791e95
commit 670f307c84
7 changed files with 140 additions and 12 deletions

View file

@ -243,7 +243,16 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
motion,
stopCompletely: () =>
_ = controller.StopCompletelyAtPhysicsObjectBoundary(),
getPosition: () => body.CellPosition,
// App/Runtime movement managers use one normalized world
// coordinate frame. PhysicsBody.CellPosition deliberately
// retains retail's landblock-local origin for cell transit;
// publishing it here made every remote TargetManager chase a
// different point whenever the player and world origin were
// not the same landblock.
getPosition: () => new Position(
body.CellPosition.ObjCellId,
body.Position,
body.Orientation),
getHeading: () => MoveToMath.GetHeading(body.Orientation),
setHeading: (heading, _) => body.Orientation =
MoveToMath.SetHeading(body.Orientation, heading),
@ -268,7 +277,10 @@ internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
};
physicsHost = new EntityPhysicsHost(
record.ServerGuid,
getPosition: () => body.CellPosition,
getPosition: () => new Position(
body.CellPosition.ObjCellId,
body.Position,
body.Orientation),
getVelocity: () => body.Velocity,
getRadius: () => preparedActivation.Radius,
inContact: () => body.InContact,