You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 15:06:19 +00:00
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.
This commit is contained in:
@@ -728,5 +728,12 @@ public class PacketManager {
|
|||||||
this.registerHandler(Incoming.HousekeepingSetUserRankEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingSetUserRankEvent.class);
|
this.registerHandler(Incoming.HousekeepingSetUserRankEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingSetUserRankEvent.class);
|
||||||
this.registerHandler(Incoming.HousekeepingTradeLockUserEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingTradeLockUserEvent.class);
|
this.registerHandler(Incoming.HousekeepingTradeLockUserEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingTradeLockUserEvent.class);
|
||||||
this.registerHandler(Incoming.HousekeepingResetUserPasswordEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingResetUserPasswordEvent.class);
|
this.registerHandler(Incoming.HousekeepingResetUserPasswordEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingResetUserPasswordEvent.class);
|
||||||
|
this.registerHandler(Incoming.HousekeepingFindRoomByIdEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingFindRoomByIdEvent.class);
|
||||||
|
this.registerHandler(Incoming.HousekeepingSearchRoomsEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingSearchRoomsEvent.class);
|
||||||
|
this.registerHandler(Incoming.HousekeepingRoomStateEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingRoomStateEvent.class);
|
||||||
|
this.registerHandler(Incoming.HousekeepingMuteRoomEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingMuteRoomEvent.class);
|
||||||
|
this.registerHandler(Incoming.HousekeepingKickAllFromRoomEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingKickAllFromRoomEvent.class);
|
||||||
|
this.registerHandler(Incoming.HousekeepingTransferRoomOwnershipEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingTransferRoomOwnershipEvent.class);
|
||||||
|
this.registerHandler(Incoming.HousekeepingDeleteRoomEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingDeleteRoomEvent.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -472,4 +472,11 @@ public class Incoming {
|
|||||||
public static final int HousekeepingSetUserRankEvent = 9107;
|
public static final int HousekeepingSetUserRankEvent = 9107;
|
||||||
public static final int HousekeepingTradeLockUserEvent = 9108;
|
public static final int HousekeepingTradeLockUserEvent = 9108;
|
||||||
public static final int HousekeepingResetUserPasswordEvent = 9109;
|
public static final int HousekeepingResetUserPasswordEvent = 9109;
|
||||||
|
public static final int HousekeepingFindRoomByIdEvent = 9110;
|
||||||
|
public static final int HousekeepingSearchRoomsEvent = 9111;
|
||||||
|
public static final int HousekeepingRoomStateEvent = 9112;
|
||||||
|
public static final int HousekeepingMuteRoomEvent = 9113;
|
||||||
|
public static final int HousekeepingKickAllFromRoomEvent = 9114;
|
||||||
|
public static final int HousekeepingTransferRoomOwnershipEvent = 9115;
|
||||||
|
public static final int HousekeepingDeleteRoomEvent = 9116;
|
||||||
}
|
}
|
||||||
|
|||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
package com.eu.habbo.messages.incoming.housekeeping;
|
||||||
|
|
||||||
|
import com.eu.habbo.Emulator;
|
||||||
|
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
|
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||||
|
import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingActionResultComposer;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permanently delete a room. Mirrors the minimum-viable subset of
|
||||||
|
* RequestDeleteRoomEvent: eject all users from the live room, dispose
|
||||||
|
* + uncache, then DELETE FROM rooms. Pets/guild/custom-layout cleanup
|
||||||
|
* is intentionally skipped on this slice — leftover rows in those
|
||||||
|
* tables become orphans but don't crash the emulator; a follow-up
|
||||||
|
* pass can cascade once we have a HK audit-log row to attach the
|
||||||
|
* orphan-cleanup to.
|
||||||
|
*/
|
||||||
|
public class HousekeepingDeleteRoomEvent extends MessageHandler {
|
||||||
|
private static final String ACTION_KEY = "room.delete";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRatelimit() {
|
||||||
|
return 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle() throws Exception {
|
||||||
|
if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int roomId = this.packet.readInt();
|
||||||
|
|
||||||
|
if (roomId <= 0) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Room room = Emulator.getGameEnvironment().getRoomManager().loadRoom(roomId, false);
|
||||||
|
|
||||||
|
if (room != null) {
|
||||||
|
room.ejectAll();
|
||||||
|
room.preventUnloading = false;
|
||||||
|
room.dispose();
|
||||||
|
Emulator.getGameEnvironment().getRoomManager().uncacheRoom(room);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||||
|
PreparedStatement statement = connection.prepareStatement("DELETE FROM rooms WHERE id = ? LIMIT 1")) {
|
||||||
|
statement.setInt(1, roomId);
|
||||||
|
int rows = statement.executeUpdate();
|
||||||
|
|
||||||
|
if (rows == 0) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.room_not_found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.db_failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, roomId, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package com.eu.habbo.messages.incoming.housekeeping;
|
||||||
|
|
||||||
|
import com.eu.habbo.Emulator;
|
||||||
|
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
|
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||||
|
import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingRoomDetailComposer;
|
||||||
|
|
||||||
|
public class HousekeepingFindRoomByIdEvent extends MessageHandler {
|
||||||
|
@Override
|
||||||
|
public int getRatelimit() {
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle() throws Exception {
|
||||||
|
if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int roomId = this.packet.readInt();
|
||||||
|
|
||||||
|
if (roomId <= 0) {
|
||||||
|
this.client.sendResponse(new HousekeepingRoomDetailComposer(null));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadRoom covers both the in-memory cache (already-loaded rooms)
|
||||||
|
// and the offline path (SELECT * FROM rooms WHERE id=?). Pass
|
||||||
|
// false for loadData so we don't pull furni/bots/pets just to
|
||||||
|
// render an HK panel summary — getOwnerName / getUserCount work
|
||||||
|
// on the pre-loaded skeleton.
|
||||||
|
Room room = Emulator.getGameEnvironment().getRoomManager().loadRoom(roomId, false);
|
||||||
|
|
||||||
|
this.client.sendResponse(new HousekeepingRoomDetailComposer(room));
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
package com.eu.habbo.messages.incoming.housekeeping;
|
||||||
|
|
||||||
|
import com.eu.habbo.Emulator;
|
||||||
|
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
|
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||||
|
import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingActionResultComposer;
|
||||||
|
|
||||||
|
public class HousekeepingKickAllFromRoomEvent extends MessageHandler {
|
||||||
|
private static final String ACTION_KEY = "room.kick_all";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRatelimit() {
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle() throws Exception {
|
||||||
|
if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int roomId = this.packet.readInt();
|
||||||
|
|
||||||
|
if (roomId <= 0) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Room room = Emulator.getGameEnvironment().getRoomManager().loadRoom(roomId, false);
|
||||||
|
|
||||||
|
if (room == null) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.room_not_found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
room.ejectAll();
|
||||||
|
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, roomId, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
package com.eu.habbo.messages.incoming.housekeeping;
|
||||||
|
|
||||||
|
import com.eu.habbo.Emulator;
|
||||||
|
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
|
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||||
|
import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingActionResultComposer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle room-wide mute. Habbo's Room.setMuted is boolean, not duration-
|
||||||
|
* scoped, so the wire `minutes` arg picks the semantic: minutes==0 =>
|
||||||
|
* unmute, minutes>0 => mute. An emulator-side scheduled unmute could
|
||||||
|
* use the value as a timer, but for now the mute stays until the
|
||||||
|
* operator unmutes manually — the minutes is reserved as a forward-
|
||||||
|
* compat field on the wire.
|
||||||
|
*/
|
||||||
|
public class HousekeepingMuteRoomEvent extends MessageHandler {
|
||||||
|
private static final String ACTION_KEY = "room.mute";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRatelimit() {
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle() throws Exception {
|
||||||
|
if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int roomId = this.packet.readInt();
|
||||||
|
int minutes = this.packet.readInt();
|
||||||
|
|
||||||
|
if (roomId <= 0) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Room room = Emulator.getGameEnvironment().getRoomManager().loadRoom(roomId, false);
|
||||||
|
|
||||||
|
if (room == null) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.room_not_found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
room.setMuted(minutes > 0);
|
||||||
|
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, roomId, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
package com.eu.habbo.messages.incoming.housekeeping;
|
||||||
|
|
||||||
|
import com.eu.habbo.Emulator;
|
||||||
|
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.RoomState;
|
||||||
|
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||||
|
import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingActionResultComposer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the room state between OPEN (open) and LOCKED (closed). The
|
||||||
|
* client picks which transition it wants via the boolean — true => OPEN,
|
||||||
|
* false => LOCKED. Persists state through `Room.save()` so the change
|
||||||
|
* outlives an unload.
|
||||||
|
*/
|
||||||
|
public class HousekeepingRoomStateEvent extends MessageHandler {
|
||||||
|
@Override
|
||||||
|
public int getRatelimit() {
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle() throws Exception {
|
||||||
|
if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int roomId = this.packet.readInt();
|
||||||
|
boolean open = this.packet.readBoolean();
|
||||||
|
String actionKey = open ? "room.open" : "room.close";
|
||||||
|
|
||||||
|
if (roomId <= 0) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(actionKey, false, 0, "housekeeping.error.invalid_input"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Room room = Emulator.getGameEnvironment().getRoomManager().loadRoom(roomId, false);
|
||||||
|
|
||||||
|
if (room == null) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(actionKey, false, 0, "housekeeping.error.room_not_found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
room.setState(open ? RoomState.OPEN : RoomState.LOCKED);
|
||||||
|
room.save();
|
||||||
|
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(actionKey, true, roomId, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
package com.eu.habbo.messages.incoming.housekeeping;
|
||||||
|
|
||||||
|
import com.eu.habbo.Emulator;
|
||||||
|
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
|
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||||
|
import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingRoomListComposer;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search rooms by name. `exactMatch=true` => `name = ?` (used by the
|
||||||
|
* findByName autocomplete that wants a unique hit). `exactMatch=false`
|
||||||
|
* => `name LIKE concat(?, '%')` (used by the prefix dropdown).
|
||||||
|
*
|
||||||
|
* Both branches go through the same packet because the wire shape is
|
||||||
|
* identical — the client picks which mode it wants by toggling the
|
||||||
|
* boolean.
|
||||||
|
*/
|
||||||
|
public class HousekeepingSearchRoomsEvent extends MessageHandler {
|
||||||
|
private static final int HARD_LIMIT = 50;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRatelimit() {
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle() throws Exception {
|
||||||
|
if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String query = this.packet.readString();
|
||||||
|
boolean exactMatch = this.packet.readBoolean();
|
||||||
|
int limit = Math.min(Math.max(this.packet.readInt(), 1), HARD_LIMIT);
|
||||||
|
|
||||||
|
if (query == null) query = "";
|
||||||
|
query = query.trim();
|
||||||
|
|
||||||
|
if (query.isEmpty()) {
|
||||||
|
this.client.sendResponse(new HousekeepingRoomListComposer(new ArrayList<>()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sql = exactMatch
|
||||||
|
? "SELECT id FROM rooms WHERE name = ? LIMIT ?"
|
||||||
|
: "SELECT id FROM rooms WHERE name LIKE ? LIMIT ?";
|
||||||
|
|
||||||
|
List<Room> rooms = new ArrayList<>();
|
||||||
|
|
||||||
|
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||||
|
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||||
|
statement.setString(1, exactMatch ? query : query + "%");
|
||||||
|
statement.setInt(2, limit);
|
||||||
|
|
||||||
|
try (ResultSet set = statement.executeQuery()) {
|
||||||
|
while (set.next()) {
|
||||||
|
Room room = Emulator.getGameEnvironment().getRoomManager().loadRoom(set.getInt("id"), false);
|
||||||
|
|
||||||
|
if (room != null) rooms.add(room);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException ignored) {
|
||||||
|
// fall through with whatever we collected before the failure
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client.sendResponse(new HousekeepingRoomListComposer(rooms));
|
||||||
|
}
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
package com.eu.habbo.messages.incoming.housekeeping;
|
||||||
|
|
||||||
|
import com.eu.habbo.Emulator;
|
||||||
|
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||||
|
import com.eu.habbo.habbohotel.users.HabboInfo;
|
||||||
|
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||||
|
import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingActionResultComposer;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transfer ownership of a room to a different user. Updates both
|
||||||
|
* `rooms.owner_id` and `rooms.owner_name` so the cached owner name on
|
||||||
|
* the navigator stays in sync without forcing a relog. The room is
|
||||||
|
* touched via direct SQL rather than via Room.setOwnerId() because
|
||||||
|
* the room may not be loaded.
|
||||||
|
*/
|
||||||
|
public class HousekeepingTransferRoomOwnershipEvent extends MessageHandler {
|
||||||
|
private static final String ACTION_KEY = "room.transfer";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRatelimit() {
|
||||||
|
return 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle() throws Exception {
|
||||||
|
if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int roomId = this.packet.readInt();
|
||||||
|
int newOwnerId = this.packet.readInt();
|
||||||
|
|
||||||
|
if (roomId <= 0 || newOwnerId <= 0) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HabboInfo newOwner = Emulator.getGameEnvironment().getHabboManager().getHabboInfo(newOwnerId);
|
||||||
|
|
||||||
|
if (newOwner == null) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.new_owner_not_found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||||
|
PreparedStatement statement = connection.prepareStatement("UPDATE rooms SET owner_id = ?, owner_name = ? WHERE id = ? LIMIT 1")) {
|
||||||
|
statement.setInt(1, newOwnerId);
|
||||||
|
statement.setString(2, newOwner.getUsername());
|
||||||
|
statement.setInt(3, roomId);
|
||||||
|
int rows = statement.executeUpdate();
|
||||||
|
|
||||||
|
if (rows == 0) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.room_not_found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.db_failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, roomId, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -589,5 +589,7 @@ public class Outgoing {
|
|||||||
// Housekeeping (in-client admin panel) — IDs 9200..9299 reserved
|
// Housekeeping (in-client admin panel) — IDs 9200..9299 reserved
|
||||||
public static final int HousekeepingUserDetailComposer = 9200;
|
public static final int HousekeepingUserDetailComposer = 9200;
|
||||||
public static final int HousekeepingActionResultComposer = 9201;
|
public static final int HousekeepingActionResultComposer = 9201;
|
||||||
|
public static final int HousekeepingRoomDetailComposer = 9202;
|
||||||
|
public static final int HousekeepingRoomListComposer = 9203;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
package com.eu.habbo.messages.outgoing.housekeeping;
|
||||||
|
|
||||||
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.RoomState;
|
||||||
|
import com.eu.habbo.messages.ServerMessage;
|
||||||
|
import com.eu.habbo.messages.outgoing.MessageComposer;
|
||||||
|
import com.eu.habbo.messages.outgoing.Outgoing;
|
||||||
|
|
||||||
|
public class HousekeepingRoomDetailComposer extends MessageComposer {
|
||||||
|
private final Room room;
|
||||||
|
|
||||||
|
public HousekeepingRoomDetailComposer(Room room) {
|
||||||
|
this.room = room;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ServerMessage composeInternal() {
|
||||||
|
this.response.init(Outgoing.HousekeepingRoomDetailComposer);
|
||||||
|
|
||||||
|
if (this.room == null) {
|
||||||
|
this.response.appendBoolean(false);
|
||||||
|
return this.response;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.response.appendBoolean(true);
|
||||||
|
appendRoomFields(this.response, this.room);
|
||||||
|
|
||||||
|
return this.response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Shared by HousekeepingRoomListComposer too. */
|
||||||
|
public static void appendRoomFields(ServerMessage response, Room room) {
|
||||||
|
response.appendInt(room.getId());
|
||||||
|
response.appendString(safe(room.getName()));
|
||||||
|
response.appendString(safe(room.getDescription()));
|
||||||
|
response.appendInt(room.getOwnerId());
|
||||||
|
response.appendString(safe(room.getOwnerName()));
|
||||||
|
response.appendInt(room.getUserCount());
|
||||||
|
response.appendInt(room.getUsersMax());
|
||||||
|
response.appendBoolean(room.getState() != null && room.getState() != RoomState.OPEN);
|
||||||
|
response.appendBoolean(room.isMuted());
|
||||||
|
response.appendBoolean(room.isPublicRoom());
|
||||||
|
response.appendInt(0); // createdAt — Room doesn't expose; left as 0 until a schema-side timestamp surfaces.
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String safe(String value) {
|
||||||
|
return value != null ? value : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package com.eu.habbo.messages.outgoing.housekeeping;
|
||||||
|
|
||||||
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
|
import com.eu.habbo.messages.ServerMessage;
|
||||||
|
import com.eu.habbo.messages.outgoing.MessageComposer;
|
||||||
|
import com.eu.habbo.messages.outgoing.Outgoing;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class HousekeepingRoomListComposer extends MessageComposer {
|
||||||
|
private final List<Room> rooms;
|
||||||
|
|
||||||
|
public HousekeepingRoomListComposer(List<Room> rooms) {
|
||||||
|
this.rooms = rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ServerMessage composeInternal() {
|
||||||
|
this.response.init(Outgoing.HousekeepingRoomListComposer);
|
||||||
|
this.response.appendInt(this.rooms != null ? this.rooms.size() : 0);
|
||||||
|
|
||||||
|
if (this.rooms != null) {
|
||||||
|
for (Room room : this.rooms) {
|
||||||
|
HousekeepingRoomDetailComposer.appendRoomFields(this.response, room);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.response;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user