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.
This commit is contained in:
medievalshell
2026-06-04 01:17:32 +02:00
committed by medievalshell
parent e7deea7d9d
commit 46306c8205
5 changed files with 45 additions and 3 deletions
+14 -1
View File
@@ -73,4 +73,17 @@ INSERT IGNORE INTO `emulator_settings` (`key`, `value`, `comment`) VALUES
ALTER TABLE `wordfilter` ALTER TABLE `wordfilter`
ADD COLUMN `prefix_only` ENUM('0','1') NOT NULL DEFAULT '0' 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.';
@@ -21,6 +21,7 @@ public class HabboMention {
private final int mentionType; private final int mentionType;
private final int timestamp; private final int timestamp;
private final boolean read; private final boolean read;
private final String senderFigure;
public HabboMention(ResultSet set) throws SQLException { public HabboMention(ResultSet set) throws SQLException {
this.id = set.getInt("id"); this.id = set.getInt("id");
@@ -33,6 +34,16 @@ public class HabboMention {
this.mentionType = set.getInt("mention_type"); this.mentionType = set.getInt("mention_type");
this.timestamp = set.getInt("timestamp"); this.timestamp = set.getInt("timestamp");
this.read = set.getInt("read") == 1; 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) { 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.mentionType = mentionType;
this.timestamp = timestamp; this.timestamp = timestamp;
this.read = false; this.read = false;
this.senderFigure = sender.getHabboInfo().getLook();
} }
public int getId() { public int getId() {
@@ -87,4 +99,8 @@ public class HabboMention {
public boolean isRead() { public boolean isRead() {
return this.read; return this.read;
} }
public String getSenderFigure() {
return this.senderFigure == null ? "" : this.senderFigure;
}
} }
@@ -297,7 +297,7 @@ public class MentionManager {
if (limit > 200) limit = 200; if (limit > 200) limit = 200;
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement( 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(1, userId);
statement.setInt(2, limit); statement.setInt(2, limit);
try (ResultSet set = statement.executeQuery()) { try (ResultSet set = statement.executeQuery()) {
@@ -428,9 +428,20 @@ public class MentionManager {
if (habbo != null) { if (habbo != null) {
return habbo; return habbo;
} }
// Hotel-wide fallback: a @nick mention must reach the target even when
// they are online in a different room (not just the sender's room).
HabboManager habboManager = Emulator.getGameEnvironment().getHabboManager();
habbo = habboManager.getHabbo(rawToken);
if (habbo != null) {
return habbo;
}
String trimmed = trimTrailingPunctuation(rawToken); String trimmed = trimTrailingPunctuation(rawToken);
if (!trimmed.isEmpty() && !trimmed.equals(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; return null;
} }
@@ -18,6 +18,7 @@ public class MentionReceivedComposer extends MessageComposer {
this.response.appendInt(this.mention.getId()); this.response.appendInt(this.mention.getId());
this.response.appendInt(this.mention.getSenderUserId()); this.response.appendInt(this.mention.getSenderUserId());
this.response.appendString(this.mention.getSenderUsername()); this.response.appendString(this.mention.getSenderUsername());
this.response.appendString(this.mention.getSenderFigure());
this.response.appendInt(this.mention.getRoomId()); this.response.appendInt(this.mention.getRoomId());
this.response.appendString(this.mention.getRoomName()); this.response.appendString(this.mention.getRoomName());
this.response.appendString(this.mention.getMessage()); this.response.appendString(this.mention.getMessage());
@@ -23,6 +23,7 @@ public class MentionsListComposer extends MessageComposer {
this.response.appendInt(mention.getId()); this.response.appendInt(mention.getId());
this.response.appendInt(mention.getSenderUserId()); this.response.appendInt(mention.getSenderUserId());
this.response.appendString(mention.getSenderUsername()); this.response.appendString(mention.getSenderUsername());
this.response.appendString(mention.getSenderFigure());
this.response.appendInt(mention.getRoomId()); this.response.appendInt(mention.getRoomId());
this.response.appendString(mention.getRoomName()); this.response.appendString(mention.getRoomName());
this.response.appendString(mention.getMessage()); this.response.appendString(mention.getMessage());