From c4b3295a454746ccc8335b4d1cf8d75510851b27 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Sun, 24 May 2026 11:03:32 +0200 Subject: [PATCH] feat(housekeeping): force-disconnect-user packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../com/eu/habbo/messages/PacketManager.java | 1 + .../eu/habbo/messages/incoming/Incoming.java | 1 + .../HousekeepingForceDisconnectUserEvent.java | 54 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingForceDisconnectUserEvent.java diff --git a/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java b/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java index 971101e6..bc45b669 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java @@ -724,5 +724,6 @@ public class PacketManager { this.registerHandler(Incoming.HousekeepingUnbanUserEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingUnbanUserEvent.class); this.registerHandler(Incoming.HousekeepingMuteUserEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingMuteUserEvent.class); this.registerHandler(Incoming.HousekeepingKickUserEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingKickUserEvent.class); + this.registerHandler(Incoming.HousekeepingForceDisconnectUserEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingForceDisconnectUserEvent.class); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java index 194bb517..a43ba1ab 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java @@ -468,4 +468,5 @@ public class Incoming { public static final int HousekeepingUnbanUserEvent = 9103; public static final int HousekeepingMuteUserEvent = 9104; public static final int HousekeepingKickUserEvent = 9105; + public static final int HousekeepingForceDisconnectUserEvent = 9106; } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingForceDisconnectUserEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingForceDisconnectUserEvent.java new file mode 100644 index 00000000..5a5193c7 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/housekeeping/HousekeepingForceDisconnectUserEvent.java @@ -0,0 +1,54 @@ +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.Habbo; +import com.eu.habbo.messages.incoming.MessageHandler; +import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingActionResultComposer; + +/** + * Force-close the session of an online user. Unlike kick (which only + * removes them from the current room), this drops their socket. Equivalent + * to /disconnect in command form but issued through the HK panel. + */ +public class HousekeepingForceDisconnectUserEvent extends MessageHandler { + private static final String ACTION_KEY = "user.disconnect"; + + @Override + public int getRatelimit() { + return 1000; + } + + @Override + public void handle() throws Exception { + if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) { + return; + } + + int userId = this.packet.readInt(); + String reason = this.packet.readString(); + + if (userId <= 0) { + this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "invalid_input")); + return; + } + + Habbo target = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId); + + if (target == null) { + this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "user_offline")); + return; + } + + if (reason != null && !reason.isEmpty()) { + target.alert(reason); + } + + // ACK first so the action result lands before the target's socket + // closes (otherwise an alerted user on the same emulator thread may + // already be torn down when we try to write). + this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, "")); + + target.disconnect(); + } +}