Files
open-wc/docs/modules/coordinate-mapping.md
T
sindoring ce4f7ec0e2 test(M01): add coordinate golden fixtures
Work-Package: M01-QAR-COORD-FIXTURES-001

Agent: sindo-main-codex
2026-07-13 14:27:38 +04:00

14 KiB

Coordinate Mapping

Metadata

Field Value
Status Implemented
Target/work package M01-FND-COORDS-001, M01-FND-COORD-TILE-AXIS-002, M01-QAR-COORD-FIXTURES-001
Owners Foundation/domain
Last verified Worktree work/sindo-main-codex/m01-coordinate-fixtures, 2026-07-13
Profiles/capabilities All profiles; contract version 2

Purpose

Provide scene-free value objects and one pure CoordinateMapper for positions, ADT grid ownership and world-facing yaw. The module makes every source space explicit before renderer, network, gameplay and authoring consumers migrate.

Non-goals

  • Reading ADT, packet, SQL or scene data.
  • Constructing Vector3, Transform3D, Node or Resource values.
  • Correcting M2/WMO local axes or MDDF/MODF Euler rotations.
  • Selecting maps, validating terrain height or owning streaming focus.
  • Persisting coordinate values in this work package.

Context and boundaries

flowchart LR
    Server[Server / movement X,Y,Z] --> ServerPosition[ServerWorldPosition]
    ADT[MDDF/MODF X,height,Z] --> AdtPosition[AdtPlacementPosition]
    ServerPosition --> Mapper[CoordinateMapper]
    AdtPosition --> Mapper
    Mapper --> Canonical[CanonicalWowWorldPosition]
    Canonical --> Tile[AdtTileCoordinate + AdtTileLocalPosition]
    Canonical --> GodotPosition[GodotWorldPosition]
    GodotPosition --> Adapter[Future scene/render adapter]
    Adapter --> Vector[Vector3 at boundary]
    Scene[Node / Camera3D / scene lookup] -. forbidden .-> Mapper

Allowed dependencies:

  • GDScript scalar math and RefCounted lifetime;
  • other value objects in src/domain/coordinates;
  • callers in network, gameplay, render and server-data adapters.

Forbidden dependencies:

  • Node, Resource, SceneTree, Camera3D and global scene lookup;
  • packet buffers, SQL rows, asset parsers and renderer state;
  • Vector3 as a public mapper input or output;
  • model-specific placement corrections.

Public API

Symbol Kind Purpose Thread/lifetime Errors
CanonicalWowWorldPosition Immutable value Client/server X/Y/Z in yards Any thread; caller-owned reference No bounds validation
ServerWorldPosition Immutable value Server/wire X/Y/Z in yards Any thread; caller-owned reference No adapter validation
AdtPlacementPosition Immutable value MDDF/MODF X/height/Z fields Any thread; caller-owned reference No file validation
GodotWorldPosition Immutable value Godot east/up/south scalars Any thread; caller-owned reference Does not create Vector3
AdtTileCoordinate Immutable value Map_tileX_tileY.adt indices Any thread; caller-owned reference is_within_map_grid() reports invalid indices
AdtTileLocalPosition Immutable value East/height/south offsets from tile north-west corner Any thread; caller-owned reference Values are intentionally unclamped
AdtChunkCoordinate Immutable value MCNK X-east/Y-south indices inside one tile Any thread; caller-owned reference is_within_map_grid() reports invalid indices
CanonicalWowWorldYaw Immutable value Canonical world yaw in radians Any thread; caller-owned reference Constructor does not normalize
ServerWorldYaw Immutable value Movement orientation in radians Any thread; caller-owned reference Constructor does not normalize
GodotWorldYaw Immutable value Godot Y-axis world yaw in radians Any thread; caller-owned reference Constructor does not normalize
CoordinateMapper.server_to_canonical / inverse Pure static methods Preserve server X/Y/Z as canonical Synchronous; new result value Null input is a caller contract violation
CoordinateMapper.canonical_to_godot / inverse Pure static methods Apply Y-up renderer basis and map offset Synchronous; new result value Non-finite scalars propagate
CoordinateMapper.canonical_to_adt_placement / inverse Pure static methods Convert ADT placement field basis Synchronous; new result value Non-finite scalars propagate
CoordinateMapper.canonical_to_adt_tile Pure static method Compute unclamped filename indices Synchronous; new result value Out-of-map result remains invalid
CoordinateMapper.canonical_to_adt_tile_local / inverse Pure static methods Split/reconstruct tile-local position Synchronous; new result value Caller validates tile ownership
CoordinateMapper.adt_tile_local_to_chunk Pure static method Compute unclamped MCNK indices Synchronous; new result value Boundary/out-of-range remains diagnosable
World-yaw mapper methods Pure static methods Normalize and cross the world-basis boundary Synchronous; new result value Non-finite input is unsupported

