Files
t5de-hub/docs/hosted-rooms.md
T
dhkatzandClaude Opus 5.5 43183ec7ee
CI / test (push) Successful in 58s
Hosted rooms' instance IDs name their owner: <owner>-<2100000000+n>
The client takes a room's owner from the instance ID's first part; with 2100000000 there, the owner
couldn't decorate their hosted room (putting furniture on went to their home room instead).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 05:18:19 -07:00

6.0 KiB

T5DE-hosted rooms (phase 1)

A hosted room lives on the hub (design.md, Rooms): T5DE users find it in the client's room list, join it, sit and chat, and its owner decorates it. The client treats it as an ordinary IMVU room: T5DE's proxy answers the client's room calls and runs the room's IMQ queue against the hub (imq-rooms.md has what the client expects). IMVU never hears of hosted rooms.

Phase 1: rooms created on the website; joining, seats, chat (messages and control mounts), the scene (the owner's furniture), occupancy in the room list. Later: moderators, bans and boots, invitations, private rooms.

IDs

IDs IMVU won't use, so the proxy can tell hosted rooms apart:

  • A room has a number n (1, 2, ...), its instance ID is <owner's IMVU ID>-<2100000000 + n> and its chat ID is 2100000000 + n. The client takes a room's owner from the instance ID's first part (so the owner can decorate it); IMVU's own room numbers are small. (IMVU's chat IDs were about 1,390,000,000 in 2026-10, and XML-RPC integers end at 2,147,483,647; IMVU customer IDs, the first part of its instance IDs, are far below 2,100,000,000.)
  • The room shell is an IMVU product (roomPid), chosen when the room is made (any room product; the client loads it like any room).
Route
POST /api/v1/hosted-rooms {name, description, roomPid, rating, maxUsers, imvuId}: make a room. imvuId is one of the person's linked IMVU accounts, shown as the owner. rating general or adult (adult needs an adult person). maxUsers 2-30, default 10. Name 1-64 characters, description up to 512. A person may own up to 10 open rooms.
GET /api/v1/hosted-rooms (also signed out) {rooms: [room]}, open rooms, newest first; adult rooms only for adults. ?mine=1: the person's own.
GET /api/v1/hosted-rooms/:n (also signed out) {room, scene: {contents, hash}}; 404 not_found (or adult, for others), 410 closed.
PATCH /api/v1/hosted-rooms/:n owner: {name?, description?, rating?, maxUsers?, roomPid?}.
PUT /api/v1/hosted-rooms/:n/scene owner: {contents, roomPid?}, from the client's test.setRoomState.
DELETE /api/v1/hosted-rooms/:n owner (or moderator console): closes it; everyone in it is told (room.closed).

A room: {n, instanceId, chatId, name, description, roomPid, rating, maxUsers, ownerImvuId, ownerName, occupancy, createdAt} (ownerName: the owner's IMVU name as linked; occupancy: people in it now). A room whose owner account is no longer linked to its owner (unlinked, or moved to another person), or whose owner is banned, is hidden (not listed, not_found) until it's linked again. Closed rooms stay closed; their numbers aren't reused.

The scene's contents is the client's room_contents: a list of [furniture instance ID (integer), product ID (integer or a hub product ID string), placement (string)], up to 500 items, placement up to 200 characters. hash is a hash of the stored scene (the client caches scenes by it): sha256, hex, of [roomPid, contents] as JSON.

Realtime (the proxy's WebSocket)

From the proxy (the session's IMVU account, sent with session, must be linked to the person):

  • {"type": "room.join", "room": n}: join. Answer {"type": "room.joined", "room": n, "chat": chatId, "participants": [{"imvu_id", "seat"}], "sequence": s} (the room's latest message number), or {"type": "room.error", "room": n, "reason": "full" | "closed" | "adult" | "not_found" | "not_linked" | "too_many", "message": "..."} (too_many: the session is in 5 hosted rooms already). Joining again (a reconnect) answers the same. A newcomer's seat is 0 until it sends room.seat. maxUsers counts IMVU accounts, so the same account joining from a second session isn't refused as full.
  • {"type": "room.leave", "room": n}.
  • {"type": "room.seat", "room": n, "seat": k}: the person sat down (*seat k); 0-99.
  • {"type": "room.send", "room": n, "mount": "messages" | "control", "message": "..."} (up to 64 KB): to everyone else in the room. For messages the hub checks the JSON's userId is the sender's IMVU account and drops it otherwise (silently). Each session may send bursts of 20, then 10 a second; more is dropped. Malformed messages (bad room, seat, mount, a message over 64 KB, sending to a room it isn't in) get {"type": "error", "message"}.

From the hub:

  • {"type": "room.message", "room": n, "from": imvuId, "mount": "...", "message": "...", "sequence": s}: numbered per room, from 1.
  • {"type": "room.participants", "room": n, "participants": [{"imvu_id", "seat"}]}: whenever someone joins, leaves or sits (not to the one joining: room.joined has the list).
  • {"type": "room.closed", "room": n}: the room closed, or this session is out of it: its IMVU account was unlinked or it sent session with another account, or the room became adult and its account isn't. (A lower maxUsers sends no one out; it only stops newcomers.)

A session closing leaves its rooms. The hub keeps the participants and message numbers in memory; messages aren't stored (design.md: chat retention).

The proxy's part

  • XML-RPC for hosted IDs, answered by the proxy (never sent to IMVU): test.getRoomCardInfo, chat.getOrMakeChat (activity publicroom-<owner>-<2100000000+n>: joins, answers chatId, seat, lastMessageId, participantUrl), test.getRoomState (the scene, with community products as local IDs), chat.getParticipants, chat.terminateChat, test.setRoomState (owners: saved with PUT .../scene).
  • IMQ: subscribing to /chat/<chatId> of a hosted room is answered by the proxy (result, JoinedQueue, CreateMounts for control, messages, participants); SendMessage on it goes to the hub as room.send, and room.message comes back as G2cSendMessage. inv:/room/room-<owner>-<2100000000+n> is answered with a result and a node mount, and nothing more.
  • Room list: hosted rooms are added to rooms_list_paginated.php's answer, and room_occupancy/<owner>-<2100000000+n> queues are answered from room.participants.