Commit Graph

523 Commits

Author SHA1 Message Date
github-actions[bot] 55b38e7b85 🆙 Bump version to 4.2.21 [skip ci] v4.2.21 2026-05-27 13:39:01 +00:00
DuckieTM 4a96c5baaf Merge pull request #128 from duckietm/dev
Dev
2026-05-27 15:37:57 +02:00
duckietm 539c5b5b96 🆙 Fix BOTS in catalog and inventory 2026-05-27 13:46:17 +02:00
duckietm 7b7154e68f 🆙 Fix search and buy #1 2026-05-27 11:34:55 +02:00
duckietm 4aabb738a3 🆙 Added missing Table for the HK 2026-05-27 09:47:30 +02:00
github-actions[bot] 691dc42627 🆙 Bump version to 4.2.20 [skip ci] v4.2.20 2026-05-27 07:43:14 +00:00
DuckieTM 226873c1fb Merge pull request #127 from duckietm/dev
Dev
2026-05-27 09:42:21 +02:00
duckietm a06a204b39 Merge branch 'dev' of https://github.com/duckietm/Arcturus-Morningstar-Extended into dev 2026-05-27 09:37:51 +02:00
duckietm e213609609 🆕 Added Pickup furni to the floorplan 2026-05-27 09:37:49 +02:00
DuckieTM 44d38b8661 🆙 SQL update 2026-05-26 22:18:02 +02:00
github-actions[bot] ccadb81970 🆙 Bump version to 4.2.19 [skip ci] v4.2.19 2026-05-26 15:16:04 +00:00
DuckieTM 0a3a940946 Merge pull request #125 from duckietm/dev
🆙 Small fix floorplan
2026-05-26 17:15:07 +02:00
duckietm 4613fbe80c 🆙 Small fix floorplan 2026-05-26 17:14:49 +02:00
github-actions[bot] 9328f4a355 🆙 Bump version to 4.2.18 [skip ci] v4.2.18 2026-05-26 14:37:17 +00:00
DuckieTM da8b947ddf Merge pull request #124 from duckietm/dev
🆕 Brand new Floorplan
2026-05-26 16:36:17 +02:00
duckietm b9658d0407 🆕 Brand new Floorplan 2026-05-26 16:35:58 +02:00
DuckieTM 68d3731393 Merge pull request #123 from duckietm/dev
Dev
2026-05-26 12:53:07 +02:00
duckietm 4ef4ed1a96 🆙 Enable HK in client with permissions 2026-05-26 12:52:49 +02:00
DuckieTM c20e273a2c Merge pull request #120 from simoleo89/feat/housekeeping-packets
feat(housekeeping): in-client admin packet handlers
2026-05-26 10:44:13 +02:00
github-actions[bot] 83d418e712 🆙 Bump version to 4.2.17 [skip ci] v4.2.17 2026-05-26 08:04:04 +00:00
DuckieTM 38d05e8a06 Merge pull request #122 from duckietm/dev
Dev
2026-05-26 10:03:05 +02:00
duckietm c83a3bad8e 🆙 Gift Updates 2026-05-26 09:58:22 +02:00
DuckieTM 0bd23ad244 Merge pull request #121 from Lorenzune/merge-duckie-main-2026-05-06
Improve emulator monitoring and wired stability safeguards
2026-05-25 18:41:50 +02:00
Lorenzune d8f74b2477 Improve emulator monitoring and wired stability safeguards 2026-05-25 10:10:57 +02:00
simoleo89 dac09e92d1 fix(housekeeping): hash reset password with BCrypt, not SHA-256
`HousekeepingResetUserPasswordEvent` was writing a SHA-256 hex digest
into `users.password`, but the Nitro auth path
(`SessionEndpoints` / `AccountChangeEndpoints` → `AuthHttpUtil.checkPassword`)
only does `BCrypt.checkpw`. A SHA-256 hex string doesn't start with
`$2…$`, so jbcrypt throws `IllegalArgumentException`, `checkPassword`
returns false, and operators saw "credenziali invalide" on every
account whose password had been reset from the in-client panel.