Inputs and outputs

Direction Contract/data Producer Consumer Ownership Thread/lifetime
Input ServerWorldPosition, ServerWorldYaw Future protocol/server adapter CoordinateMapper Immutable caller value Any thread, call duration
Input AdtPlacementPosition Future ADT adapter CoordinateMapper Immutable caller value Any thread, call duration
Input CanonicalWowWorldPosition, CanonicalWowWorldYaw Gameplay/content/domain CoordinateMapper Immutable caller value Any thread, call duration
Output CanonicalWowWorldPosition CoordinateMapper Gameplay/content/adapters New immutable value Caller-owned reference
Output AdtTileCoordinate, AdtTileLocalPosition, AdtChunkCoordinate CoordinateMapper Streaming/content adapters New immutable values Caller-owned references
Output GodotWorldPosition, GodotWorldYaw CoordinateMapper Future render/scene adapter New immutable values Caller-owned references
Test input coordinate_golden_points.json schema 1 Pinned public server row plus private numeric observations Headless fixture verifier Versioned repository fixture Test-process lifetime

Side effects:

  • none;
  • no scene mutation, file/cache write, network send, database access or logging.

Data flow

flowchart LR
    ServerFixture[Pinned AzerothCore spawn] --> FixtureVerifier[Golden fixture verifier]
    RawADTFixture[Raw ADT numeric metadata] --> FixtureVerifier
    ClientFixture[Build 12340 observations] --> FixtureVerifier
    FixtureVerifier --> Mapper
    Server[ServerWorldPosition X,Y,Z] -->|identity components| Canonical[CanonicalWowWorldPosition]
    ADT[AdtPlacementPosition X,height,Z] -->|half extent - horizontal| Canonical
    Canonical -->|tileX from Y; tileY from X| Tile[AdtTileCoordinate]
    Canonical -->|north-west edge offsets| Local[AdtTileLocalPosition]
    Local -->|floor offset / chunk size| Chunk[AdtChunkCoordinate]
    Canonical -->|half extent - Y; Z; half extent - X| Godot[GodotWorldPosition]
    ServerYaw[ServerWorldYaw] -->|normalize only| CanonicalYaw[CanonicalWowWorldYaw]
    CanonicalYaw -->|same numeric world angle| GodotYaw[GodotWorldYaw]

Lifecycle/state

The module is stateless. Each call reads immutable scalar inputs and returns a new value object. There is no initialization, shutdown, cancellation or retry state machine.

Main sequence

No cross-layer asynchronous sequence occurs inside this module. Producers parse or validate their external format first, call the mapper synchronously, and then pass only typed results across the next boundary.

Ownership, threading and resources

  • Value objects own only scalar fields and, for chunks, one immutable tile reference.
  • Callers own returned RefCounted references.
  • Methods do not mutate inputs or shared state and are safe for worker use.
  • No Node, RID, file, socket, database or cache resource is acquired.

Errors, cancellation and recovery

Failure Detection Behavior Diagnostic Recovery
Tile/chunk outside standard grid is_within_map_grid() Unclamped indices are preserved Caller reports source and map context Reject or apply explicit map policy
Tile-local value outside half-open tile Consumer boundary validation Value is preserved Caller reports source coordinate Recompute ownership or reject malformed input
Null value object Static typing/call failure Programming contract violation GDScript error with call site Fix producer; no fallback value
NaN/infinite scalar Adapter validation Arithmetic propagates invalid value Adapter must report source field Reject malformed external input

There is no cancellation because every conversion is constant-time scalar math.

Configuration and capabilities

Setting/capability Default Profile Runtime mutable Effect
Contract version 2 All No Corrected filename/chunk axes in ADR 0001
Godot units per WoW yard 1 Blizzlike335 and current tools No Preserves current renderer scale
ADT grid 64 tiles/axis, 16 chunks/tile WotLK 3.3.5a No Defines index and boundary math

