Skip to content

Fix swapped d22/d23 in call_RMTMatrix_Relative ELSE branch#4

Open
patrickoshaughnessey wants to merge 1 commit into
MetaversalCorp:mainfrom
PatchedReality:fix/relative-d22-d23-swap
Open

Fix swapped d22/d23 in call_RMTMatrix_Relative ELSE branch#4
patrickoshaughnessey wants to merge 1 commit into
MetaversalCorp:mainfrom
PatchedReality:fix/relative-d22-d23-swap

Conversation

@patrickoshaughnessey

Copy link
Copy Markdown
Contributor

Summary

call_RMTMatrix_Relative's ELSE branch has the column references for mr.d23 and mr.d22 listed in the wrong order in the SELECT ... INTO ... clause. In MySQL, SELECT ... INTO ... is positional, so this silently swaps the values:

  • local d22 := mr.d23 (should have been mr.d22)
  • local d23 := mr.d22 (should have been mr.d23)

The subsequent transform extraction then computes:

  • Transform_Scale_dZ = SQRT(d02² + d12² + d22²) = 0 — because local d22 now holds the translation column
  • Transform_Position_dZ = d23 — because local d23 now holds the diagonal scale entry

These corrupt values get written back to the RMTObject row by the UPDATE at the end of the procedure, even though the actual RMTMatrix row is correct. Subsequent reads of the row return the corrupt values, and subscriptions propagate them to all clients.

The bug only affects objects whose parent class is not RMTObject (i.e. sectors parented directly under root). Parcels and physicals go through the IF branch, which uses inline matrix-multiplication expressions whose textual order naturally matches the INTO list, so the bug doesn't manifest there.

It also only affects the z components. Position-y/scale-y come from d13/d11, which aren't reordered. That's why update_object calls that include a non-default y stuck while z reverted to whatever the swapped extraction produced.

Root cause

-- BEFORE (ELSE branch)
SELECT mr.d00, ...
       mr.d20,
       mr.d21,
       mr.d23,    -- ← textually 3rd
       mr.d22,    -- ← textually 4th
       ...
  INTO d00, ...,
       d20, d21, d22, d23,
       ...

In MySQL, the third value in the SELECT list (mr.d23) is assigned to the third INTO target (d22), and the fourth (mr.d22) is assigned to d23. Result: a stable, asymptomatic-on-write but corrupt-on-read state for any sector that has been transform-updated.

Fix

Restore canonical column order so SELECT and INTO agree:

SELECT mr.d00, ...
       mr.d20,
       mr.d21,
       mr.d22,
       mr.d23,
       ...
  INTO d00, ..., d20, d21, d22, d23, ...

The SQL Server version of the same proc had the identical out-of-order textual layout, but SQL Server's syntax is SET @var = column (assignment by name, not position), so it was cosmetic only. This PR also fixes the SQL Server file for consistency, so future contributors don't propagate the bad pattern back into MySQL.

Verification

Reproduced on a live deployment with a corrupted sector row and verified end-to-end:

  1. Confirmed the sector's RMTObject row had Position_dZ=1, Scale_dZ=0 despite the corresponding RMTMatrix row having d22=1, d23=0.
  2. Replaced call_RMTMatrix_Relative from the patched file.
  3. Sent a single update_object transform call to the sector.
  4. Re-read the row: now Position_dZ=0, Scale_dZ=1 — matching the matrix.
  5. Reproduction sequence (sector update → child update → re-read sector) now stays clean; child updates no longer regress the parent's z fields.

Notes for ops

Any sectors in production that have been transform-updated under the buggy procedure currently have corrupt Transform_Position_dZ / Transform_Scale_dZ in their RMTObject rows. They self-heal one-by-one as their transforms are re-touched after the procedure is replaced. A batch heal — rebuilding the row z fields from the matrix d22/d23 for affected sectors — could be done as a separate one-shot UPDATE if desired, but isn't required.

The ELSE branch (taken when the parent is not an RMTObject — i.e. for
sectors directly under root) used a `SELECT ... INTO ...` pattern with
`mr.d23` and `mr.d22` listed in the wrong order against the
`d20, d21, d22, d23` INTO list.

In MySQL, `SELECT ... INTO ...` is positional, so this silently assigned
local `d22 := mr.d23` and `d23 := mr.d22`. The matrix-to-transform
extraction then computed `Transform_Scale_dZ = SQRT(... d22²) = 0` and
`Transform_Position_dZ = d23` from the wrong column, persisting
`scale.z = 0` and `position.z = <translation z>` to the RMTObject row
even though the underlying matrix was correct. Reads from the row
returned the corrupt values; subscriptions propagated them to clients.

The SQL Server version had the same out-of-order textual layout but the
syntax there is `@var = column` (assignment by name, not position), so
it was cosmetic only. Fix both for consistency so the parallel MySQL
bug isn't reintroduced by copying the SQL Server pattern.

Verified on a live database: a sector whose row had been corrupted
self-healed to the correct values on the next transform update after
the procedure was reloaded.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant