From bf1a29a6e8bc7b9fcc3b1948e60b1f64b0bf1bd2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 30 May 2026 05:53:48 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=86=99=20Bump=20version=20to=204.2.26?= =?UTF-8?q?=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Emulator/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emulator/pom.xml b/Emulator/pom.xml index 88b0e6a3..17628061 100644 --- a/Emulator/pom.xml +++ b/Emulator/pom.xml @@ -6,7 +6,7 @@ com.eu.habbo Habbo - 4.2.25 + 4.2.26 UTF-8 From da63439d53706f5902793519a754501d3d1dad78 Mon Sep 17 00:00:00 2001 From: medievalshell Date: Sun, 31 May 2026 00:03:39 +0200 Subject: [PATCH 2/3] fix(bans): persist client machine fingerprint so machine/super bans work The Nitro client already sends a strong machine fingerprint (Thumbmark, "IID-") via the UniqueID packet (header 2490 -> MachineIDEvent), but the emulator only stored it on the GameClient and never copied it onto the Habbo's HabboInfo, so it was never written to users.machine_id. As a result machine/super bans (which read users.machine_id) matched nobody. - MachineIDEvent: when the fingerprint arrives and the Habbo is already loaded, copy it onto HabboInfo and persist (run the Habbo save). - SecureLoginEvent: if the fingerprint arrived before login, copy it onto HabboInfo right before the login save. This makes machine/super bans effective without changing the client. --- .../messages/incoming/handshake/MachineIDEvent.java | 10 ++++++++++ .../messages/incoming/handshake/SecureLoginEvent.java | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/handshake/MachineIDEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/handshake/MachineIDEvent.java index 477fc3c6..64696bf7 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/handshake/MachineIDEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/handshake/MachineIDEvent.java @@ -1,5 +1,6 @@ package com.eu.habbo.messages.incoming.handshake; +import com.eu.habbo.Emulator; import com.eu.habbo.messages.NoAuthMessage; import com.eu.habbo.messages.incoming.MessageHandler; import org.slf4j.Logger; @@ -24,6 +25,15 @@ public class MachineIDEvent extends MessageHandler { this.client.setMachineId(storedMachineId); + // Persist the machine fingerprint onto the user so machine/super bans can + // target it (createOfflineUserBan copies users.machine_id). The Nitro client + // sends this UniqueID packet right after the SSO ticket, so the Habbo is + // normally already loaded by the time we get here. + if (!storedMachineId.isEmpty() && this.client.getHabbo() != null && this.client.getHabbo().getHabboInfo() != null) { + this.client.getHabbo().getHabboInfo().setMachineID(storedMachineId); + Emulator.getThreading().run(this.client.getHabbo()); + } + LOGGER.debug("Setting client MachineId to {}", storedMachineId); } } \ No newline at end of file diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/handshake/SecureLoginEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/handshake/SecureLoginEvent.java index 7c7dcf3c..cdebe27d 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/handshake/SecureLoginEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/handshake/SecureLoginEvent.java @@ -161,6 +161,12 @@ public class SecureLoginEvent extends MessageHandler { throw new NullPointerException(habbo.getHabboInfo().getUsername() + " has a NON EXISTING RANK!"); } + // If the machine fingerprint already arrived (UniqueID before login), + // persist it so machine/super bans can target this user. + if (this.client.getMachineId() != null && !this.client.getMachineId().isEmpty()) { + this.client.getHabbo().getHabboInfo().setMachineID(this.client.getMachineId()); + } + Emulator.getThreading().run(habbo); Emulator.getGameEnvironment().getHabboManager().addHabbo(habbo); } catch (Exception e) { From 02ab30180c49d05eefabb469c567ea733b247369 Mon Sep 17 00:00:00 2001 From: medievalshell Date: Sun, 31 May 2026 03:39:23 +0200 Subject: [PATCH 3/3] fix(chat): relay unknown chat bubble ids instead of resetting to default getBubble() fell back to NORMAL (bubble 0) for any id not in the registered BUBBLES map, so custom client-side chat bubbles (e.g. ids 253+) rendered as the default bubble for everyone. Now unknown positive ids (<=1000) pass through as a transient bubble carrying that id, so the server relays it and clients render their own .bubble- style. No need to enumerate each one. --- .../habbohotel/rooms/RoomChatMessageBubbles.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessageBubbles.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessageBubbles.java index d38133e4..fef00f33 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessageBubbles.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessageBubbles.java @@ -134,7 +134,18 @@ public class RoomChatMessageBubbles { } public static RoomChatMessageBubbles getBubble(int id) { - return BUBBLES.getOrDefault(id, NORMAL); + RoomChatMessageBubbles bubble = BUBBLES.get(id); + if (bubble != null) return bubble; + + // Custom chat bubbles (client-side only, e.g. ids 253+) are not registered + // above. Instead of falling back to NORMAL (which made them render as the + // default bubble), pass the id through so the server relays it as-is and + // the client renders its own .bubble- style. Capped to avoid abuse. + if (id > 0 && id <= 1000) { + return new RoomChatMessageBubbles(id, "CUSTOM_" + id, "", true, false); + } + + return NORMAL; } private static void registerBubble(RoomChatMessageBubbles bubble) {