Switch to `BCrypt.hashpw(plain, BCrypt.gensalt(10))` — same idiom
already used by `SessionEndpoints.java:351` and
`AccountChangeEndpoints.java:98`. Cost 10 (vs 12 there) is fine for a
server-generated 12-char random password: gensalt(10) keeps the
operator-facing reset snappy and the output is identical-shape
(`$2a$…`) to what jbcrypt 0.4 already accepts.

Side-effects:
- drops the `MessageDigest` / `NoSuchAlgorithmException` /
  `StandardCharsets` imports and the local `sha256Hex` helper
- repurposes the existing `housekeeping.error.hash_failed` key for
  `BCrypt.gensalt`'s only failure mode (invalid cost / log_rounds out
  of range) so the client error surface is unchanged
- updates the file javadoc to stop telling future readers to "swap the
  MessageDigest constant" — Arcturus itself only verifies BCrypt

Companion of duckietm/Nitro-V3#157 (`feat/housekeeping-panel`). The
client/UI is untouched — packet 9200, the action-result reveal card,
the copy button, and the plaintext flow through `message` are all
unchanged.
2026-05-24 22:25:16 +02:00
simoleo89 fbf979419e feat(housekeeping): hotel alert + dashboard + audit log
Closes out the HK panel server-side surface.

* Incoming 9127 HousekeepingSendHotelAlertEvent — broadcast a
  StaffAlertWithLinkComposer to every online user that hasn't
  set blockStaffAlerts. Composed once, fanned out by reference;
  empty-message guard returns `housekeeping.error.alert_empty`.

* Outgoing 9206 HousekeepingDashboardComposer + Incoming 9128
  HousekeepingGetDashboardEvent — single round trip with the
  aggregated counters: online / total users + active / total
  rooms + pending support tickets + sanctions in the last 24h +
  approximate emulator uptime + a version string. Active-rooms
  is derived from RoomManager.getActiveRooms().getUserCount()>0
  to avoid counting idle preloaded rooms. Peak online today /
  all-time aren't tracked yet, so they currently echo the live
  online count as a best-effort placeholder.

* Outgoing 9207 HousekeepingActionLogComposer + Incoming 9129
  HousekeepingListActionLogEvent — read the optional
  housekeeping_log table. If the table isn't there the SQL
  exception is swallowed and an empty list goes back, so the
  panel renders a no-entries view rather than crashing. Schema
  is documented in the handler's javadoc; operators who want
  audit run a single CREATE TABLE then the HK panel populates
  from new writes (writes are a follow-up — every HK handler
  will eventually append a row).

`mvn package` clean — the final fat jar lands in
Latest_Compiled_Version/ after the build finishes.
2026-05-24 16:31:01 +02:00
simoleo89 6126c35779 feat(housekeeping): economy domain — credits/currency/items/hc
* Incoming 9117 HousekeepingGiveCreditsEvent — Habbo.giveCredits for
  online (ships UserCreditsComposer) or UPDATE users.credits for offline.

* Incoming 9118 HousekeepingGiveCurrencyEvent — generic across the
  non-credits currencies. currencyType 0 => duckets/pixels (givePixels),
  5 => diamonds (givePoints(5,n)), anything else routes through
  givePoints(type,n). Offline path INSERT ... ON DUPLICATE KEY UPDATE
  users_currency.

* Incoming 9119 HousekeepingGrantItemEvent — batch-INSERT N rows into
  the items table with item_id = base furni id. Capped at 100 per call
  so a typo can't bury the DB. Online inventory refresh deferred — the
  user picks the new items up on next hand-inventory open or relog.

* Incoming 9120 HousekeepingSetHcSubscriptionEvent — extends
  users_settings.club_expire_timestamp by `days*86400`. Stacks on top
  of the existing expiry if it's still in the future, otherwise starts
  from now. days==0 clamps to now (effective cancel).

All four reuse HousekeepingActionResultComposer (no new outgoing
composer this slice).

`mvn compile` clean.
2026-05-24 16:29:55 +02:00
simoleo89 a1749c9eda feat(housekeeping): rooms domain — find/search + open/close/mute/kick-all/transfer/delete
Eight new incoming handlers + two new outgoing composers cover the
full rooms-domain HK panel.

* Outgoing 9202 HousekeepingRoomDetailComposer — single room with a
  leading `found` boolean. Writes the IHousekeepingRoom shape via a
  static `appendRoomFields` that HousekeepingRoomListComposer shares.

