Room State
Walking flow:
Client Server Room (all clients incl. walker)
│ │ │
│── [3320] Walk(5,3) ───>│ │
│ │ A* pathfind to (5,3) │
│ │ compute tile path │
│ │ ┌─ game tick fires ──────── │
│ │ │ advance one tile │
│ │ │ set status: mv x,y,z │
│ │ └────────────────────────── │
│ │ │
│ ┌── [1640] UserStatus #1 (tick 1: first step) ──────>│
│ │ statusString="/mv 3,2,0.5/" │
│ │ (body: id, prevX, prevY, prevZ, headRot, bodyRot, │
│ │ statusString - prevX/Y/Z = tile just LEFT) │
│<─┘ │ │
│ │ ┌─ next tick ────────────── │
│ │ │ advance another tile │
│ │ └────────────────────────── │
│ │ │
│ ┌── [1640] UserStatus #2 (tick N: intermediate) ────>│
│ │ statusString="/mv 4,3,0.0/" ← still has mv │
│ │ (one broadcast per tile per tick until goal) │
│<─┘ │ │
│ │ ┌─ final tick: goal reached │
│ │ │ remove "mv" status │
│ │ │ onWalkOn() fires for tile│
│ │ └────────────────────────── │
│ │ │
│ ┌── [1640] UserStatus #3 (arrival) ─────────────────>│
│ │ statusString="/" ← no mv, just final position │
│ │ (prevX/Y/Z = last intermediate tile; │
│ │ client snaps avatar to final position) │
│<─┘ │ │
Why
[1640] UserStatuscarriesprevX/Y/Z, not current position:RoomUserStatusserializesgetPreviousLocation()+getPreviousLocationZ(), not the current tile. After serializing it callssetPreviousLocation(getCurrentLocation())to advance the window. This means each packet tells the client "I was at (prevX,prevY,prevZ) and am now moving toward (next from statusString)". The client animates the transition between previous and next positions at its own frame rate.
S→C 374 - RoomUsers (entities entering/in room)
Alt: RoomEntities
Delivers the list of all entities (users, bots, pets) currently in the room at load time or as they enter.
Body:
count: int
[count user entries]:
userId: int
username: string
motto: string
look: string Figure string
roomUnitId: int Per-room unit ID (used in all subsequent status msgs)
x: int
y: int
z: string Double as string (e.g. "0.0")
bodyRotation: int 0-7 (N=2, NE=3, E=4, SE=5, S=6, SW=7, W=0, NW=1)
entityType: int 1=user, 2=pet, 4=bot (NOTE: bots use 4, NOT 3)
gender: string "M" or "F"
groupId: int (-1 if no group)
groupRank: int (-1 if no group)
groupName: string (empty if no group)
swimmingFigure: string (empty if not swimming)
achievementScore: int
Bot-specific extra fields (only appended when
entityType == 4): AfterisModerator, bots have additional fields serialized byRoomUsers:ownerId: int Account ID of the bot's ownerownerName: string Username of the bot's ownerskills: int Always 10 (count of skills shorts that follow)[10 shorts] Skill slots 0-9 (short values, always 0–9)
S→C 1640 - RoomUserStatus
Pushes position, rotation, and status-string updates for one or more room units (movement, sitting, waving, etc.).
Body:
count: int
[count entries]:
roomUnitId: int
x: int Previous X
y: int Previous Y
z: string Previous Z as string
headRotation: int 0-7
bodyRotation: int 0-7
Status keys used in statusString:
| Key | Value | Meaning |
|---|---|---|
mv | x,y,z | Moving to position |
sit | height | Sitting (height as double string) |
lay | height | Lying down |
wave | 1 | Waving |
carry | itemId | Carrying an item |
use | itemId | Using an item |
sign | signId | Showing a sign (0-17) |
swim | 1 | Swimming |
trd | 1 | In a trade |
dead | 1 | Dead (BattleBanzai) |
flatctrl | level | Has room rights (level 1-4) |
S→C 2661 - RoomUserRemove
Alt: RoomUserLeave
Notifies the client that a specific room unit (user, bot, or pet) has left the room.
Body: (empty)
S→C 339 - RoomOwner
Nitro:
ROOM_RIGHTS_OWNERSource:RoomOwnerComposer,RoomOwnerEvent
Body: (empty)
Note: RoomOwner sends no fields. Receiving this packet signals that the receiving
client is the room owner. The same information is also conveyed by the isOwner:boolean
field in S→C 749 RoomPane; RoomOwner (339) is the older companion signal sent
Signals to the client that the current user is the room owner. Carries no fields; ownership is implicit from receipt.