Commit Graph

255 Commits

Author SHA1 Message Date
simoleo89 7da07aa1d5 feat(furni-editor): add sortField/sortDir to search composer
Append optional sort field + direction to FurniEditorSearchComposer so
the server can order the full result set (not just the visible page).
Defaults id/asc keep existing callers working.
2026-06-06 15:08:46 +02:00
simoleo89 751da35ce4 fix(furnieditor): register furnidata update/revert composers (was Unknown Composer) 2026-06-06 13:07:53 +02:00
simoleo89 4f3e2b7ce7 feat(furnieditor): outgoing composers for furnidata update (10046) + revert (10048) 2026-06-06 02:42:17 +02:00
simoleo89 beea0a2c61 Merge remote-tracking branch 'fork/main'
# Conflicts:
#	packages/communication/src/NitroMessages.ts
2026-06-06 00:21:11 +02:00
simoleo89 334e8e07be Merge branch 'feat/furni-names-from-json-server'
# Conflicts:
#	packages/communication/src/NitroMessages.ts
2026-06-05 23:35:10 +02:00
DuckieTM 6a7443b602 🆙 mask filter 2026-06-05 21:01:54 +02:00
duckietm 746e2c8289 🆙 Small alphablend fix 2026-06-05 17:22:48 +02:00
duckietm 20f6af232e 🆙 Update to Pixi.js 8.19.0 and alphablend is now fixed 2026-06-05 16:30:22 +02:00
duckietm d61a07e1e7 🆙 Fix the Admin Catalogue stuff 2026-06-05 14:25:47 +02:00
simoleo89 1d6c102fd6 feat(session): apply FurnitureDataReload delta + reload-hint (separate path) 2026-06-04 22:01:08 +02:00
simoleo89 dbd398ae80 feat(communication): route FURNITURE_DATA_RELOAD to its event 2026-06-04 21:54:43 +02:00
simoleo89 17957e7f54 feat(communication): FurnitureDataReload incoming event + parser (header 10047) 2026-06-04 21:50:34 +02:00
duckietm becf654c9e 🆙 Updates Mention 2026-06-04 10:42:10 +02:00
medievalshell e83468563d feat(session): live furnidata reload via mergeFurnitureDataFromUrl
Add SessionDataManager.mergeFurnitureDataFromUrl() + FurnitureDataLoader.mergeFromUrl()
to merge a single furnidata chunk (e.g. a custom tier) into the live floor/wall maps at
runtime, returning the added entries so callers can also refresh the RoomContentLoader.
Lets newly added furniture appear without a full client reload.
2026-06-03 23:36:07 +02:00
DuckieTM 6c07cf8677 Merge pull request #86 from simoleo89/feat/mentions-packets
feat(mentions): mention packets (received / list / request / mark-read / delete)
2026-06-03 09:48:56 +02:00
duckietm 90f2fa5fd8 🆙 Updated Prefixes 2026-06-03 09:39:53 +02:00
simoleo89 cf81ca6689 feat(messenger): typing packets (ConsoleTyping + FriendTyping) 2026-06-02 20:57:38 +02:00
simoleo89 9a678b04fb feat(messenger): read-receipt packets (MarkConsoleRead + ConsoleReadReceipt) 2026-06-02 20:03:32 +02:00
simoleo89 4774eeeae9 feat(messenger): add friend-category client composers (add/rename/remove/move) 2026-06-02 17:30:30 +02:00
simoleo89 6701b8bf50 feat(mentions): add DeleteMention composer (header 4805) 2026-06-02 14:44:15 +02:00
simoleo89 2b32ffa990 feat(mentions): add MentionReceived/MentionsList packets + parsers and composers 2026-05-31 21:38:46 +02:00
medievalshell c3b15f02bf perf(gamedata): manifest ext by JSON mode, no double-probe
tryFetchManifestPair sceglie l'estensione in base a resolveJsonMode():
json5 -> .json5, legacy -> .json, auto -> entrambi. Evita le richieste
manifest.json fallite a ogni avvio in modalita json5.
2026-05-30 00:14:44 +02:00
medievalshell b127501c52 fix: restore room-background Z transparency after branding offsetZ change
FurnitureBrandedImageVisualization now adds offsetZ to the branded layer (z-index for the MPU/billboard editor). The room background uses offsetZ as an inverse depth push (the 'play with Z to hide floor/walls' trick); its getLayerZOffset subtracted offsetZ assuming the parent did not add it, so the two cancelled out and the effect was lost. Cancel the parent's +offsetZ for the branded layer to restore the original net (base - offsetZ).
2026-05-29 00:45:05 +02:00
medievalshell 9ece87240e feat: branding furni image position + scale (MPU background editor)
Renderer support for the in-client image position editor:
- FurnitureBrandedImageVisualization applies offsetX/Y to the branded image
  layer only (offsetZ stays as z-index/depth), so the image can be moved
  without shifting the furni frame