* Outgoing 9203 HousekeepingRoomListComposer — `count` then N rooms.
  Used for both find-by-name (exact match, up to 50) and the prefix
  autocomplete dropdown (up to 8).

* Incoming 9110 HousekeepingFindRoomByIdEvent — loadRoom(id, false)
  covers both the in-memory cache and the offline `SELECT * FROM rooms`
  path. No `loadData` so HK doesn't pull furni/bots/pets just to
  render a summary.

* Incoming 9111 HousekeepingSearchRoomsEvent — (query, exactMatch,
  limit). Branches between `name = ?` and `name LIKE ?` so the same
  wire packet serves both the autocomplete and the exact-find flows.
  Hard-capped to 50.

* Incoming 9112 HousekeepingRoomStateEvent — (roomId, open). Toggles
  Room.setState(OPEN | LOCKED) and persists via Room.save(). One
  packet covers both the open and close API endpoints.

* Incoming 9113 HousekeepingMuteRoomEvent — (roomId, minutes). Room.
  setMuted is a boolean, so minutes==0 unmutes and minutes>0 mutes.
  A scheduled auto-unmute is left for a future slice; the wire field
  is reserved.

* Incoming 9114 HousekeepingKickAllFromRoomEvent — Room.ejectAll().

* Incoming 9115 HousekeepingTransferRoomOwnershipEvent — UPDATEs both
  rooms.owner_id and rooms.owner_name so the navigator cached name
  doesn't go stale. Validates the new owner exists via
  HabboManager.getHabboInfo before touching the row.