Persistence, cache and migration

Production code adds no persisted format, cache or migration. Test schema 1 in coordinate_golden_points.json persists explicit source provenance, coordinate contract version 2, tolerances, source-space values and expected outputs. It contains no proprietary bytes, database dump or original-client image. Existing dictionaries, native Vector3 payloads and renderer conversion helpers remain compatible. Consumer migration is ordered after this contract and must remove old manual conversions only after its producer/consumer tests pass.

Any future serialized coordinate must store a schema version and explicit space; raw three-number arrays are not an accepted new persistence contract.

Diagnostics and observability

  • Logs: none in production mapper.
  • Metrics: none; conversion cost is constant and outside frame-budget concern.
  • Debug views: headless contract probe prints one PASS summary.
  • Correlation IDs: supplied by external adapters if an invalid source is reported.

Verification

  • Unit/contract tests: src/tools/verify_coordinate_mapper.gd.
  • Cross-source golden test: src/tools/verify_coordinate_golden_fixtures.gd.
  • Integration/E2E: consumer migration and StreamingFocus packages remain pending.
  • Fidelity evidence: five build-12340 camera positions from the M00 manifest map within 0.002 yard; a pinned AzerothCore human-warrior spawn and one raw MCNK header observation independently confirm tile (32,48) and chunk (3,12); independent reference formulas are recorded in ADR 0001.
  • Performance budgets: constant-time arithmetic; no scene or file access.
  • Manual diagnostics: not required for the pure contract; renderer checkpoints are required when consumers migrate.

Extension points

  • Add typed map IDs around positions without changing axis semantics.
  • Add a format-specific placement-orientation adapter with its own fixtures.
  • Add serialization only with explicit space/version fields and migrations.
  • Add consumer adapters that construct engine-native vectors at their boundary.

Capability status

Capability Status Evidence Gap/next step
Canonical/server/Godot position mapping Implemented Headless round-trip and five M00 golden points Migrate producers/consumers
ADT placement mapping Implemented Synthetic/direct round-trip fixtures Compare native parsed placements during migration
ADT tile/local/chunk ownership Implemented Center/extent boundaries plus raw Azeroth_31_49.adt filename and MCNK direction evidence Migrate streaming consumers
World-facing yaw mapping Implemented Cardinal/wrap round-trip fixtures Placement Euler remains separate
Scene-free production contract Implemented Source boundary and headless test Add dependency search gate later in M01
Cross-source coordinate fixture Implemented Pinned AzerothCore spawn, raw ADT MCNK metadata and five build-12340 points pass one headless verifier Add live adapter/renderer integration
TrinityCore populated spawn equivalence Not verified The base development schema has no pinned populated row used by this fixture Pin and verify a TDB snapshot before claiming parity
Visual/server-spawn integration Planned M01 target criteria Route the fixture through migrated adapters and renderer

Known gaps and risks

  • Existing native loaders and renderer scripts still contain manual conversions.
  • Contract version 1 briefly transposed ADT filename/chunk axes; version 2 fixes the defect before any consumer migration.
  • MDDF/MODF rotation comments and implementations disagree across existing paths; this package deliberately does not generalize them into world yaw.
  • Finite-number validation belongs to external format adapters and is not yet implemented.
  • Arithmetic agreement does not prove terrain, placement, camera direction or visual parity.
  • The golden server row is verified against pinned AzerothCore data only; no TrinityCore equivalence claim is made without a pinned populated TDB snapshot.

Source map

Path Responsibility
src/domain/coordinates/coordinate_mapper.gd Constants and all coordinate-axis conversions
src/domain/coordinates/*_position.gd Immutable typed position values
src/domain/coordinates/adt_tile_coordinate.gd ADT filename tile indices and bounds
src/domain/coordinates/adt_chunk_coordinate.gd MCNK indices and bounds
src/domain/coordinates/*_yaw.gd Immutable typed world-facing yaw values
src/tools/verify_coordinate_mapper.gd Headless fixtures and boundary regressions
src/tests/fixtures/coordinate_golden_points.json Versioned cross-source values, provenance and tolerances
src/tools/verify_coordinate_golden_fixtures.gd Cross-source fixture schema and mapper validation
docs/adr/0001-canonical-world-coordinates.md Normative axes, units, boundaries and rollout decision