- new `scale` branding key + FURNITURE_BRANDING_SCALE: zooms the image via a
  real per-sprite scale (RoomObjectSprite.scale, default 1, applied in
  RoomSpriteCanvas) — NOT by writing the read-only width/height
- AssetManager loads external raster images (png/jpg/…) via a CORS <img> +
  Texture.from instead of Assets.load (which didn't load cross-origin images);
  branding image download failures are now surfaced instead of swallowed
2026-05-28 15:29:42 +02:00
medievalshell 238592cd72 feat: soundboard packets
Add the soundboard message protocol mirroring the Arcturus side:
- incoming SoundboardSettings (enabled flag + sound list) and
  SoundboardPlay (soundId, url, username) events + parsers
- outgoing SoundboardPlay (soundId) and SoundboardSetEnabled composers
- header ids 9405/9406 (incoming), 9306/9307 (outgoing)
- NitroMessages registration + barrel exports
2026-05-28 09:02:57 +02:00
medievalshell 87eec0563d feat: rare values + fortune wheel protocol + prize editor
Composers/parsers/events for rare values + wheel (open/spin/buy/data/result/
recent-wins) + admin (get/save prizes), headers 9300-9305 / 9400-9404.
fix: figure map uses split-aware loadGamedata (raw fetch broke on tier-manifest
gamedata, silently empty avatars).
2026-05-28 02:39:01 +02:00
duckietm b7688f9d2b 🆕 Added Pickup furni to the floorplan 2026-05-27 09:41:18 +02:00
DuckieTM 72c9564488 Merge pull request #78 from simoleo89/pr/floor-editor-live-preview
feat(room): RoomMessageHandler.applyFloorModelLocally for live floor-plan editor preview
2026-05-26 13:21:56 +02:00
DuckieTM 0a6afd1742 Merge pull request #77 from simoleo89/feat/housekeeping-packets
feat(communication): Housekeeping in-client admin packet surface
2026-05-26 10:50:13 +02:00
DuckieTM 4ddd4bb93d Merge branch 'Dev' into merge-duckie-main-2026-05-06 2026-05-25 18:48:34 +02:00
Lorenzune 22a6d0b3d2 Add total badge count to user profile parser 2026-05-25 10:55:26 +02:00
simoleo89 2504aea85f fix(room): guard RoomPreviewer.updatePreviewModel against null _planeParser
After dispose() nulls out the internal _planeParser /
_backgroundSprite refs, any further updatePreviewModel call
crashed with 'this._planeParser is null'. React 19 StrictMode
in dev double-mounts effects (setup, cleanup, setup again),
which can briefly leave a consumer holding a stale reference
to a disposed previewer between the two setup runs. Bail
silently in that window instead of crashing the editor.
2026-05-24 21:14:53 +02:00
simoleo89 28a41ba543 fix(room): applyFloorModelLocally also rebuilds the furniture stacking map
The first cut updated wallGeometry + RoomMapData (so the
visualization rebuilt) but NOT the FurnitureStackingHeightMap.
The stacking map is what governs whether the room treats a
tile as 'a room tile you can stack furni on' vs. 'blocked'.
Without rebuilding it, every newly-painted tile in the live
preview looks walkable but rejects furniture placement -
user reported exactly that.

Mirror the structure of onRoomHeightMapEvent: build a fresh
FurnitureStackingHeightMap from the parsed floor (height +
isRoomTile from FloorHeightMapMessageParser.TILE_BLOCKED),
default stackingBlocked=false, then setFurnitureStackingHeightMap
+ refreshTileObjectMap so the room object map picks up the
new tile set.
2026-05-24 21:14:52 +02:00
simoleo89 afd0a4fa16 feat(room): RoomMessageHandler.applyFloorModelLocally for live floor preview
Adds a public method that rebuilds the active room's floor
geometry from an in-memory model string + wallHeight without
touching the server. Same pipeline as the wire-driven
onRoomModelEvent (FloorHeightMapMessageParser ->
_planeParser -> wallGeometry), but instead of going through
RoomEngine.createRoomInstance (which is a no-op on a room
that already exists) it routes the resulting RoomMapData
through the room object's ObjectRoomMapUpdateMessage channel
- the same mechanism RoomPreviewer.updateRoomPlanes uses for
its iso preview. Result: the visualization rebuilds in place
and existing furniture/avatars are preserved.

Refactor: extracted the parser->planeParser->wallGeometry-
>RoomMapData work from onRoomModelEvent into a private
_rebuildFloorGeometry(parser) helper so the wire handler and
the new public method share an implementation.

Intended use: tools that need a live in-room preview of a
floor edit before committing it server-side (e.g. the React
floor-plan editor's live-preview mode). The wire
UpdateFloorPropertiesMessageComposer remains the source of
truth - call applyFloorModelLocally only for transient
client-side preview.
2026-05-24 21:14:52 +02:00
simoleo89 5dd5b26bbe feat(communication): housekeeping hotel alert + dashboard + audit log
Outgoing 9127-9129: send-hotel-alert (message string), get-dashboard
(no args), list-action-log (limit int).

Incoming 9206 HousekeepingDashboardEvent + 9207 ActionLogEvent with
matching parsers and data classes. Dashboard is a flat one-shot
parse — no count prefix; action log uses the standard "count + N
entries" list pattern.

Closes the HK packet surface — yarn compile:fast clean.
2026-05-24 16:28:52 +02:00
simoleo89 386bf79ddc feat(communication): housekeeping economy — 4 composers
OutgoingHeader 9117-9120: give-credits, give-currency (generic across
duckets/diamonds/seasonal via a currencyType int), grant-item,
set-hc-subscription. All four ride the existing
HousekeepingActionResultEvent — no new parser needed.

`yarn compile:fast` clean.
2026-05-24 16:26:07 +02:00
simoleo89 597cd2402f feat(communication): housekeeping rooms domain — 7 composers + 2 events
* Outgoing 9110-9116: find-room-by-id, search-rooms (exact|prefix),
  room-state (open|close toggle), mute-room, kick-all-from-room,
  transfer-room-ownership, delete-room.

* Incoming 9202 HousekeepingRoomDetailEvent + 9203 RoomListEvent.

* HousekeepingRoomData parser data class with the 11 IHousekeepingRoom
  fields. Single-room and list events share the same data class via
  composition.

`yarn compile:fast` clean.
2026-05-24 16:26:07 +02:00
simoleo89 c6c6cfe04b feat(communication): housekeeping set-rank + trade-lock + reset-password composers
Three composers closing out the users-domain HK actions:
* OutgoingHeader 9107 HousekeepingSetUserRankComposer (userId, rankId)
* OutgoingHeader 9108 HousekeepingTradeLockUserComposer (userId, hours, reason)
* OutgoingHeader 9109 HousekeepingResetUserPasswordComposer (userId)

All three ride the existing HousekeepingActionResultEvent for the ack.
2026-05-24 16:26:07 +02:00
simoleo89 fbe8a02a72 feat(communication): housekeeping force-disconnect-user composer
OutgoingHeader 9106 HousekeepingForceDisconnectUserComposer carrying
(userId, reason). Reuses HousekeepingActionResultEvent for the ack.
2026-05-24 16:26:06 +02:00
simoleo89 370b1fc100 feat(communication): housekeeping mute-user + kick-user composers
OutgoingHeader 9104 HousekeepingMuteUserComposer — (userId, reason,
minutes). 9105 HousekeepingKickUserComposer — (userId, reason). Both
ride the existing HousekeepingActionResultEvent for the ack, so no
new parser is needed.

vitest 138/138, `yarn compile:fast` clean.
2026-05-24 16:26:06 +02:00
simoleo89 c9d8f32e62 feat(communication): housekeeping unban-user composer
HousekeepingUnbanUserComposer (OutgoingHeader 9103) carrying a single
userId int. Response side reuses HousekeepingActionResultEvent — no
new parser needed because the ack shape is action-agnostic.

`yarn compile:fast` clean.
2026-05-24 16:26:06 +02:00
simoleo89 31598b8883 feat(communication): housekeeping ban-user + generic action-result
* HousekeepingBanUserComposer (OutgoingHeader 9102): (userId,
  reason, hours).

* HousekeepingActionResultEvent + Parser (IncomingHeader 9201):
  generic ack carrying (actionKey, ok, actionId, message). Same
  parser will back mute / kick / give-credits / room-close / etc.
  callers — adding a new HK action only needs a new outgoing
  composer plus the right ACTION_KEY constant on the server side.

vitest 138/138, `yarn compile:fast` clean.
2026-05-24 16:26:06 +02:00
simoleo89 3113baf559 feat(communication): housekeeping find-user-by-id composer
OutgoingHeader.HOUSEKEEPING_FIND_USER_BY_ID = 9101 with a one-int
payload. The response side reuses HousekeepingUserDetailEvent (no new
parser) — find-by-id and find-by-name converge on the same shape
because the server has nothing different to say about a user found
via numeric id vs. via username lookup.

vitest 138/138, `yarn compile:fast` clean.
2026-05-24 16:26:06 +02:00
simoleo89 ec7e122e74 feat(communication): add housekeeping find-user-by-name packet pair
TS counterparts to Arcturus' new HK packet pair. Adds
HousekeepingFindUserByNameComposer (OutgoingHeader 9100) and
HousekeepingUserDetailEvent (IncomingHeader 9200) with a parser that
wraps an optional HousekeepingUserDetailData. The data class follows
the flat optional-trailing-field pattern (isMuted / isTradeLocked
read under bytesAvailable guards) so the renderer stays compatible
with a server that hasn't surfaced those manager APIs offline yet.

The parser exposes `found: boolean` and `user: HousekeepingUserDetailData | null`
so a callsite that gets a "user not found" reply can branch without
having to read into an unpopulated data object — the composer writes
`appendBoolean(false)` and stops, the parser sees the false and leaves
`user` null.

Headers 9100..9199 / 9200..9299 reserved for the rest of the HK
packet surface. Composer + event registered in NitroMessages alongside
the existing YouTube-room overrides. `yarn compile:fast` clean, vitest
138/138 green.
2026-05-24 16:26:06 +02:00
duckietm 081e06b208 🆙 Catalog Editor, now you can also edit the text1 2026-05-22 11:05:45 +02:00
duckietm bdbb8e7161 🆙 Fix Catalog Edit 2026-05-21 16:59:36 +02:00
duckietm c15b606a4d 🌲 Bump to Version 3.5.0 2026-05-20 11:43:54 +02:00
simoleo89 1bad1b20ca 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.
2026-05-19 21:48:02 +02:00
simoleo89 05ea0db806 fix(parser): drop unsafe borderId read inside the RoomUnitParser per-user loop
The Infostand Borders merge (origin/Dev 4b7d04d, upstream commit) added

    user.borderId = (wrapper.bytesAvailable ? wrapper.readInt() : 0);

inside the per-user loop in RoomUnitParser (the parser for the
RoomUsersComposer packet — header 3920 — which ships the full roster
on room enter). The guard is unsafe inside a loop: `bytesAvailable`
is a boolean meaning "any bytes left in the WHOLE packet?", not
"any bytes left in THIS user record". For every user except the
last one, `bytesAvailable === true` because the NEXT user's bytes
still follow, so the parser reads an int and steals 4 bytes from
the next user — cascade corruption of the entire roster.

Symptom in production: users don't see each other on first room
sight. The roster arrives, the parser sfasa, RoomEngine drops the
malformed records.

Fix: stop reading borderId inside the loop. The per-user border id
is shipped separately via RoomUnitInfoParser (single-user packet,
no loop), where the bytesAvailable guard is safe. The roster
packet's last-tail extension story stays clean for any future
trailing block the same way other parsers do — but only when the
guard is the LAST read in the packet, not a per-record one.

This also makes the renderer wire-compatible with both old
emulators (no borderId at all) and the new Arcturus version that
ships borderId in RoomUsersComposer — the latter just has 4 extra
trailing bytes per user that the parser ignores. A follow-up change
on Arcturus' RoomUsersComposer can drop the borderId append, or
keep it and the client simply doesn't read it from the roster
(which is fine — the infostand re-fetch via RoomUnitInfoParser
gives the authoritative border).

mvn-equivalent: yarn compile:fast clean, vitest 138/138.
2026-05-19 21:05:36 +02:00
simoleo89 cc1e8fe9c7 fix(api): align IRoomSession.sendBackgroundMessage signature with the impl
The RoomSession.sendBackgroundMessage impl takes 5 args (background,
stand, overlay, card, border) but the interface only declared 4 —
TypeScript consumers calling roomSession.sendBackgroundMessage(...) with
the border arg failed to typecheck even though the runtime call worked.
Add the optional backgroundBorder?: number trailing parameter to the
interface so the contract matches what RoomSession.ts ships.
2026-05-19 20:38:47 +02:00