fix(client): draw entities at the mesh display-Z (P2a — kill the float) #270
No reviewers
Labels
No labels
alpha:wave-0
alpha:wave-1
alpha:wave-2
alpha:wave-3
area:assets
area:combat
area:ecology
area:infra
area:render
area:scripting
area:ui
area:world
enhancement
epic
migration
post-alpha
roadmap
tech-debt
type:bug
type:chore
type:design
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
marco/IsoMmo!270
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/render-unify-entity-height"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
P2a of the multi-level world design (
docs/superpowers/specs/2026-08-03-multi-level-world-model-design.md, epic #268): unify the surface height so entities stop floating.The ground mesh draws at the smoothed display-Z (
GroundBlendRenderer, the #247 cliff-smoothing that rounds a cliff into a ramp), but entities (player, mobiles, corpses, statics, ground items) were drawn at the rawGroundZAt. Two different heights for one cell, and withIsoProjection.ZScale = 4(~4 px per Z) the gap detaches the sprite from the ground it stands on — the character "flies and climbs better than Messner" on cliffs and carved roads.Fix: entities are drawn at the same height the mesh uses for their cell. One seam —
ClientWorld.DisplayZAt(renamed fromGroundZAt) is now wired toGroundBlendRenderer.DisplayZ(a new public rounded-int accessor over the existing display-Z window, with a raw fallback outside it). Every entity-draw height routes through it: the mobile/corpseGroundZinjection, the static draw (GridRenderer.DrawStaticnow takes the resolved Z instead of reading rawGroundZAt), and the ground-item projection. The rawGroundZAtstays only for the admin HUD readout and cursor picking (they must show the real terrain Z). Client-only display change: no protocol/persistence/server/gameplay change — walkability still reads the authoritative rawGroundZAtserver-side.Scope note: this is the prerequisite height fix. The dramatic, user-visible win — the character correctly behind a cliff and revealed by an anti-occlusion fade (Diablo/Fallout-style) — is P2b (
§ Relief anti-occlusionin the design), a separate PR. P2a is what puts the character at the right depth for P2b to occlude/reveal it correctly.Screenshots / recording
Piloted the client from a fresh DB (debug-harness):
login test,/tp 6195 2757onto the saved carved road,screenshot. The character renders on the carved-road surface at its display height (render_after.png, harnessscreenshotat tile 6195,2757, "here 50"). Honest note: at this particular cell the display-Z and raw-Z are close, so the delta vs the raw build (the owner's earlier float screenshots) is subtle here — the mismatch is largest, and the fix most visible, in a narrow trench / right at a tall cliff base, and the dramatic fix is P2b's anti-occlusion. Verified the fix compiles, runs, and draws the character glued to the mesh surface; happy to capture a higher-divergence spot on request.How it was tested
dotnet build IsoMmo.slnx→ 0 warnings / 0 errors.dotnet test IsoMmo.slnx→ all green (Shared 177, GameServer 346, Client.Core 196, Auth 19, Scripting 39, MapEditor.Core 66, others — full solution).dotnet csharpier check .→ clean (515 files).GroundZAtreads are the admin HUD readout and cursor picking (intentional).Invariants Check
Client-only display change; most gameplay invariants N/A (each falsifiable).
GroundZAtserver-side; the client sends no Z. · GM auth / Identity N/A. · Protocol versioned ✓ N/A — no wire shape/enum/DTO changed, so noProtocolVersionbump. · String catalog N/A. · Single-threaded sim N/A (client render). ·World.csgate N/A. ·ScreenHARD GATE ✓ the height logic lives inGroundBlendRenderer+ theClientWorldseam;GameScreenonly wires it. · Client engine-independence ✓ the smoothing (TerrainDisplayHeight, Client.Core, unit-tested) is unchanged; this is MonoGame draw glue routing its result. · Gameplay/Networking N/A. · Act on the instance ✓ no side-collection; a singleDisplayZAtprovider. · Extend by type N/A. · Persistence (GameServer/Auth) N/A — no save/schema change. · Process separation N/A. · Typed options N/A. · Broadcasts/AoI N/A. · Multi-platform ✓ pure .NET/MonoGame. · Assets N/A. · ModernUO/D4 N/A for this slice (the surface model is the epic; this is only the height). · Docs & DoD ✓ the design doc (#269) carries P2a's DoD.No
✗.Definition of Done
GroundZAtremains only for the HUD readout + cursor picking; no other entity draw reads it.Checklist
just lintpasses (CSharpier clean + zero-warning build)just testgreen (whole solution)TerrainDisplayHeight); verified by build + harnessPrerequisite slice of #268 (design #269). Anti-occlusion is P2b, separate.