feat(net+app): apply ObjScale from PhysicsData (Phase 5c)

The Nullified Statue of a Drudge renders correctly in color/shape
after Phase 5b's SubPalette fix, but the user reported it's rendering
at base drudge size when it should be larger. AC statues use the
PhysicsDescriptionFlag.ObjScale field to scale the base mesh; my
parser was consuming-and-skipping those 4 bytes.

Changes:
  - CreateObject.TryParse: extract the u32 float from the ObjScale
    field instead of advancing past it. Declaration moved to the top
    of the method alongside other accumulators so the PartialResult
    local function at the bottom can reference it for the truncation
    fallback path. Same structural change for position and setupTableId
    since PartialResult already needed them too.
  - CreateObject.Parsed gains ObjScale (float?).
  - WorldSession.EntitySpawn gains ObjScale; propagated through the
    fire site in ProcessDatagram.
  - GameWindow.OnLiveEntitySpawned bakes a scale matrix into every
    MeshRef's PartTransform when ObjScale != 1.0, following the same
    pattern the offline scenery hydration already uses. No change to
    WorldEntity or StaticMeshRenderer — the scale is absorbed into the
    per-part transform the renderer already multiplies through.

Tests: 77 core + 83 net = 160, all green.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-11 18:01:14 +02:00
parent 733f8ff601
commit f67f7851e6
3 changed files with 32 additions and 7 deletions

View file

@ -50,6 +50,7 @@ public sealed class WorldSession : IDisposable
IReadOnlyList<CreateObject.TextureChange> TextureChanges,
IReadOnlyList<CreateObject.SubPaletteSwap> SubPalettes,
uint? BasePaletteId,
float? ObjScale,
string? Name);
/// <summary>Fires when the session finishes parsing a CreateObject.</summary>
@ -234,6 +235,7 @@ public sealed class WorldSession : IDisposable
parsed.Value.TextureChanges,
parsed.Value.SubPalettes,
parsed.Value.BasePaletteId,
parsed.Value.ObjScale,
parsed.Value.Name));
}
}