Millions of Debug.Log lines later, I got my Udon mahjong world in a mostly-working state. Try it out, report any bugs

https://vrchat.com/home/launch?worldId=wrld_c69bade4-f2de-4da1-892a-b499b8798190

The world now avoids vrchat's own positional sync completely, instead stuffing all the physics state into bytes that get packed into synchronized strings. As a result, the state syncs immediately, rather than the slow (often never) reconciliation you get with vrchat. In webm related, the desktop player on the left is the client, VR on right owns the tiles. It's the usual vrc pickups locally, but the desktop player sees the new updates snap in every 200ms. It may be feasible to interpolate the positions instead of instant 200ms snaps, but udon is super slow; already the update loops that run every 200ms will chug the game, so adding more every-frame code probably won't be great.

I haven't added any of the other features yet like the english tile faces or an actual scoreboard, will do that later, once I shake out most of the bugs of the basic syncing system. If you're interested in the bitpacking code that powers the sync, check out https://github.com/hiinaspace/just-mahjong/blob/master/Assets/Riichi/OwnAndSortTiles.cs