You've already forked Nitro_Render_V3
mirror of
https://github.com/duckietm/Nitro_Render_V3.git
synced 2026-06-19 15:06:20 +00:00
fix(parser): restore per-user borderId read in RoomUnitParser
The earlier "drop unsafe borderId read" fix (05ea0db) was based on the
assumption that Arcturus did not append a per-user borderId at the end
of each user record in RoomUsersComposer. That was true at the time —
but the Infostand Borders cherry-pick on the Arcturus side
(8f8f568, "feat: Infostand Borders") then added
`appendInt(getInfostandBorder())` at the end of EVERY user record
(single habbo, habbos collection, single bot=0, bots collection=0).
With the cherry-pick applied and the parser still skipping the read,
each user record left 4 unconsumed bytes on the wire. The NEXT
iteration's `id = wrapper.readInt()` then picked up the previous
user's borderId, the rest of the loop interpreted shifted bytes as
strings/ints, and the entire roster cascaded into corruption —
visible to the user as "I cannot see the other users in the room".
The bytesAvailable guard around this read is intentionally NOT
re-added: `bytesAvailable` is a boolean meaning "any bytes left in
the whole packet?", not "any bytes left for THIS user". With Arcturus
guaranteed to ship a borderId for every record (constant 0 for bots),
the read must be unconditional to stay wire-aligned.
This commit is contained in:
@@ -146,16 +146,17 @@ export class RoomUnitParser implements IMessageParser
|
|||||||
|
|
||||||
user.roomEntryMethod = wrapper.readString();
|
user.roomEntryMethod = wrapper.readString();
|
||||||
user.roomEntryTeleportId = wrapper.readInt();
|
user.roomEntryTeleportId = wrapper.readInt();
|
||||||
// NOTE: do NOT read borderId here. `wrapper.bytesAvailable`
|
// Arcturus appends a trailing borderId int per user
|
||||||
// is a boolean meaning "any bytes left in the whole packet?",
|
// (RoomUsersComposer, after the Infostand Borders feature)
|
||||||
// not "any bytes left in THIS user". For users that aren't
|
// for every record — habbo, bot, rentable bot — using 0 as
|
||||||
// the last in the roster, bytesAvailable === true because
|
// the constant for the records that have no border. The
|
||||||
// the NEXT user's bytes follow — reading an int would steal
|
// read MUST be unconditional: a bytesAvailable guard would
|
||||||
// 4 bytes from the next user and cascade-corrupt the entire
|
// be semantically wrong here (the guard answers "any byte
|
||||||
// roster (users not seeing each other on first sight). The
|
// left in the whole packet?" not "any byte left for THIS
|
||||||
// border id for an individual user arrives via
|
// user"), and skipping the read would leave 4 bytes per
|
||||||
// RoomUnitInfoParser (single-user packet), where the
|
// record and cascade-corrupt every subsequent user in the
|
||||||
// bytesAvailable guard is safe because there is no loop.
|
// roster.
|
||||||
|
user.borderId = wrapper.readInt();
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user