* Incoming 9116 HousekeepingDeleteRoomEvent — ejectAll + dispose +
  uncacheRoom + DELETE FROM rooms, mirroring the minimum-viable
  subset of RequestDeleteRoomEvent. Pets/guild/custom-layout cleanup
  is skipped on this slice (orphans don't crash the emulator).

`mvn compile` clean.
2026-05-24 16:29:55 +02:00
simoleo89 525c124fa5 feat(housekeeping): set-rank + trade-lock + reset-password
Closes out the users-domain HK actions.

* Incoming 9107 HousekeepingSetUserRankEvent — (userId, rankId).
  Validates the rank exists in `permission_ranks`, UPDATEs users.rank,
  and if the target is online rebinds their HabboInfo to the fresh
  Rank object and ships a UserPermissionsComposer so server-side
  hasPermission() and the client's useHasPermission(key) consumers
  re-render against the new permissions without a relog.

* Incoming 9108 HousekeepingTradeLockUserEvent — (userId, hours,
  reason). Writes `users_settings.trade_locked_until = now + hours*3600`
  so the lock survives logout/login. Online targets also get their
  in-memory HabboStats.allowTrade cleared and an optional alert.

* Incoming 9109 HousekeepingResetUserPasswordEvent — (userId).
  Generates a 12-char alphanumeric (SecureRandom over a curated
  ambiguity-free alphabet), writes its SHA-256 hex to users.password
  (the column is varchar(64) — already sized for SHA-256 hex) and
  blanks auth_ticket so any live SSO ticket can't bypass the reset.
  Plaintext is returned to the operator in the action-result
  message — they relay it out-of-band. If your CMS uses a hash other
  than SHA-256, swap the MessageDigest.getInstance constant.

`mvn compile` clean.
2026-05-24 16:29:55 +02:00
simoleo89 57087a31f2 fix(housekeeping): emit localizable error keys instead of bare slugs
Every HK action handler returned bare error slugs (\"invalid_input\",
\"user_offline\", \"no_active_ban\", \"target_unkickable\", \"ban_failed\",
\"user_not_found\") in HousekeepingActionResultComposer.message. The
client's `localizeOrPassthrough` only treats a value as a translation
key when it contains a dot, so those bare slugs were rendered raw in
the status banner and the toast — ugly and untranslatable.

Re-prefix all error messages with `housekeeping.error.` so the EN +
IT dictionaries can resolve them. Success path is unchanged (server
sends empty string, client falls back to `housekeeping.action.success`).

Companion dictionary entries land on the client side.
2026-05-24 16:29:55 +02:00
simoleo89 c4b3295a45 feat(housekeeping): force-disconnect-user packet
Incoming 9106 HousekeepingForceDisconnectUserEvent — (userId, reason).
Sends the optional reason as a Habbo.alert, dispatches the action ack
BEFORE calling target.disconnect() so the result lands on the wire
before the target's socket closes, then drops the session. Online-only;
offline target returns `user_offline`.

`mvn compile` clean.
2026-05-24 16:29:54 +02:00
simoleo89 418c753e6c feat(housekeeping): mute-user + kick-user packets
Incoming 9104 HousekeepingMuteUserEvent — (userId, reason, minutes).
Unlike ModToolSanctionMute which takes a fixed-bucket minutes arg
from a CFH context, this one applies an arbitrary in-session mute via
Habbo.mute(seconds, false). Mute is online-only (the live Habbo object
holds the remaining seconds), so an offline target returns ok=false
with `user_offline`. The reason string, if non-empty, is delivered via
Habbo.alert so the muted user sees why.

Incoming 9105 HousekeepingKickUserEvent — (userId, reason). Replicates
the ModToolManager.kick body (leave room + alert) locally so HK doesn't
piggyback on ACC_SUPPORTTOOL the way ModToolManager.kick does — keeps
the permission model `acc_housekeeping`-only. Respects ACC_UNKICKABLE
the same way the legacy path does.

Both reuse HousekeepingActionResultComposer with their own actionKey
(user.mute / user.kick).

`mvn compile` clean.
2026-05-24 16:29:54 +02:00
simoleo89 8419f11883 feat(housekeeping): unban-user packet
Incoming 9103 HousekeepingUnbanUserEvent — reads userId, resolves
the username via HabboManager.getHabboInfo(int) (covers both online
and offline paths in one call), then dispatches to
ModToolManager.unban(username) which clears all active rows from
the `bans` table for that user.

Reuses HousekeepingActionResultComposer with actionKey `user.unban`.
If the user never had an active ban the SQL UPDATE matches zero rows
and the handler responds with `ok: false, message: 'no_active_ban'`
— from a UI standpoint that's a no-op, not an error.

`mvn compile` clean.
2026-05-24 16:29:54 +02:00
simoleo89 1a0d783ff7 feat(housekeeping): ban-user with arbitrary duration + ack composer
Adds two new packets:

* Incoming 9102 HousekeepingBanUserEvent — reads (userId, reason,
  hours). Unlike ModToolSanctionBanEvent which only accepts the four
  fixed Habbo-protocol banType buckets (18h / 7d / 30d / 100y), this
  one converts the hours arg straight to seconds and feeds them into
  ModToolManager.ban with ModToolBanType.ACCOUNT and cfhTopic=0.
  Duration is clamped to 100 years to keep it inside `int` range.

* Outgoing 9201 HousekeepingActionResultComposer — generic ack
  for any HK action (ban / mute / kick / give-credits / room-close /
  …). Wire shape is (actionKey, ok, actionId, message). The
  actionKey lets the client filter multiple in-flight actions to
  the right Promise via `accept`, so concurrent admin operations
  don't cross-resolve.

actionId here is the target user id because ModToolBan doesn't
expose the `bans` autoinc id on the object — there's a TODO to swap
this for a dedicated housekeeping_log row id once that table goes in.

Same ACC_HOUSEKEEPING permission gate as the find-user packets, so
operators only need to grant the permission once.

`mvn compile` clean.
2026-05-24 16:29:54 +02:00
simoleo89 655e039df7 feat(housekeeping): find-user-by-id packet + acc_housekeeping gate
Adds Incoming 9101 HousekeepingFindUserByIdEvent, which replies on
the existing HousekeepingUserDetailComposer (Outgoing 9200) — the
composer is shape-agnostic about how the lookup was issued, so the
two find-* handlers share the same response packet.

The by-id handler uses HabboManager.getHabboInfo(int) directly, which
already covers both the online (in-memory hashmap) and offline (SQL
LIMIT 1 on users) branches in one call. The by-name path still has
to do online + offline manually because the equivalent String overload
doesn't exist as an instance method, only as a static.

Also introduces Permission.ACC_HOUSEKEEPING ("acc_housekeeping") so
the in-client housekeeping panel doesn't piggyback on ACC_SUPPORTTOOL.
Both HK handlers now gate on the new permission; the toolbar UI on
the client side was already checking `acc_housekeeping`, so this
closes the loop. Operators must add the permission to
permission_definitions for the desired rank:

  INSERT INTO permission_definitions
    (permission_key, max_value, comment,
     rank_1, rank_2, rank_3, rank_4, rank_5, rank_6, rank_7)
  VALUES
    ('acc_housekeeping', 1,
     'Allows access to the in-client Housekeeping admin panel ...',
     0, 0, 0, 0, 0, 0, 1)
  ON DUPLICATE KEY UPDATE rank_7 = 1, comment = VALUES(comment);

`mvn package` clean (Habbo-4.2.12-jar-with-dependencies.jar).
2026-05-24 16:29:54 +02:00
simoleo89 7726691cde feat(housekeeping): add find-user-by-name packet pair
First wire-level packet for the in-client housekeeping admin panel.
Adds an incoming handler (Incoming 9100) that resolves a username to
a HabboInfo (online via the HabboManager hashmap, offline via the
users-table SQL fallback) and replies with HousekeepingUserDetail
(Outgoing 9200) containing id / username / motto / look / rank / rank
name / online / lastOnline / credits / duckets / diamonds / email /
ipLogin / isBanned. Active-mute and active-trade-lock are written as
trailing booleans (currently false) so the renderer parser can pick
them up later behind a bytesAvailable guard once those manager APIs
are surfaced offline-side.

Permission gate is ACC_SUPPORTTOOL — same one ModTools already uses.
Avoids adding a new column to the permissions table on this slice; a
dedicated ACC_HOUSEKEEPING permission can be introduced later when
the destructive HK operations (give-credits, delete-room, reset-pwd)
go in.

Reserves the 9100..9199 / 9200..9299 ID blocks for the rest of the
HK packet surface (search-prefix, find-by-id, ban/mute/kick with
arbitrary duration, room actions, economy, catalog admin, dashboard
aggregate, audit log read).

`mvn compile` clean on Habbo 4.2.12.
2026-05-24 16:29:54 +02:00
github-actions[bot] 67503aeb2a 🆙 Bump version to 4.2.16 [skip ci] v4.2.16 2026-05-22 09:04:30 +00:00
DuckieTM b206b32748 Merge pull request #119 from duckietm/dev
🆙 Catalog Editor, now you can also edit the text1
2026-05-22 11:03:35 +02:00
duckietm ad60861a3f 🆙 Catalog Editor, now you can also edit the text1 2026-05-22 11:03:17 +02:00
github-actions[bot] b77290f5e7 🆙 Bump version to 4.2.15 [skip ci] v4.2.15 2026-05-21 15:03:23 +00:00
DuckieTM b14730d37f Merge pull request #118 from duckietm/dev
Dev
2026-05-21 17:02:19 +02:00
duckietm 9126396973 🆙 Fix Catalog Edit 2026-05-21 17:01:56 +02:00
duckietm d321ff3b85 Update 003_live_required_schema.sql 2026-05-21 15:54:10 +02:00
duckietm 7f38a25eef 🆙 Small SQL update 2026-05-21 15:44:30 +02:00
github-actions[bot] 4820ab15f3 🆙 Bump version to 4.2.14 [skip ci] v4.2.14 2026-05-21 12:03:07 +00:00
DuckieTM 8d989e7a19 Merge pull request #117 from duckietm/dev
🆕 Redesign of HC Club buy, now also give as gift
2026-05-21 14:02:14 +02:00
duckietm 1f7ec96e1c 🆕 Redesign of HC Club buy, now also give as gift 2026-05-21 14:01:57 +02:00
github-actions[bot] 969f177108 🆙 Bump version to 4.2.13 [skip ci] v4.2.13 2026-05-21 07:02:08 +00:00
DuckieTM e485c2747c Merge pull request #116 from duckietm/dev
Dev
2026-05-21 09:01:07 +02:00
DuckieTM d99a51899b Merge pull request #115 from simoleo89/fix/modtool-counter-bumps
fix(modtool): bump users_settings counters on every sanction
2026-05-21 07:40:49 +02:00