ghost multiplayer: fix wire-struct packing; set default relay to relay.mithraic.lol

- #pragma pack(1) on all protocol structs: alignas(1) set the struct
  alignment but still let the compiler pad members to their natural
  alignment - the uint16_t payload_size landed on an even offset, so
  PacketHeader was 8 bytes instead of 7 and the relay's
   guard dropped every real 7-byte packet
  (n=7 < 8). The in-process tests passed only because BuildPacket/PacketSize
  used the same inflated size on both sides. With true packing the struct
  sizes now equal the wire sizes exactly (PacketHeader=7, PosePayload=3140,
  HelloPayload=687, RoomsPayload=1266, ...), verified.
- kGhostDefaultServer -> relay.mithraic.lol (the production beta relay on
  the OVH VPS; IPv6 PTR set, IPv4 PTR still pending at OVH).
This commit is contained in:
MiTHRAL 2026-08-26 23:17:08 -04:00
parent 1763b39eca
commit 32c5e438ed

View file

@ -35,8 +35,10 @@ constexpr uint32_t kGhostMaxRoomMembers = 4; // member names shown per room
// captured count are identity-padded so every mesh's referenced bones stay
// in range on the receiving side.
constexpr uint32_t kGhostMaxBones = 64;
// Placeholder default public relay: replace in ONE place (skate3_native_ghost.cpp).
constexpr const char* kGhostDefaultServer = "ghost.skate3.example";
// Default public relay (the production beta relay on the OVH VPS). Clients
// connect OUTBOUND to this; no port forwarding on any client. Override at
// runtime with skate3_ghost_server.
constexpr const char* kGhostDefaultServer = "relay.mithraic.lol";
constexpr uint16_t kGhostDefaultServerPort = 40001;
// A LAN host with no room advertised is implicitly in this room.
constexpr const char* kGhostLobbyRoom = "LOBBY";
@ -53,7 +55,15 @@ enum PacketType : uint8_t {
kTypeRooms = 9, // relay -> client: { RoomsPayload } (the lobby browser)
};
struct alignas(1) PacketHeader {
// True byte-packing: the struct layouts below must match the wire format
// exactly (the receiver bounds-checks every packet against these sizes, and
// the relay rejects undersized datagrams with `n < sizeof(PacketHeader)`).
// alignas(1) alone is NOT enough - it sets the struct alignment but the
// compiler still pads MEMBERS to their natural alignment (a uint16_t lands
// on an even offset, inflating PacketHeader to 8 bytes and dropping every
// real 7-byte packet).
#pragma pack(push, 1)
struct PacketHeader {
uint32_t magic;
uint8_t type;
uint16_t payload_size; // bytes following this header
@ -201,10 +211,11 @@ struct GhostPoseReassembler {
// Largest payload: PoseChunkPayload (1214 bytes).
constexpr uint16_t kGhostMaxPayload = 3200;
struct alignas(1) PacketBuf {
struct PacketBuf {
PacketHeader h;
uint8_t payload[kGhostMaxPayload];
};
#pragma pack(pop)
inline uint16_t PacketSize(const PacketBuf& p) {
return uint16_t(sizeof(PacketHeader) + p.h.payload_size);