namespace DorkNet.Server.Services; /// /// Converts between a sub-room's position in the room /// (, 0-based, what the /// server stores and indexes on) and the SubRoomId the 2023 client /// sees on the wire. /// /// Why they differ. The client refuses to load a sub-room whose /// id is not positive: SubroomModel.DOKCPLJOKIE /// (IsilDump/Assembly-CSharp/RRUI/Data/SubroomModel.txt:3) is /// RoomId > 0 && SubroomId > 0, and /// Model`1.LNPEMMMGCPC skips the load when it is false. With the /// first sub-room advertised as id 0, its Room Settings > Subrooms row /// never fetched its details (SubroomModel.KBOJBJNCOGK → /// FGCPNAACHIK.OBFPEGLLELP(long?)), so the row showed no name, and /// every per-row action (rename, max players, permissions, duplicate) ran /// against a null sub-room. Rec Room's own ids were large unique numbers; /// the client needs only "positive and stable per room". /// /// Mapping. Wire id = OrderIndex + 1, so a room's first /// sub-room is 1. Incoming ids go back through ; /// 0 (and anything negative) is accepted as an alias of the first sub-room, /// which keeps cached client state, old presence rows and bare /// matchmake/room/{id} joins working. /// /// Where the conversion happens. Only at the wire: the room /// details SubRooms[], the sub-room routes /// (rooms/{id}/subrooms/{sub}/*), matchmake/room/{id}/{sub}, /// the room-instance JSON (RoomInstanceDto.subRoomId), the instance /// browser, sub-room save DTOs and permission rows. Everything stored /// (RoomScenes, PrivateInstances, RoomDataBlobs, presence) keeps the /// OrderIndex. /// public static class RoomSceneIds { /// OrderIndex → wire SubRoomId (always ≥ 1). public static long ToWire(long orderIndex) => Math.Max(0, orderIndex) + 1; /// Wire SubRoomId → OrderIndex. 0 and negatives map to the first /// sub-room. public static int ToOrderIndex(long wireSubRoomId) => wireSubRoomId <= 1 ? 0 : (int)Math.Min(int.MaxValue, wireSubRoomId - 1); }