- InteractionGift/OpenRecycleBoxEvent: add an atomic open-once guard so two
near-simultaneous OpenRecycleBox packets can't both schedule the async,
delayed OpenGift before the wrapper is removed (redundant double-process).
- ClientMessage.readString: treat the length prefix as unsigned (mask 0xFFFF)
and clamp to the buffered bytes, so a bogus/oversized length no longer
throws mid-read and desyncs the remaining fields of the packet.
Security
- HousekeepingSetUserRankEvent: add rank-ceiling guard (reject granting a
rank above the operator's own and modifying a higher-ranked target),
mirroring GiveRankCommand — closes a privilege-escalation path.
Trade integrity
- RoomTrade.clearAccepted now also resets confirmed; a stale confirmed=true
let a user strip their side and still complete once the partner re-confirms.
Concurrency
- RoomCycleManager: iterate the synchronized bot/pet maps under their own
monitor (lock order stays one-directional vs addBot/addPet — no deadlock).
- RoomSpecialTypes: synchronize nest/petDrink/petFood/petToy/petTree writers
on the same monitor their getters already use.
- HabboStats: synchronize achievement-progress map accessors.
- RebugKickBallAction: drop redundant direct mutation of the shared tile-cache
sets (updateTile invalidates them right after) — removes a data race.
Robustness
- Wired legacy parsers (HabboCount, NotHabboCount, MatchStatePosition,
MoveRotateFurni): guard length/format so one malformed row no longer aborts
the whole room's wired load.
- RoomLayout: fill malformed/short heightmap rows with INVALID tiles instead
of leaving nulls, and bounds-check door coordinates.
- FurnidataWatcher: defer (instead of drop) a throttled delta so furni-name
changes are never lost between broadcasts.
- GuildManager.getGuildMembers: fix LIMIT row-count (page size 14, not
offset+14) so member pages no longer overlap from page 1 on.
FriendsComposer only serialized a buddy's look when online, sending an
empty string for offline friends. The look is already loaded from the DB
for every friend in Messenger.loadFriends (SELECT users.look), so the
gate just discarded valid data: offline friends rendered with the
anonymous/standard avatar in the friend list and messenger, while their
profile (fetched separately) showed the real figure.
Always serialize row.getLook(). StaffChatBuddy keeps a non-null look
("ADM") so there is no NPE risk, and UpdateFriendComposer already sent
the look unconditionally, so this only aligns the initial friend list.
FurniEditorImportTextEvent (incoming 10049, ACC_CATALOGFURNI): resolves
the classname, fetches the admin-configured furnidata URL via HttpClient
with a TTL cache (furni.editor.import.url / .cache.ms, default habbo.it),
finds name/description by classname and returns them via
FurniEditorImportTextResultComposer (outgoing 10049). URL is DB-configured
only (no client-supplied URL -> no SSRF); serves stale cache on failure.
Read sortField/sortDir from the search packet and ORDER BY a whitelisted
items_base column (id/sprite_id/item_name/public_name/type/interaction_type)
with a stable id tie-break, so sorting orders the whole result set instead
of just the page the client received. Column names come from a fixed
whitelist (never raw input) so the dynamic ORDER BY stays injection-safe.
On a successful furnidata name update (10046), after the JSON write +
10047 broadcast, also UPDATE items_base.public_name to the new
(sanitized) name and refresh the in-memory Item cache via loadItems()
so Item.getFullName() stays consistent without a restart. Guarded by
name != null (description-only edits never blank the column), runs only
on the success path, outside FurnidataLock, with a parameterized
statement.
- resolveHabbo() falls back to a hotel-wide online lookup so a direct @nick
mention reaches the target even when they are in a different room (was
resolved only within the sender's room).
- HabboMention now carries the sender figure (live from the sender Habbo,
history from a users.look JOIN); MentionReceived/MentionsList composers
append it so the client can render the sender avatar in the notification.
- 009: add users_settings.mentions_enabled / mass_mentions_enabled columns
so :disablementions / :disablemassmentions actually persist.