Authoritative terrain Z — UO-style diagonal heightfield (design + 3-slice plan) #224
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#224
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Authoritative per-point terrain Z — a UO-style diagonal heightfield. Z is a signed coordinate of the terrain (not a material property, not biome-derived); Z differences between neighbouring points deform the isometric surface diagonally.
rocky_ground/mountain_rockare the first terrains to build and verify on, but it must work for any terrain. The final world map is hand-authored in the editor — this feature does not generate geography.Design agreed via the
critical-design-reviewskill (verdict: go-with-changes → go once the three calls below were made). This issue is the master tracker; the completed Invariants Check + Verification plan live here per CLAUDE.md.Agreed design decisions
ToScreen(x,y,GroundZAt), texcoord(x,y), two UO-diagonal triangles per cell;ground_blend.fxstays unchanged and the blend deforms for free (no per-tile masks to keep coincident). Rejected: reintroducing the per-tile dual-tile mesh model the original prompt assumed.main(linear history, no stacked PR).GroundZAt, centralizedMin/MaxTerrainZ(−225/+255),ZScale(4 px/Z),MaxStepZ(2);TextMapFormatnumeric Z block;ToScreen(x,y,z), UO triangulation, point-in-triangle — all pure, no visible change.MaxStepZgate + mover audit,docs/architecture.md.Invariants Check (CLAUDE.md
## Design checklist)abs(GroundZAt(into)−GroundZAt(from)) ≤ MaxStepZ; client never sends a Z result.move+direction); if the audit finds a real wire need, STOP and bumpProtocolVersion.Currentin that change.GroundZAton the sim thread; no new lock.World.csHARD GATE ✓ step-Z rule inMovementSystem/TileMap.CanStep, notWorld.cs.ScreenHARD GATE (client) ✓ mesh/picking in renderer + Client.Core units;GameScreenonly wires.ToScreen(x,y,z), triangulation, point-in-triangle inClient.Core; only vertex upload/draw inClient.Gameplay/; no transport touched.SetZ(clamped once); no side-collection shadow.world.mapviaIMapFormat), notworld.sav; no entity-save/version change; no tick-loop file IO.MaxStepZ=GameOptionsfield (default once);ZScale/Min/MaxTerrainZ= single Shared/Client.Core constants.DrawUserIndexedPrimitives, no OS-specific API; server pure .NET; shader stays pre-compiled.xnb.docs/architecture.md(durable model, no volatile byte layout); each PR carries its DoD delta.Server-side validation (trust boundary)
Intent unchanged (
move+direction). Server validates inMovementSystem: in-bounds → walkable → no blocker/creature (existing) → newabs(GroundZAt(into)−GroundZAt(from)) ≤ GameOptions.MaxStepZ. Audit all movers: player, creature/AI, spawn, teleport (resolves to a walkable dest, no step-delta), resurrection/relocation, GM. A forged client Z can't become authoritative.Verification plan
CanStepat 0 /MaxStepZ/MaxStepZ+1.ToScreen(x,y,0)==flat;+1 Z==Y−4; adjacent shared vertices bit-identical; diagonal/winding; point-in-triangle on both triangles; picking a ramp + overlapping surfaces; facing invariant under Z.Worldunit + WebSocket flow): allowed step accepted; too-tall step/drop rejected; client can't forge Z; AI respects the surface; teleport semantics./tpto reach the fixture.Definition of Done
−225 ≤ Z ≤ +255.−z*4in one shared place.TileUnderCursorcaller); culling correct via per-chunk min/max Z (not global).Out of scope (guards)
No auto-mountain generator; no biome→Z; Z0/Z<0 ≠ water (hydrology ⟂ elevation); no voxels; no multilayer/caves/overlapping surfaces at the same (x,y) — this slice is a single heightfield; no slope PNGs / fake vertical walls; no client-authoritative Z; no full-map scan per frame/click/stroke; never overwrite the user's world map.
Blocked on: PR #223 merged to
main(owner merge) — then Slice A branches off main.Marco aiutami invece di farti le unghie a tema pokemon 💅
Risolta: terrain Z heightfield autoritativo su main (#225 · #227 · #228).