Compare commits

...

11 Commits

Author SHA1 Message Date
github-actions[bot] 2c0ef9873c 🆙 Bump version to 4.2.36 [skip ci] 2026-06-04 08:44:19 +00:00
DuckieTM dadc1b8aaf Merge pull request #153 from duckietm/dev
Dev
2026-06-04 10:43:21 +02:00
duckietm 85758b53fa 🆙 Updates Mention 2026-06-04 10:43:05 +02:00
DuckieTM 2171b5f2ec Merge pull request #152 from medievalshell/feat/mentions-hotelwide-figure
feat(mentions): hotel-wide @nick delivery + sender figure + disable-m…
2026-06-04 08:50:49 +02:00
medievalshell 46306c8205 feat(mentions): hotel-wide @nick delivery + sender figure + disable-mention persistence
- resolveHabbo() falls back to a hotel-wide online lookup so a direct @nick
  mention reaches the target even when they are in a different room (was
  resolved only within the sender's room).
- HabboMention now carries the sender figure (live from the sender Habbo,
  history from a users.look JOIN); MentionReceived/MentionsList composers
  append it so the client can render the sender avatar in the notification.
- 009: add users_settings.mentions_enabled / mass_mentions_enabled columns
  so :disablementions / :disablemassmentions actually persist.
2026-06-04 01:27:45 +02:00
github-actions[bot] fadec887cd 🆙 Bump version to 4.2.35 [skip ci] 2026-06-03 14:45:16 +00:00
DuckieTM e614c1d64f Merge pull request #150 from duckietm/dev
Merge pull request #149 from duckietm/main
2026-06-03 16:44:04 +02:00
DuckieTM e7deea7d9d Merge pull request #149 from duckietm/main
sync to dev
2026-06-03 16:39:01 +02:00
github-actions[bot] 44ea3abd4e 🆙 Bump version to 4.2.34 [skip ci] 2026-06-03 14:37:38 +00:00
DuckieTM 609cd20ab2 Merge pull request #143 from simoleo89/feat/command-autocomplete-refactor
Structure commands alert output
2026-06-03 16:36:33 +02:00
simoleo89 9f36d95dbc fix(commands): structure commands alert output 2026-06-02 18:34:50 +02:00
8 changed files with 92 additions and 20 deletions
+14 -1
View File
@@ -73,4 +73,17 @@ INSERT IGNORE INTO `emulator_settings` (`key`, `value`, `comment`) VALUES
ALTER TABLE `wordfilter`
ADD COLUMN `prefix_only` ENUM('0','1') NOT NULL DEFAULT '0'
COMMENT 'When 1, this word only applies to custom prefixes, not to chat/motto/guild.' AFTER `mute`;
COMMENT 'When 1, this word only applies to custom prefixes, not to chat/motto/guild.' AFTER `mute`;
-- ----------------------------------------------------------------------------
-- 5. Per-user mention preferences (:disablementions / :disablemassmentions)
--
-- Read by HabboStats (default '1' = enabled), toggled by the commands.
-- Without these columns the toggle commands cannot persist.
-- ----------------------------------------------------------------------------
ALTER TABLE `users_settings`
ADD COLUMN IF NOT EXISTS `mentions_enabled` ENUM('0','1') NOT NULL DEFAULT '1'
COMMENT 'Receive @nick mention notifications.',
ADD COLUMN IF NOT EXISTS `mass_mentions_enabled` ENUM('0','1') NOT NULL DEFAULT '1'
COMMENT 'Receive broadcast (@all / @friends / @room) mentions.';
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>com.eu.habbo</groupId>
<artifactId>Habbo</artifactId>
<version>4.2.33</version>
<version>4.2.36</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -17,7 +17,22 @@ public class CommandsCommand extends Command {
message.append("(").append(commands.size()).append("):\r\n");
for (Command c : commands) {
message.append(Emulator.getTexts().getValue("commands.description." + c.permission, "commands.description." + c.permission)).append("\r");
String textKey = "commands.description." + c.permission;
String commandText = Emulator.getTexts().getValue(textKey, "");
String commandLine = ":" + c.keys[0];
String description = "";
if (commandText.startsWith(":")) {
commandLine = commandText;
} else if (!commandText.isEmpty() && !commandText.equals(textKey)) {
description = commandText;
}
message.append(commandLine).append("\r");
if (!description.isEmpty()) {
message.append(description).append("\r");
}
}
gameClient.getHabbo().alert(new String[]{message.toString()});
@@ -21,6 +21,7 @@ public class HabboMention {
private final int mentionType;
private final int timestamp;
private final boolean read;
private final String senderFigure;
public HabboMention(ResultSet set) throws SQLException {
this.id = set.getInt("id");
@@ -33,6 +34,16 @@ public class HabboMention {
this.mentionType = set.getInt("mention_type");
this.timestamp = set.getInt("timestamp");
this.read = set.getInt("read") == 1;
this.senderFigure = hasSenderFigure(set) ? set.getString("sender_figure") : "";
}
private static boolean hasSenderFigure(ResultSet set) {
try {
set.findColumn("sender_figure");
return true;
} catch (SQLException e) {
return false;
}
}
public HabboMention(int targetUserId, int id, Habbo sender, Room room, String roomName, String message, int mentionType, int timestamp) {
@@ -46,6 +57,7 @@ public class HabboMention {
this.mentionType = mentionType;
this.timestamp = timestamp;
this.read = false;
this.senderFigure = sender.getHabboInfo().getLook();
}
public int getId() {
@@ -87,4 +99,8 @@ public class HabboMention {
public boolean isRead() {
return this.read;
}
public String getSenderFigure() {
return this.senderFigure == null ? "" : this.senderFigure;
}
}
@@ -9,18 +9,8 @@ import com.eu.habbo.habbohotel.users.HabboManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.sql.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class MentionManager {
@@ -43,7 +33,6 @@ public class MentionManager {
return Emulator.getConfig().getInt("mentions.enabled", 1) == 1;
}
/** Broadcast category resolved from a mention alias. */
public enum BroadcastScope {
NONE,
ROOM,
@@ -249,7 +238,9 @@ public class MentionManager {
}
private boolean acceptsMention(Habbo recipient, boolean isBroadcast) {
if (recipient == null || recipient.getHabboStats() == null) return true;
if (recipient == null) return false;
if (recipient.getClient() == null) return false;
if (recipient.getHabboStats() == null) return false;
if (!recipient.getHabboStats().mentionsEnabled()) return false;
if (isBroadcast && !recipient.getHabboStats().massMentionsEnabled()) return false;
return true;
@@ -297,7 +288,7 @@ public class MentionManager {
if (limit > 200) limit = 200;
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement(
"SELECT * FROM habbo_mentions WHERE target_user_id = ? ORDER BY id DESC LIMIT ?")) {
"SELECT habbo_mentions.*, users.look AS sender_figure FROM habbo_mentions LEFT JOIN users ON users.id = habbo_mentions.sender_user_id WHERE target_user_id = ? ORDER BY id DESC LIMIT ?")) {
statement.setInt(1, userId);
statement.setInt(2, limit);
try (ResultSet set = statement.executeQuery()) {
@@ -423,14 +414,49 @@ public class MentionManager {
return value.substring(0, max);
}
private boolean isBotOrPetName(Room room, String token) {
if (room == null || token == null || token.isEmpty()) return false;
List<com.eu.habbo.habbohotel.bots.Bot> bots = room.getBots(token);
if (bots != null && !bots.isEmpty()) return true;
if (room.getUnitManager() != null && room.getUnitManager().getPets() != null) {
for (com.eu.habbo.habbohotel.pets.Pet pet : room.getUnitManager().getPets()) {
if (pet != null && pet.getName() != null && pet.getName().equalsIgnoreCase(token)) {
return true;
}
}
}
return false;
}
private Habbo resolveHabbo(Room room, String rawToken) {
if (isBotOrPetName(room, rawToken)) {
return null;
}
String trimmedForBotCheck = trimTrailingPunctuation(rawToken);
if (!trimmedForBotCheck.equals(rawToken) && isBotOrPetName(room, trimmedForBotCheck)) {
return null;
}
Habbo habbo = room.getHabbo(rawToken);
if (habbo != null) {
return habbo;
}
HabboManager habboManager = Emulator.getGameEnvironment().getHabboManager();
habbo = habboManager.getHabbo(rawToken);
if (habbo != null) {
return habbo;
}
String trimmed = trimTrailingPunctuation(rawToken);
if (!trimmed.isEmpty() && !trimmed.equals(rawToken)) {
return room.getHabbo(trimmed);
habbo = room.getHabbo(trimmed);
if (habbo != null) {
return habbo;
}
return habboManager.getHabbo(trimmed);
}
return null;
}
@@ -18,6 +18,7 @@ public class MentionReceivedComposer extends MessageComposer {
this.response.appendInt(this.mention.getId());
this.response.appendInt(this.mention.getSenderUserId());
this.response.appendString(this.mention.getSenderUsername());
this.response.appendString(this.mention.getSenderFigure());
this.response.appendInt(this.mention.getRoomId());
this.response.appendString(this.mention.getRoomName());
this.response.appendString(this.mention.getMessage());
@@ -23,6 +23,7 @@ public class MentionsListComposer extends MessageComposer {
this.response.appendInt(mention.getId());
this.response.appendInt(mention.getSenderUserId());
this.response.appendString(mention.getSenderUsername());
this.response.appendString(mention.getSenderFigure());
this.response.appendInt(mention.getRoomId());
this.response.appendString(mention.getRoomName());
this.response.appendString(mention.getMessage());
+1 -1
View File
@@ -10,7 +10,7 @@ and is developed for free by talented developers and is compatible with the foll
[Latest compiled version](https://github.com/duckietm/Arcturus-Morningstar-Extended/tree/main/Latest_Compiled_Version)
## Connection ##
Use the Websocket plugin!
Use the BUILD-IN Websocket so do NOT load any websocket plugin!
### How do I connect to my emulator using Secure Websockets (wss)?
You have several options to add WSS support to your websocket server.