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
Merge remote-tracking branch 'upstream/main'
# Conflicts: # Emulator/src/main/java/com/eu/habbo/habbohotel/commands/CommandHandler.java # Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java # Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotHabboHasHandItem.java # Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectFurniToFurni.java # Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectFurniToUser.java # Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/effects/WiredEffectUserToFurni.java # Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/triggers/WiredTriggerFurniStateToggled.java # Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/triggers/WiredTriggerHabboClicksFurni.java # Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/triggers/WiredTriggerHabboClicksTile.java # Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/triggers/WiredTriggerHabboClicksUser.java # Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomUnitManager.java # Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredConditionType.java # Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredEffectType.java # Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredTriggerType.java # Emulator/src/main/java/com/eu/habbo/habbohotel/wired/core/WiredManager.java # Emulator/src/main/java/com/eu/habbo/habbohotel/wired/migrate/WiredEvents.java # Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/items/ClickFurniEvent.java # Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/users/ClickUserEvent.java
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
CREATE TABLE IF NOT EXISTS `user_prefixes` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` INT(11) NOT NULL,
|
||||
`text` VARCHAR(50) NOT NULL,
|
||||
`color` VARCHAR(255) NOT NULL DEFAULT '#FFFFFF',
|
||||
`icon` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`effect` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`active` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `idx_user_id` (`user_id`),
|
||||
INDEX `idx_user_active` (`user_id`, `active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
@@ -0,0 +1,115 @@
|
||||
-- ============================================================
|
||||
-- Custom Prefix System - Complete Setup
|
||||
-- ============================================================
|
||||
|
||||
-- 1. Main user prefixes table
|
||||
CREATE TABLE IF NOT EXISTS `user_prefixes` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` INT(11) NOT NULL,
|
||||
`text` VARCHAR(50) NOT NULL,
|
||||
`color` VARCHAR(255) NOT NULL DEFAULT '#FFFFFF',
|
||||
`icon` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`effect` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`active` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `idx_user_id` (`user_id`),
|
||||
INDEX `idx_user_active` (`user_id`, `active`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- 2. Prefix settings table
|
||||
CREATE TABLE IF NOT EXISTS `custom_prefix_settings` (
|
||||
`key_name` VARCHAR(100) NOT NULL,
|
||||
`value` VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (`key_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Default settings
|
||||
INSERT IGNORE INTO `custom_prefix_settings` (`key_name`, `value`) VALUES
|
||||
('max_length', '15'),
|
||||
('min_rank_to_buy', '1'),
|
||||
('price_credits', '5'),
|
||||
('price_points', '0'),
|
||||
('points_type', '0');
|
||||
|
||||
-- 3. Blacklisted words table
|
||||
CREATE TABLE IF NOT EXISTS `custom_prefix_blacklist` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`word` VARCHAR(100) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_word` (`word`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Example blacklist entries (customize as needed)
|
||||
INSERT IGNORE INTO `custom_prefix_blacklist` (`word`) VALUES
|
||||
('admin'),
|
||||
('staff'),
|
||||
('mod'),
|
||||
('owner');
|
||||
|
||||
-- 4. Add effect column (if table already exists without it)
|
||||
-- ALTER TABLE `user_prefixes` ADD COLUMN IF NOT EXISTS `effect` VARCHAR(50) NOT NULL DEFAULT '' AFTER `icon`;
|
||||
|
||||
-- ============================================================
|
||||
-- Catalog page for custom prefixes
|
||||
-- ============================================================
|
||||
-- NOTE: Adjust parent_id to match your catalog parent category ID.
|
||||
-- Example: parent_id = -1 for root, or the ID of your "Extra" / "Specials" category
|
||||
|
||||
INSERT INTO `catalog_pages` (
|
||||
`parent_id`, `caption`, `caption_save`, `icon_image`, `visible`, `enabled`,
|
||||
`min_rank`, `page_layout`, `page_strings_1`, `page_strings_2`
|
||||
) VALUES (
|
||||
-1,
|
||||
'Custom Prefix',
|
||||
'custom_prefix',
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
'custom_prefix',
|
||||
'Create your own custom prefix!\rChoose text, colors, icon and effects to stand out in chat.',
|
||||
''
|
||||
);
|
||||
|
||||
-- ============================================================
|
||||
-- Command texts (insert into emulator_texts if not present)
|
||||
-- ============================================================
|
||||
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
|
||||
-- GivePrefix command
|
||||
('commands.keys.cmd_give_prefix', 'giveprefix'),
|
||||
('commands.error.cmd_give_prefix.usage', 'Usage: :giveprefix <username> <text> <color> [icon] [effect]'),
|
||||
('commands.error.cmd_give_prefix.invalid_color', 'Invalid color format. Use hex format (#FF0000).'),
|
||||
('commands.error.cmd_give_prefix.too_long', 'Prefix text is too long (max 15 characters).'),
|
||||
('commands.error.cmd_give_prefix.user_not_found', 'User not found or not online.'),
|
||||
('commands.succes.cmd_give_prefix', 'Prefix {%prefix%} successfully given to %user%!'),
|
||||
-- ListPrefixes command
|
||||
('commands.keys.cmd_list_prefixes', 'listprefixes'),
|
||||
('commands.error.cmd_list_prefixes.usage', 'Usage: :listprefixes <username>'),
|
||||
('commands.error.cmd_list_prefixes.user_not_found', 'User not found or not online.'),
|
||||
('commands.succes.cmd_list_prefixes.header', 'Prefixes of %user%:'),
|
||||
('commands.succes.cmd_list_prefixes.empty', '%user% has no prefixes.'),
|
||||
-- RemovePrefix command
|
||||
('commands.keys.cmd_remove_prefix', 'removeprefix'),
|
||||
('commands.error.cmd_remove_prefix.usage', 'Usage: :removeprefix <username> <id|all>'),
|
||||
('commands.error.cmd_remove_prefix.user_not_found', 'User not found or not online.'),
|
||||
('commands.error.cmd_remove_prefix.invalid_id', 'Invalid prefix ID. Must be a number or "all".'),
|
||||
('commands.error.cmd_remove_prefix.not_found', 'Prefix not found for this user.'),
|
||||
('commands.succes.cmd_remove_prefix', 'Prefix #%id% removed from %user%.'),
|
||||
('commands.succes.cmd_remove_prefix.all', 'All prefixes removed from %user%.'),
|
||||
-- PrefixBlacklist command
|
||||
('commands.keys.cmd_prefix_blacklist', 'prefixblacklist'),
|
||||
('commands.error.cmd_prefix_blacklist.usage', 'Usage: :prefixblacklist <add|remove|list> [word]'),
|
||||
('commands.error.cmd_prefix_blacklist.empty_word', 'Word cannot be empty.'),
|
||||
('commands.succes.cmd_prefix_blacklist.header', 'Blacklisted prefix words:'),
|
||||
('commands.succes.cmd_prefix_blacklist.empty', 'No blacklisted words.'),
|
||||
('commands.succes.cmd_prefix_blacklist.added', 'Word "%word%" added to prefix blacklist.'),
|
||||
('commands.succes.cmd_prefix_blacklist.removed', 'Word "%word%" removed from prefix blacklist.');
|
||||
|
||||
-- ============================================================
|
||||
-- Permissions for prefix commands (add to permissions table)
|
||||
-- ============================================================
|
||||
INSERT IGNORE INTO `permissions` (`id`, `rank_id`, `permission_name`, `setting_type`) VALUES
|
||||
(NULL, 7, 'cmd_give_prefix', '1'),
|
||||
(NULL, 7, 'cmd_list_prefixes', '1'),
|
||||
(NULL, 7, 'cmd_remove_prefix', '1'),
|
||||
(NULL, 7, 'cmd_prefix_blacklist', '1');
|
||||
@@ -7,6 +7,7 @@ import com.eu.habbo.core.*;
|
||||
import com.eu.habbo.core.consolecommands.ConsoleCommand;
|
||||
import com.eu.habbo.database.Database;
|
||||
import com.eu.habbo.habbohotel.GameEnvironment;
|
||||
import com.eu.habbo.habbohotel.gameclients.SessionResumeManager;
|
||||
import com.eu.habbo.networking.gameserver.GameServer;
|
||||
import com.eu.habbo.networking.rconserver.RCONServer;
|
||||
import com.eu.habbo.plugin.PluginManager;
|
||||
@@ -319,6 +320,7 @@ public final class Emulator {
|
||||
if (Emulator.pluginManager != null)
|
||||
tryShutdown(() -> Emulator.pluginManager.fireEvent(new EmulatorStartShutdownEvent()));
|
||||
if (Emulator.rconServer != null) tryShutdown(() -> Emulator.rconServer.stop());
|
||||
tryShutdown(() -> SessionResumeManager.getInstance().disposeAll());
|
||||
if (Emulator.gameEnvironment != null) tryShutdown(() -> Emulator.gameEnvironment.dispose());
|
||||
if (Emulator.pluginManager != null)
|
||||
tryShutdown(() -> Emulator.pluginManager.fireEvent(new EmulatorStoppedEvent()));
|
||||
|
||||
@@ -173,6 +173,9 @@ public class CatalogManager {
|
||||
case mad_money:
|
||||
this.put(layout.name().toLowerCase(), MadMoneyLayout.class);
|
||||
break;
|
||||
case custom_prefix:
|
||||
this.put(layout.name().toLowerCase(), CustomPrefixLayout.class);
|
||||
break;
|
||||
case default_3x3:
|
||||
default:
|
||||
this.put("default_3x3", Default_3x3Layout.class);
|
||||
|
||||
@@ -43,5 +43,6 @@ public enum CatalogPageLayouts {
|
||||
builders_club_loyalty,
|
||||
monkey,
|
||||
niko,
|
||||
mad_money
|
||||
mad_money,
|
||||
custom_prefix
|
||||
}
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.eu.habbo.habbohotel.catalog.layouts;
|
||||
|
||||
import com.eu.habbo.habbohotel.catalog.CatalogPage;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class CustomPrefixLayout extends CatalogPage {
|
||||
|
||||
public CustomPrefixLayout(ResultSet set) throws SQLException {
|
||||
super(set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ServerMessage message) {
|
||||
message.appendString("custom_prefix");
|
||||
message.appendInt(3);
|
||||
message.appendString(super.getHeaderImage());
|
||||
message.appendString(super.getTeaserImage());
|
||||
message.appendString(super.getSpecialImage());
|
||||
message.appendInt(3);
|
||||
message.appendString(super.getTextOne());
|
||||
message.appendString(super.getTextDetails());
|
||||
message.appendString(super.getTextTeaser());
|
||||
}
|
||||
}
|
||||
@@ -297,8 +297,11 @@ public class CommandHandler {
|
||||
addCommand(new SoftKickCommand());
|
||||
addCommand(new SubscriptionCommand());
|
||||
addCommand(new UpdateChatBubblesCommand());
|
||||
addCommand(new GivePrefixCommand());
|
||||
addCommand(new ListPrefixesCommand());
|
||||
addCommand(new RemovePrefixCommand());
|
||||
addCommand(new PrefixBlacklistCommand());
|
||||
addCommand(new WiredCommand());
|
||||
|
||||
addCommand(new TestCommand());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.eu.habbo.habbohotel.commands;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomChatMessageBubbles;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.UserPrefix;
|
||||
import com.eu.habbo.messages.outgoing.inventory.prefixes.PrefixReceivedComposer;
|
||||
import com.eu.habbo.messages.outgoing.inventory.prefixes.UserPrefixesComposer;
|
||||
|
||||
public class GivePrefixCommand extends Command {
|
||||
public GivePrefixCommand() {
|
||||
super("cmd_give_prefix", Emulator.getTexts().getValue("commands.keys.cmd_give_prefix").split(";"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(GameClient gameClient, String[] params) throws Exception {
|
||||
if (params.length < 4) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_give_prefix.usage"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
String targetName = params[1];
|
||||
String text = params[2];
|
||||
String color = params[3];
|
||||
String icon = params.length > 4 ? params[4] : "";
|
||||
String effect = params.length > 5 ? params[5] : "";
|
||||
|
||||
// Validate color
|
||||
String[] colorParts = color.split(",");
|
||||
for (String part : colorParts) {
|
||||
if (!part.matches("^#[0-9A-Fa-f]{6}$")) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_give_prefix.invalid_color"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (text.length() > 15) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_give_prefix.too_long"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
Habbo target = Emulator.getGameEnvironment().getHabboManager().getHabbo(targetName);
|
||||
|
||||
if (target == null) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_give_prefix.user_not_found"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
UserPrefix prefix = new UserPrefix(target.getHabboInfo().getId(), text, color, icon, effect);
|
||||
prefix.run();
|
||||
target.getInventory().getPrefixesComponent().addPrefix(prefix);
|
||||
|
||||
target.getClient().sendResponse(new PrefixReceivedComposer(prefix));
|
||||
target.getClient().sendResponse(new UserPrefixesComposer(target));
|
||||
|
||||
gameClient.getHabbo().whisper(
|
||||
Emulator.getTexts().getValue("commands.succes.cmd_give_prefix")
|
||||
.replace("%user%", targetName)
|
||||
.replace("%prefix%", text),
|
||||
RoomChatMessageBubbles.ALERT
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.eu.habbo.habbohotel.commands;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomChatMessageBubbles;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.UserPrefix;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ListPrefixesCommand extends Command {
|
||||
public ListPrefixesCommand() {
|
||||
super("cmd_list_prefixes", Emulator.getTexts().getValue("commands.keys.cmd_list_prefixes").split(";"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(GameClient gameClient, String[] params) throws Exception {
|
||||
if (params.length < 2) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_list_prefixes.usage"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
String targetName = params[1];
|
||||
|
||||
Habbo target = Emulator.getGameEnvironment().getHabboManager().getHabbo(targetName);
|
||||
|
||||
if (target == null) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_list_prefixes.user_not_found"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
List<UserPrefix> prefixes = target.getInventory().getPrefixesComponent().getPrefixes();
|
||||
|
||||
if (prefixes.isEmpty()) {
|
||||
gameClient.getHabbo().whisper(
|
||||
Emulator.getTexts().getValue("commands.succes.cmd_list_prefixes.empty").replace("%user%", targetName),
|
||||
RoomChatMessageBubbles.ALERT
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(Emulator.getTexts().getValue("commands.succes.cmd_list_prefixes.header").replace("%user%", targetName)).append("\r");
|
||||
|
||||
for (UserPrefix prefix : prefixes) {
|
||||
sb.append("ID: ").append(prefix.getId())
|
||||
.append(" | {").append(prefix.getText()).append("}")
|
||||
.append(" | Color: ").append(prefix.getColor())
|
||||
.append(prefix.getIcon().isEmpty() ? "" : " | Icon: " + prefix.getIcon())
|
||||
.append(prefix.getEffect().isEmpty() ? "" : " | Effect: " + prefix.getEffect())
|
||||
.append(prefix.isActive() ? " [ACTIVE]" : "")
|
||||
.append("\r");
|
||||
}
|
||||
|
||||
gameClient.getHabbo().whisper(sb.toString(), RoomChatMessageBubbles.ALERT);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.eu.habbo.habbohotel.commands;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomChatMessageBubbles;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class PrefixBlacklistCommand extends Command {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PrefixBlacklistCommand.class);
|
||||
|
||||
public PrefixBlacklistCommand() {
|
||||
super("cmd_prefix_blacklist", Emulator.getTexts().getValue("commands.keys.cmd_prefix_blacklist").split(";"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(GameClient gameClient, String[] params) throws Exception {
|
||||
if (params.length < 2) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_prefix_blacklist.usage"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
String action = params[1].toLowerCase();
|
||||
|
||||
if (action.equals("list")) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(Emulator.getTexts().getValue("commands.succes.cmd_prefix_blacklist.header")).append("\r");
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT word FROM custom_prefix_blacklist ORDER BY word")) {
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
int count = 0;
|
||||
while (set.next()) {
|
||||
sb.append("- ").append(set.getString("word")).append("\r");
|
||||
count++;
|
||||
}
|
||||
if (count == 0) {
|
||||
sb.append(Emulator.getTexts().getValue("commands.succes.cmd_prefix_blacklist.empty"));
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Error listing prefix blacklist", e);
|
||||
}
|
||||
|
||||
gameClient.getHabbo().whisper(sb.toString(), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (params.length < 3) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_prefix_blacklist.usage"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
String word = params[2].toLowerCase().trim();
|
||||
|
||||
if (word.isEmpty()) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_prefix_blacklist.empty_word"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (action.equals("add")) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("INSERT INTO custom_prefix_blacklist (word) VALUES (?)")) {
|
||||
statement.setString(1, word);
|
||||
statement.execute();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Error adding prefix blacklist word", e);
|
||||
}
|
||||
|
||||
gameClient.getHabbo().whisper(
|
||||
Emulator.getTexts().getValue("commands.succes.cmd_prefix_blacklist.added").replace("%word%", word),
|
||||
RoomChatMessageBubbles.ALERT
|
||||
);
|
||||
} else if (action.equals("remove")) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("DELETE FROM custom_prefix_blacklist WHERE word = ?")) {
|
||||
statement.setString(1, word);
|
||||
statement.execute();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Error removing prefix blacklist word", e);
|
||||
}
|
||||
|
||||
gameClient.getHabbo().whisper(
|
||||
Emulator.getTexts().getValue("commands.succes.cmd_prefix_blacklist.removed").replace("%word%", word),
|
||||
RoomChatMessageBubbles.ALERT
|
||||
);
|
||||
} else {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_prefix_blacklist.usage"), RoomChatMessageBubbles.ALERT);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.eu.habbo.habbohotel.commands;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomChatMessageBubbles;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.UserPrefix;
|
||||
import com.eu.habbo.messages.outgoing.inventory.prefixes.UserPrefixesComposer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RemovePrefixCommand extends Command {
|
||||
public RemovePrefixCommand() {
|
||||
super("cmd_remove_prefix", Emulator.getTexts().getValue("commands.keys.cmd_remove_prefix").split(";"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(GameClient gameClient, String[] params) throws Exception {
|
||||
if (params.length < 3) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_remove_prefix.usage"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
String targetName = params[1];
|
||||
String prefixIdStr = params[2];
|
||||
|
||||
Habbo target = Emulator.getGameEnvironment().getHabboManager().getHabbo(targetName);
|
||||
|
||||
if (target == null) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_remove_prefix.user_not_found"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (prefixIdStr.equalsIgnoreCase("all")) {
|
||||
List<UserPrefix> prefixes = target.getInventory().getPrefixesComponent().getPrefixes();
|
||||
for (UserPrefix prefix : prefixes) {
|
||||
prefix.needsDelete(true);
|
||||
Emulator.getThreading().run(prefix);
|
||||
}
|
||||
// Clear in-memory
|
||||
for (UserPrefix prefix : prefixes) {
|
||||
target.getInventory().getPrefixesComponent().removePrefix(prefix);
|
||||
}
|
||||
|
||||
target.getClient().sendResponse(new UserPrefixesComposer(target));
|
||||
|
||||
gameClient.getHabbo().whisper(
|
||||
Emulator.getTexts().getValue("commands.succes.cmd_remove_prefix.all").replace("%user%", targetName),
|
||||
RoomChatMessageBubbles.ALERT
|
||||
);
|
||||
} else {
|
||||
int prefixId;
|
||||
try {
|
||||
prefixId = Integer.parseInt(prefixIdStr);
|
||||
} catch (NumberFormatException e) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_remove_prefix.invalid_id"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
UserPrefix prefix = target.getInventory().getPrefixesComponent().getPrefix(prefixId);
|
||||
|
||||
if (prefix == null) {
|
||||
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_remove_prefix.not_found"), RoomChatMessageBubbles.ALERT);
|
||||
return true;
|
||||
}
|
||||
|
||||
target.getInventory().getPrefixesComponent().removePrefix(prefix);
|
||||
prefix.needsDelete(true);
|
||||
Emulator.getThreading().run(prefix);
|
||||
|
||||
target.getClient().sendResponse(new UserPrefixesComposer(target));
|
||||
|
||||
gameClient.getHabbo().whisper(
|
||||
Emulator.getTexts().getValue("commands.succes.cmd_remove_prefix").replace("%user%", targetName).replace("%id%", String.valueOf(prefixId)),
|
||||
RoomChatMessageBubbles.ALERT
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ public class GameClient {
|
||||
private Habbo habbo;
|
||||
private boolean handshakeFinished;
|
||||
private String machineId = "";
|
||||
private String ssoTicket = "";
|
||||
|
||||
public final ConcurrentHashMap<Integer, Integer> incomingPacketCounter = new ConcurrentHashMap<>(25);
|
||||
public final ConcurrentHashMap<Class<? extends MessageHandler>, Long> messageTimestamps = new ConcurrentHashMap<>();
|
||||
@@ -82,6 +83,14 @@ public class GameClient {
|
||||
this.machineId = machineId;
|
||||
}
|
||||
|
||||
public String getSsoTicket() {
|
||||
return this.ssoTicket;
|
||||
}
|
||||
|
||||
public void setSsoTicket(String ssoTicket) {
|
||||
this.ssoTicket = ssoTicket != null ? ssoTicket : "";
|
||||
}
|
||||
|
||||
public void sendResponse(MessageComposer composer) {
|
||||
this.sendResponse(composer.compose());
|
||||
}
|
||||
@@ -145,8 +154,15 @@ public class GameClient {
|
||||
|
||||
if (this.habbo != null) {
|
||||
if (this.habbo.isOnline()) {
|
||||
this.habbo.getHabboInfo().setOnline(false);
|
||||
this.habbo.disconnect();
|
||||
// Try to park the habbo in the grace period instead of immediate disconnect
|
||||
boolean parked = SessionResumeManager.getInstance().parkHabbo(this.habbo, this.ssoTicket);
|
||||
|
||||
if (!parked) {
|
||||
// No grace period configured — immediate disconnect as before
|
||||
this.habbo.getHabboInfo().setOnline(false);
|
||||
this.habbo.disconnect();
|
||||
}
|
||||
// If parked, do NOT call disconnect() — the habbo stays in the room
|
||||
}
|
||||
|
||||
this.habbo = null;
|
||||
|
||||
@@ -116,6 +116,22 @@ public class GameClientManager {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find an existing GameClient that authenticated with the given SSO ticket.
|
||||
* Used to detect reconnections where the old connection hasn't been closed yet.
|
||||
*/
|
||||
public GameClient findClientBySsoTicket(String ssoTicket) {
|
||||
if (ssoTicket == null || ssoTicket.isEmpty()) return null;
|
||||
|
||||
for (GameClient client : this.clients.values()) {
|
||||
if (ssoTicket.equals(client.getSsoTicket()) && client.getHabbo() != null) {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public List<Habbo> getHabbosWithMachineId(String machineId) {
|
||||
List<Habbo> habbos = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
package com.eu.habbo.habbohotel.gameclients;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
/**
|
||||
* Manages a grace period for disconnected users. Instead of immediately
|
||||
* disposing a Habbo when their WebSocket drops, the Habbo is held in
|
||||
* a "ghost" state for a configurable number of seconds. If the same
|
||||
* user reconnects (via SSO ticket) within the grace window, their
|
||||
* existing Habbo object is resumed on the new connection — keeping
|
||||
* them in their room, preserving inventory state, etc.
|
||||
*
|
||||
* Config key: session.reconnect.grace.seconds (default: 30)
|
||||
*/
|
||||
public class SessionResumeManager {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SessionResumeManager.class);
|
||||
|
||||
private static SessionResumeManager instance;
|
||||
|
||||
private final ConcurrentHashMap<Integer, GhostSession> ghostSessions = new ConcurrentHashMap<>();
|
||||
|
||||
public static SessionResumeManager getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new SessionResumeManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public int getGracePeriodSeconds() {
|
||||
return Emulator.getConfig().getInt("session.reconnect.grace.seconds", 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* Park a disconnected Habbo in ghost mode. Their room presence is
|
||||
* preserved, but the old GameClient channel is closed.
|
||||
*
|
||||
* @return true if the habbo was parked (grace period > 0), false if immediate dispose should happen
|
||||
*/
|
||||
public boolean parkHabbo(Habbo habbo, String ssoTicket) {
|
||||
int graceSeconds = getGracePeriodSeconds();
|
||||
if (graceSeconds <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int userId = habbo.getHabboInfo().getId();
|
||||
|
||||
// Cancel any existing ghost session for this user
|
||||
GhostSession existing = ghostSessions.remove(userId);
|
||||
if (existing != null && existing.disposeFuture != null) {
|
||||
existing.disposeFuture.cancel(false);
|
||||
}
|
||||
|
||||
LOGGER.info("[SessionResume] Parking {} (id={}) for {}s grace period",
|
||||
habbo.getHabboInfo().getUsername(), userId, graceSeconds);
|
||||
|
||||
// Restore the SSO ticket so the client can reconnect with the same ticket
|
||||
if (ssoTicket != null && !ssoTicket.isEmpty()) {
|
||||
restoreSsoTicket(userId, ssoTicket);
|
||||
}
|
||||
|
||||
// Schedule the final disconnect after the grace period
|
||||
ScheduledFuture<?> future = Emulator.getThreading().run(() -> {
|
||||
GhostSession ghost = ghostSessions.remove(userId);
|
||||
if (ghost != null) {
|
||||
LOGGER.info("[SessionResume] Grace period expired for {} (id={}) - performing full disconnect",
|
||||
ghost.habbo.getHabboInfo().getUsername(), userId);
|
||||
performFullDisconnect(ghost.habbo);
|
||||
}
|
||||
}, graceSeconds * 1000);
|
||||
|
||||
ghostSessions.put(userId, new GhostSession(habbo, ssoTicket, future));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to resume a ghost session for the given user ID.
|
||||
*
|
||||
* @return the parked Habbo if found within grace period, null otherwise
|
||||
*/
|
||||
public Habbo resumeSession(int userId) {
|
||||
GhostSession ghost = ghostSessions.remove(userId);
|
||||
if (ghost == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Cancel the scheduled dispose
|
||||
if (ghost.disposeFuture != null) {
|
||||
ghost.disposeFuture.cancel(false);
|
||||
}
|
||||
|
||||
LOGGER.info("[SessionResume] Resuming session for {} (id={})",
|
||||
ghost.habbo.getHabboInfo().getUsername(), userId);
|
||||
|
||||
return ghost.habbo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user has a ghost session (is in grace period).
|
||||
*/
|
||||
public boolean hasGhostSession(int userId) {
|
||||
return ghostSessions.containsKey(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately expire all ghost sessions (e.g. on emulator shutdown).
|
||||
*/
|
||||
public void disposeAll() {
|
||||
for (GhostSession ghost : ghostSessions.values()) {
|
||||
if (ghost.disposeFuture != null) {
|
||||
ghost.disposeFuture.cancel(false);
|
||||
}
|
||||
performFullDisconnect(ghost.habbo);
|
||||
}
|
||||
ghostSessions.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual full disconnect that normally happens in Habbo.disconnect().
|
||||
*/
|
||||
private void performFullDisconnect(Habbo habbo) {
|
||||
try {
|
||||
habbo.getHabboInfo().setOnline(false);
|
||||
habbo.disconnect();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("[SessionResume] Error during deferred disconnect", e);
|
||||
}
|
||||
|
||||
// Clear the SSO ticket now that the grace period is truly over
|
||||
clearSsoTicket(habbo.getHabboInfo().getId());
|
||||
}
|
||||
|
||||
private void restoreSsoTicket(int userId, String ssoTicket) {
|
||||
try (var connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
var statement = connection.prepareStatement("UPDATE users SET auth_ticket = ? WHERE id = ? LIMIT 1")) {
|
||||
statement.setString(1, ssoTicket);
|
||||
statement.setInt(2, userId);
|
||||
statement.execute();
|
||||
LOGGER.info("[SessionResume] Restored SSO ticket for user {} during grace period", userId);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("[SessionResume] Failed to restore SSO ticket for user " + userId, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearSsoTicket(int userId) {
|
||||
try (var connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
var statement = connection.prepareStatement("UPDATE users SET auth_ticket = ? WHERE id = ? LIMIT 1")) {
|
||||
statement.setString(1, "");
|
||||
statement.setInt(2, userId);
|
||||
statement.execute();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("[SessionResume] Failed to clear SSO ticket for user " + userId, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class GhostSession {
|
||||
final Habbo habbo;
|
||||
final String ssoTicket;
|
||||
final ScheduledFuture<?> disposeFuture;
|
||||
|
||||
GhostSession(Habbo habbo, String ssoTicket, ScheduledFuture<?> disposeFuture) {
|
||||
this.habbo = habbo;
|
||||
this.ssoTicket = ssoTicket;
|
||||
this.disposeFuture = disposeFuture;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,29 +49,13 @@ import com.eu.habbo.habbohotel.items.interactions.totems.InteractionTotemLegs;
|
||||
import com.eu.habbo.habbohotel.items.interactions.totems.InteractionTotemPlanet;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.conditions.*;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.effects.*;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectFurniArea;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectUsersArea;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectUsersNeighborhood;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectFurniNeighborhood;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectFurniByType;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectFurniAltitude;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectFurniOnFurni;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectFurniPicks;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectFurniSignal;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectUsersSignal;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectUsersByType;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectUsersTeam;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectUsersByAction;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectUsersByName;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectUsersHandItem;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectUsersOnFurni;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.WiredEffectUsersGroup;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredBlob;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterFurni;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterUser;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraOrEval;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraRandom;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraUnseen;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.*;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.triggers.*;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
|
||||
+8
@@ -164,6 +164,14 @@ public class WiredConditionHabboHasHandItem extends InteractionWiredCondition {
|
||||
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL;
|
||||
}
|
||||
|
||||
protected int getHandItem() {
|
||||
return this.handItem;
|
||||
}
|
||||
|
||||
protected int getUserSource() {
|
||||
return this.userSource;
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
int handItemId;
|
||||
int userSource;
|
||||
|
||||
+17
-10
@@ -19,7 +19,6 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class WiredTriggerFurniStateToggled extends InteractionWiredTrigger {
|
||||
private static final WiredTriggerType type = WiredTriggerType.STATE_CHANGED;
|
||||
@@ -60,7 +59,6 @@ public class WiredTriggerFurniStateToggled extends InteractionWiredTrigger {
|
||||
if (snapshot == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return snapshot.state.equals(this.normalizeState(sourceItem.getExtradata()));
|
||||
}
|
||||
|
||||
@@ -234,15 +232,24 @@ public class WiredTriggerFurniStateToggled extends InteractionWiredTrigger {
|
||||
}
|
||||
|
||||
private boolean matchesSourceItem(WiredEvent event, HabboItem sourceItem) {
|
||||
List<HabboItem> selectedItems = event.getRoom() == null
|
||||
? new ArrayList<>()
|
||||
: this.snapshots.stream()
|
||||
.map(snapshot -> event.getRoom().getHabboItem(snapshot.itemId))
|
||||
.filter(item -> item != null)
|
||||
.collect(Collectors.toList());
|
||||
List<HabboItem> selectedItems = new ArrayList<>();
|
||||
|
||||
return WiredTriggerSourceUtil.resolveItems(this, event, this.furniSource, selectedItems).stream()
|
||||
.anyMatch(item -> item != null && item.getId() == sourceItem.getId());
|
||||
if (event.getRoom() != null) {
|
||||
for (StateSnapshot snapshot : this.snapshots) {
|
||||
HabboItem item = event.getRoom().getHabboItem(snapshot.itemId);
|
||||
if (item != null) {
|
||||
selectedItems.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (HabboItem item : WiredTriggerSourceUtil.resolveItems(this, event, this.furniSource, selectedItems)) {
|
||||
if (item != null && item.getId() == sourceItem.getId()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int normalizeFurniSource(int value) {
|
||||
|
||||
@@ -202,6 +202,25 @@ public class RoomChatMessage implements Runnable, ISerialize, DatabaseLoggable {
|
||||
message.appendInt(0);
|
||||
message.appendString(this.RoomChatColour); //Added packet for room chat
|
||||
message.appendInt(this.getMessage().length());
|
||||
|
||||
// Custom prefix data
|
||||
String prefixText = "";
|
||||
String prefixColor = "";
|
||||
String prefixIcon = "";
|
||||
String prefixEffect = "";
|
||||
if (this.habbo != null && this.habbo.getInventory() != null && this.habbo.getInventory().getPrefixesComponent() != null) {
|
||||
com.eu.habbo.habbohotel.users.UserPrefix activePrefix = this.habbo.getInventory().getPrefixesComponent().getActivePrefix();
|
||||
if (activePrefix != null) {
|
||||
prefixText = activePrefix.getText();
|
||||
prefixColor = activePrefix.getColor();
|
||||
prefixIcon = activePrefix.getIcon();
|
||||
prefixEffect = activePrefix.getEffect();
|
||||
}
|
||||
}
|
||||
message.appendString(prefixText);
|
||||
message.appendString(prefixColor);
|
||||
message.appendString(prefixIcon);
|
||||
message.appendString(prefixEffect);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Caught exception", e);
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ public class RoomManager {
|
||||
/**
|
||||
* Loads a room, optionally loading its data.
|
||||
* If the room is already being loaded in the background, this will wait for that to complete.
|
||||
*
|
||||
*
|
||||
* @param id The room ID
|
||||
* @param loadData Whether to load room data (items, bots, pets, etc.)
|
||||
* @return The loaded room, or null if not found
|
||||
@@ -499,14 +499,18 @@ public class RoomManager {
|
||||
}
|
||||
|
||||
public void enterRoom(Habbo habbo, int roomId, String password) {
|
||||
this.enterRoom(habbo, roomId, password, false, null);
|
||||
this.enterRoom(habbo, roomId, password, false, null, false);
|
||||
}
|
||||
|
||||
public void enterRoom(Habbo habbo, int roomId, String password, boolean overrideChecks) {
|
||||
this.enterRoom(habbo, roomId, password, overrideChecks, null);
|
||||
this.enterRoom(habbo, roomId, password, overrideChecks, null, false);
|
||||
}
|
||||
|
||||
public void enterRoom(Habbo habbo, int roomId, String password, boolean overrideChecks, RoomTile doorLocation) {
|
||||
this.enterRoom(habbo, roomId, password, overrideChecks, doorLocation, false);
|
||||
}
|
||||
|
||||
public void enterRoom(Habbo habbo, int roomId, String password, boolean overrideChecks, RoomTile doorLocation, boolean isReconnectSpawn) {
|
||||
Room room = this.loadRoom(roomId, true);
|
||||
|
||||
if (room == null)
|
||||
@@ -547,7 +551,7 @@ public class RoomManager {
|
||||
room.hasRights(habbo) ||
|
||||
(room.getState().equals(RoomState.INVISIBLE) && room.hasRights(habbo)) ||
|
||||
(room.hasGuild() && room.getGuildRightLevel(habbo).isGreaterThan(RoomRightLevels.GUILD_RIGHTS))) {
|
||||
this.openRoom(habbo, room, doorLocation);
|
||||
this.openRoom(habbo, room, doorLocation, isReconnectSpawn);
|
||||
} else if (room.getState() == RoomState.LOCKED) {
|
||||
boolean rightsFound = false;
|
||||
|
||||
@@ -572,7 +576,7 @@ public class RoomManager {
|
||||
room.addToQueue(habbo);
|
||||
} else if (room.getState() == RoomState.PASSWORD) {
|
||||
if (room.getPassword().equalsIgnoreCase(password))
|
||||
this.openRoom(habbo, room, doorLocation);
|
||||
this.openRoom(habbo, room, doorLocation, isReconnectSpawn);
|
||||
else {
|
||||
habbo.getClient().sendResponse(new GenericErrorMessagesComposer(GenericErrorMessagesComposer.WRONG_PASSWORD_USED));
|
||||
habbo.getClient().sendResponse(new HotelViewComposer());
|
||||
@@ -585,6 +589,10 @@ public class RoomManager {
|
||||
}
|
||||
|
||||
void openRoom(Habbo habbo, Room room, RoomTile doorLocation) {
|
||||
this.openRoom(habbo, room, doorLocation, false);
|
||||
}
|
||||
|
||||
void openRoom(Habbo habbo, Room room, RoomTile doorLocation, boolean isReconnectSpawn) {
|
||||
if (room == null || room.getLayout() == null)
|
||||
return;
|
||||
|
||||
@@ -623,7 +631,13 @@ public class RoomManager {
|
||||
if (doorLocation == null) {
|
||||
habbo.getRoomUnit().setBodyRotation(RoomUserRotation.values()[room.getLayout().getDoorDirection()]);
|
||||
habbo.getRoomUnit().setHeadRotation(RoomUserRotation.values()[room.getLayout().getDoorDirection()]);
|
||||
} else if (isReconnectSpawn) {
|
||||
// Reconnect spawn: place at tile but keep normal room behavior
|
||||
// (user can still leave by door, no teleport flags)
|
||||
habbo.getRoomUnit().setBodyRotation(RoomUserRotation.values()[room.getLayout().getDoorDirection()]);
|
||||
habbo.getRoomUnit().setHeadRotation(RoomUserRotation.values()[room.getLayout().getDoorDirection()]);
|
||||
} else {
|
||||
// Furniture teleport spawn
|
||||
habbo.getRoomUnit().setCanLeaveRoomByDoor(false);
|
||||
habbo.getRoomUnit().isTeleporting = true;
|
||||
HabboItem topItem = room.getTopItemAt(doorLocation.x, doorLocation.y);
|
||||
|
||||
@@ -22,6 +22,7 @@ public class HabboInventory {
|
||||
private EffectsComponent effectsComponent;
|
||||
private ItemsComponent itemsComponent;
|
||||
private PetsComponent petsComponent;
|
||||
private PrefixesComponent prefixesComponent;
|
||||
|
||||
public HabboInventory(Habbo habbo) {
|
||||
this.habbo = habbo;
|
||||
@@ -61,6 +62,12 @@ public class HabboInventory {
|
||||
LOGGER.error("Caught exception", e);
|
||||
}
|
||||
|
||||
try {
|
||||
this.prefixesComponent = new PrefixesComponent(this.habbo);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Caught exception", e);
|
||||
}
|
||||
|
||||
this.items = MarketPlace.getOwnOffers(this.habbo);
|
||||
}
|
||||
|
||||
@@ -112,6 +119,14 @@ public class HabboInventory {
|
||||
this.petsComponent = petsComponent;
|
||||
}
|
||||
|
||||
public PrefixesComponent getPrefixesComponent() {
|
||||
return this.prefixesComponent;
|
||||
}
|
||||
|
||||
public void setPrefixesComponent(PrefixesComponent prefixesComponent) {
|
||||
this.prefixesComponent = prefixesComponent;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
this.badgesComponent.dispose();
|
||||
this.botsComponent.dispose();
|
||||
@@ -119,6 +134,7 @@ public class HabboInventory {
|
||||
this.itemsComponent.dispose();
|
||||
this.petsComponent.dispose();
|
||||
this.wardrobeComponent.dispose();
|
||||
this.prefixesComponent.dispose();
|
||||
|
||||
this.badgesComponent = null;
|
||||
this.botsComponent = null;
|
||||
@@ -126,6 +142,7 @@ public class HabboInventory {
|
||||
this.itemsComponent = null;
|
||||
this.petsComponent = null;
|
||||
this.wardrobeComponent = null;
|
||||
this.prefixesComponent = null;
|
||||
}
|
||||
|
||||
public void addMarketplaceOffer(MarketPlaceOffer marketPlaceOffer) {
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.eu.habbo.habbohotel.users;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
public class UserPrefix implements Runnable {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(UserPrefix.class);
|
||||
|
||||
private int id;
|
||||
private final int userId;
|
||||
private String text;
|
||||
private String color;
|
||||
private String icon;
|
||||
private String effect;
|
||||
private boolean active;
|
||||
private boolean needsInsert;
|
||||
private boolean needsUpdate;
|
||||
private boolean needsDelete;
|
||||
|
||||
public UserPrefix(ResultSet set) throws SQLException {
|
||||
this.id = set.getInt("id");
|
||||
this.userId = set.getInt("user_id");
|
||||
this.text = set.getString("text");
|
||||
this.color = set.getString("color");
|
||||
this.icon = set.getString("icon");
|
||||
if (this.icon == null) this.icon = "";
|
||||
this.effect = set.getString("effect");
|
||||
if (this.effect == null) this.effect = "";
|
||||
this.active = set.getBoolean("active");
|
||||
this.needsInsert = false;
|
||||
this.needsUpdate = false;
|
||||
this.needsDelete = false;
|
||||
}
|
||||
|
||||
public UserPrefix(int userId, String text, String color, String icon, String effect) {
|
||||
this.id = 0;
|
||||
this.userId = userId;
|
||||
this.text = text;
|
||||
this.color = color;
|
||||
this.icon = icon != null ? icon : "";
|
||||
this.effect = effect != null ? effect : "";
|
||||
this.active = false;
|
||||
this.needsInsert = true;
|
||||
this.needsUpdate = false;
|
||||
this.needsDelete = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (this.needsInsert) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(
|
||||
"INSERT INTO user_prefixes (user_id, text, color, icon, effect, active) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
Statement.RETURN_GENERATED_KEYS)) {
|
||||
statement.setInt(1, this.userId);
|
||||
statement.setString(2, this.text);
|
||||
statement.setString(3, this.color);
|
||||
statement.setString(4, this.icon);
|
||||
statement.setString(5, this.effect);
|
||||
statement.setBoolean(6, this.active);
|
||||
statement.execute();
|
||||
try (ResultSet set = statement.getGeneratedKeys()) {
|
||||
if (set.next()) {
|
||||
this.id = set.getInt(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.needsInsert = false;
|
||||
} else if (this.needsDelete) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(
|
||||
"DELETE FROM user_prefixes WHERE id = ? AND user_id = ?")) {
|
||||
statement.setInt(1, this.id);
|
||||
statement.setInt(2, this.userId);
|
||||
statement.execute();
|
||||
}
|
||||
this.needsDelete = false;
|
||||
} else if (this.needsUpdate) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(
|
||||
"UPDATE user_prefixes SET text = ?, color = ?, icon = ?, effect = ?, active = ? WHERE id = ? AND user_id = ?")) {
|
||||
statement.setString(1, this.text);
|
||||
statement.setString(2, this.color);
|
||||
statement.setString(3, this.icon);
|
||||
statement.setString(4, this.effect);
|
||||
statement.setBoolean(5, this.active);
|
||||
statement.setInt(6, this.id);
|
||||
statement.setInt(7, this.userId);
|
||||
statement.execute();
|
||||
}
|
||||
this.needsUpdate = false;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getId() { return this.id; }
|
||||
public int getUserId() { return this.userId; }
|
||||
public String getText() { return this.text; }
|
||||
public void setText(String text) { this.text = text; }
|
||||
public String getColor() { return this.color; }
|
||||
public void setColor(String color) { this.color = color; }
|
||||
public String getIcon() { return this.icon; }
|
||||
public void setIcon(String icon) { this.icon = icon != null ? icon : ""; }
|
||||
public String getEffect() { return this.effect; }
|
||||
public void setEffect(String effect) { this.effect = effect != null ? effect : ""; }
|
||||
public boolean isActive() { return this.active; }
|
||||
|
||||
public void setActive(boolean active) {
|
||||
this.active = active;
|
||||
this.needsUpdate = true;
|
||||
}
|
||||
|
||||
public void needsUpdate(boolean needsUpdate) { this.needsUpdate = needsUpdate; }
|
||||
public void needsInsert(boolean needsInsert) { this.needsInsert = needsInsert; }
|
||||
public void needsDelete(boolean needsDelete) { this.needsDelete = needsDelete; }
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package com.eu.habbo.habbohotel.users.inventory;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.UserPrefix;
|
||||
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.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PrefixesComponent {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PrefixesComponent.class);
|
||||
|
||||
private final List<UserPrefix> prefixes = new ArrayList<>();
|
||||
private final Habbo habbo;
|
||||
|
||||
public PrefixesComponent(Habbo habbo) {
|
||||
this.habbo = habbo;
|
||||
this.loadPrefixes();
|
||||
}
|
||||
|
||||
private void loadPrefixes() {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT * FROM user_prefixes WHERE user_id = ?")) {
|
||||
statement.setInt(1, this.habbo.getHabboInfo().getId());
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
while (set.next()) {
|
||||
this.prefixes.add(new UserPrefix(set));
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<UserPrefix> getPrefixes() {
|
||||
synchronized (this.prefixes) {
|
||||
return new ArrayList<>(this.prefixes);
|
||||
}
|
||||
}
|
||||
|
||||
public UserPrefix getActivePrefix() {
|
||||
synchronized (this.prefixes) {
|
||||
for (UserPrefix prefix : this.prefixes) {
|
||||
if (prefix.isActive()) return prefix;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public UserPrefix getPrefix(int id) {
|
||||
synchronized (this.prefixes) {
|
||||
for (UserPrefix prefix : this.prefixes) {
|
||||
if (prefix.getId() == id) return prefix;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addPrefix(UserPrefix prefix) {
|
||||
synchronized (this.prefixes) {
|
||||
this.prefixes.add(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
public void removePrefix(UserPrefix prefix) {
|
||||
synchronized (this.prefixes) {
|
||||
this.prefixes.remove(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
public void setActive(int prefixId) {
|
||||
synchronized (this.prefixes) {
|
||||
for (UserPrefix prefix : this.prefixes) {
|
||||
boolean shouldBeActive = prefix.getId() == prefixId;
|
||||
if (prefix.isActive() != shouldBeActive) {
|
||||
prefix.setActive(shouldBeActive);
|
||||
Emulator.getThreading().run(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivateAll() {
|
||||
synchronized (this.prefixes) {
|
||||
for (UserPrefix prefix : this.prefixes) {
|
||||
if (prefix.isActive()) {
|
||||
prefix.setActive(false);
|
||||
Emulator.getThreading().run(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
synchronized (this.prefixes) {
|
||||
this.prefixes.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -296,7 +296,6 @@ public final class WiredManager {
|
||||
private static String getPendingFurniClickKey(Room room, RoomUnit user, HabboItem item) {
|
||||
return room.getId() + ":" + user.getId() + ":" + item.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger when a user clicks invisible click tile furniture.
|
||||
*/
|
||||
@@ -318,7 +317,6 @@ public final class WiredManager {
|
||||
}
|
||||
|
||||
WiredTriggerHabboClicksUser.clearRuntimeFlags(clickingUser);
|
||||
|
||||
WiredEvent event = WiredEvents.userClicksUser(room, clickingUser, clickedUser);
|
||||
return handleEvent(event);
|
||||
}
|
||||
@@ -444,6 +442,30 @@ public final class WiredManager {
|
||||
return handleEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a long periodic timer.
|
||||
*/
|
||||
public static boolean triggerTimerRepeatLong(Room room, HabboItem timerItem) {
|
||||
if (!isEnabled() || room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WiredEvent event = WiredEvents.timerRepeatLong(room, timerItem);
|
||||
return handleEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a short periodic timer.
|
||||
*/
|
||||
public static boolean triggerTimerRepeatShort(Room room, HabboItem timerItem) {
|
||||
if (!isEnabled() || room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WiredEvent event = WiredEvents.timerRepeatShort(room, timerItem);
|
||||
return handleEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger game start.
|
||||
*/
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.eu.habbo.messages.incoming.helper.MySanctionStatusEvent;
|
||||
import com.eu.habbo.messages.incoming.helper.RequestTalentTrackEvent;
|
||||
import com.eu.habbo.messages.incoming.hotelview.*;
|
||||
import com.eu.habbo.messages.incoming.inventory.*;
|
||||
import com.eu.habbo.messages.incoming.inventory.prefixes.*;
|
||||
import com.eu.habbo.messages.incoming.modtool.*;
|
||||
import com.eu.habbo.messages.incoming.navigator.*;
|
||||
import com.eu.habbo.messages.incoming.polls.AnswerPollEvent;
|
||||
@@ -370,6 +371,12 @@ public class PacketManager {
|
||||
this.registerHandler(Incoming.RequestInventoryPetsEvent, RequestInventoryPetsEvent.class);
|
||||
this.registerHandler(Incoming.RequestInventoryPetDelete, RequestInventoryPetDelete.class);
|
||||
this.registerHandler(Incoming.RequestInventoryBadgeDelete, RequestInventoryBadgeDelete.class);
|
||||
|
||||
// Custom Prefixes
|
||||
this.registerHandler(Incoming.RequestUserPrefixesEvent, RequestUserPrefixesEvent.class);
|
||||
this.registerHandler(Incoming.SetActivePrefixEvent, SetActivePrefixEvent.class);
|
||||
this.registerHandler(Incoming.DeletePrefixEvent, DeletePrefixEvent.class);
|
||||
this.registerHandler(Incoming.PurchasePrefixEvent, PurchasePrefixEvent.class);
|
||||
}
|
||||
|
||||
void registerRooms() throws Exception {
|
||||
|
||||
@@ -380,7 +380,7 @@ public class Incoming {
|
||||
|
||||
public static final int UNKNOWN_SNOWSTORM_6000 = 6000;
|
||||
public static final int UNKNOWN_SNOWSTORM_6001 = 6001;
|
||||
public static final int UNKNOWN_SNOWSTORM_6002 = 6002;
|
||||
// public static final int UNKNOWN_SNOWSTORM_6002 = 6002;
|
||||
public static final int UNKNOWN_SNOWSTORM_6003 = 6003;
|
||||
public static final int UNKNOWN_SNOWSTORM_6004 = 6004;
|
||||
public static final int UNKNOWN_SNOWSTORM_6005 = 6005;
|
||||
@@ -411,4 +411,10 @@ public class Incoming {
|
||||
public static final int ClickUserEvent = 10020;
|
||||
public static final int RequestInventoryPetDelete = 10030;
|
||||
public static final int RequestInventoryBadgeDelete = 10031;
|
||||
|
||||
// Custom Prefixes
|
||||
public static final int RequestUserPrefixesEvent = 7011;
|
||||
public static final int SetActivePrefixEvent = 7012;
|
||||
public static final int DeletePrefixEvent = 7013;
|
||||
public static final int PurchasePrefixEvent = 7014;
|
||||
}
|
||||
|
||||
+5
@@ -9,6 +9,11 @@ import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
|
||||
public class PurchaseTargetOfferEvent extends MessageHandler {
|
||||
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
final int offerId = this.packet.readInt();
|
||||
|
||||
+5
@@ -4,6 +4,11 @@ import com.eu.habbo.habbohotel.catalog.marketplace.MarketPlace;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
|
||||
public class BuyItemEvent extends MessageHandler {
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
int offerId = this.packet.readInt();
|
||||
|
||||
+5
@@ -4,6 +4,11 @@ import com.eu.habbo.habbohotel.catalog.marketplace.MarketPlace;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
|
||||
public class RequestCreditsEvent extends MessageHandler {
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 2000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
MarketPlace.getCredits(this.client);
|
||||
|
||||
+5
@@ -4,6 +4,11 @@ import com.eu.habbo.habbohotel.catalog.marketplace.MarketPlace;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
|
||||
public class TakeBackItemEvent extends MessageHandler {
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 500;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
int offerId = this.packet.readInt();
|
||||
|
||||
+136
-50
@@ -2,10 +2,13 @@ package com.eu.habbo.messages.incoming.handshake;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.messenger.Messenger;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.gameclients.SessionResumeManager;
|
||||
import com.eu.habbo.habbohotel.modtool.ModToolSanctionItem;
|
||||
import com.eu.habbo.habbohotel.modtool.ModToolSanctions;
|
||||
import com.eu.habbo.habbohotel.navigation.NavigatorSavedSearch;
|
||||
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomManager;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboManager;
|
||||
@@ -14,6 +17,7 @@ import com.eu.habbo.habbohotel.users.subscriptions.SubscriptionHabboClub;
|
||||
import com.eu.habbo.messages.NoAuthMessage;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
import com.eu.habbo.messages.outgoing.commands.AvailableCommandsComposer;
|
||||
import com.eu.habbo.messages.outgoing.gamecenter.GameCenterAccountInfoComposer;
|
||||
import com.eu.habbo.messages.outgoing.gamecenter.GameCenterGameListComposer;
|
||||
import com.eu.habbo.messages.outgoing.generic.alerts.GenericAlertComposer;
|
||||
@@ -81,31 +85,94 @@ public class SecureLoginEvent extends MessageHandler {
|
||||
}
|
||||
|
||||
if (this.client.getHabbo() == null) {
|
||||
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().loadHabbo(sso);
|
||||
// Store SSO ticket on client for grace period tracking
|
||||
this.client.setSsoTicket(sso);
|
||||
|
||||
// Race condition fix: if the old WebSocket connection is still alive on the
|
||||
// server when the client reconnects, the SSO ticket won't be in the DB yet
|
||||
// (it was cleared on first login, and parkHabbo hasn't run because the old
|
||||
// channel hasn't closed). Find the old client by SSO ticket and force-dispose
|
||||
// it, which parks the habbo and restores the ticket to the DB.
|
||||
GameClient existingClient = Emulator.getGameServer().getGameClientManager().findClientBySsoTicket(sso);
|
||||
if (existingClient != null && existingClient != this.client) {
|
||||
LOGGER.info("[SessionResume] Found existing client with same SSO ticket — disposing old connection to trigger parking");
|
||||
Emulator.getGameServer().getGameClientManager().disposeClient(existingClient);
|
||||
}
|
||||
|
||||
// First, look up the user ID to check for ghost sessions
|
||||
int lookupUserId = 0;
|
||||
try (java.sql.Connection conn = Emulator.getDatabase().getDataSource().getConnection();
|
||||
java.sql.PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE auth_ticket = ? LIMIT 1")) {
|
||||
stmt.setString(1, sso);
|
||||
try (java.sql.ResultSet rs = stmt.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
lookupUserId = rs.getInt("id");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Caught exception looking up user for session resume", e);
|
||||
}
|
||||
|
||||
// Check if this user has a ghost session (disconnected within grace period)
|
||||
Habbo habbo = null;
|
||||
boolean isSessionResume = false;
|
||||
|
||||
if (lookupUserId > 0) {
|
||||
habbo = SessionResumeManager.getInstance().resumeSession(lookupUserId);
|
||||
}
|
||||
|
||||
if (habbo != null) {
|
||||
try {
|
||||
habbo.setClient(this.client);
|
||||
this.client.setHabbo(habbo);
|
||||
if(!this.client.getHabbo().connect()) {
|
||||
// Session resume — reattach the existing Habbo to the new client
|
||||
isSessionResume = true;
|
||||
LOGGER.info("[SessionResume] Resuming session for {} (id={})",
|
||||
habbo.getHabboInfo().getUsername(), habbo.getHabboInfo().getId());
|
||||
|
||||
habbo.setClient(this.client);
|
||||
this.client.setHabbo(habbo);
|
||||
this.client.setMachineId(habbo.getHabboInfo().getMachineID());
|
||||
|
||||
// Clear the SSO ticket now that session is resumed (prevent reuse)
|
||||
if (!Emulator.debugging) {
|
||||
try (java.sql.Connection conn = Emulator.getDatabase().getDataSource().getConnection();
|
||||
java.sql.PreparedStatement stmt = conn.prepareStatement("UPDATE users SET auth_ticket = ? WHERE id = ? LIMIT 1")) {
|
||||
stmt.setString(1, "");
|
||||
stmt.setInt(2, habbo.getHabboInfo().getId());
|
||||
stmt.execute();
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to clear SSO ticket after session resume", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Normal login — load from database
|
||||
habbo = Emulator.getGameEnvironment().getHabboManager().loadHabbo(sso);
|
||||
}
|
||||
|
||||
if (habbo != null) {
|
||||
if (!isSessionResume) {
|
||||
try {
|
||||
habbo.setClient(this.client);
|
||||
this.client.setHabbo(habbo);
|
||||
if(!this.client.getHabbo().connect()) {
|
||||
Emulator.getGameServer().getGameClientManager().disposeClient(this.client);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.client.getHabbo().getHabboInfo() == null) {
|
||||
Emulator.getGameServer().getGameClientManager().disposeClient(this.client);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.client.getHabbo().getHabboInfo().getRank() == null) {
|
||||
throw new NullPointerException(habbo.getHabboInfo().getUsername() + " has a NON EXISTING RANK!");
|
||||
}
|
||||
|
||||
Emulator.getThreading().run(habbo);
|
||||
Emulator.getGameEnvironment().getHabboManager().addHabbo(habbo);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Caught exception", e);
|
||||
Emulator.getGameServer().getGameClientManager().disposeClient(this.client);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.client.getHabbo().getHabboInfo() == null) {
|
||||
Emulator.getGameServer().getGameClientManager().disposeClient(this.client);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.client.getHabbo().getHabboInfo().getRank() == null) {
|
||||
throw new NullPointerException(habbo.getHabboInfo().getUsername() + " has a NON EXISTING RANK!");
|
||||
}
|
||||
|
||||
Emulator.getThreading().run(habbo);
|
||||
Emulator.getGameEnvironment().getHabboManager().addHabbo(habbo);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Caught exception", e);
|
||||
Emulator.getGameServer().getGameClientManager().disposeClient(this.client);
|
||||
return;
|
||||
}
|
||||
|
||||
if(ClothingValidationManager.VALIDATE_ON_LOGIN) {
|
||||
@@ -121,7 +188,18 @@ public class SecureLoginEvent extends MessageHandler {
|
||||
|
||||
int roomIdToEnter = 0;
|
||||
|
||||
if (!this.client.getHabbo().getHabboStats().nux || Emulator.getConfig().getBoolean("retro.style.homeroom") && this.client.getHabbo().getHabboInfo().getHomeRoom() != 0)
|
||||
if (isSessionResume) {
|
||||
// On session resume, DON'T set roomIdToEnter. The client keeps its
|
||||
// existing room view alive and the habbo is already in the room on
|
||||
// the server. Setting roomIdToEnter = 0 prevents UserHomeRoomComposer
|
||||
// from triggering a full room re-entry on the client (which would
|
||||
// tear down and rebuild the room view).
|
||||
Room currentRoom = habbo.getHabboInfo().getCurrentRoom();
|
||||
if (currentRoom != null) {
|
||||
LOGGER.info("[SessionResume] {} is still in room {} — client will resume in-place",
|
||||
habbo.getHabboInfo().getUsername(), currentRoom.getId());
|
||||
}
|
||||
} else if (!this.client.getHabbo().getHabboStats().nux || Emulator.getConfig().getBoolean("retro.style.homeroom") && this.client.getHabbo().getHabboInfo().getHomeRoom() != 0)
|
||||
roomIdToEnter = this.client.getHabbo().getHabboInfo().getHomeRoom();
|
||||
else if (!this.client.getHabbo().getHabboStats().nux || Emulator.getConfig().getBoolean("retro.style.homeroom") && RoomManager.HOME_ROOM_ID > 0)
|
||||
roomIdToEnter = RoomManager.HOME_ROOM_ID;
|
||||
@@ -131,6 +209,11 @@ public class SecureLoginEvent extends MessageHandler {
|
||||
messages.add(new UserClothesComposer(this.client.getHabbo()).compose());
|
||||
messages.add(new NewUserIdentityComposer(habbo).compose());
|
||||
messages.add(new UserPermissionsComposer(this.client.getHabbo()).compose());
|
||||
messages.add(new AvailableCommandsComposer(
|
||||
Emulator.getGameEnvironment().getCommandHandler().getCommandsForRank(
|
||||
this.client.getHabbo().getHabboInfo().getRank().getId()
|
||||
)
|
||||
).compose());
|
||||
messages.add(new AvailabilityStatusMessageComposer(true, false, true).compose());
|
||||
messages.add(new PingComposer().compose());
|
||||
messages.add(new EnableNotificationsComposer(Emulator.getConfig().getBoolean("bubblealerts.enabled", true)).compose());
|
||||
@@ -189,42 +272,45 @@ public class SecureLoginEvent extends MessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
UserLoginEvent userLoginEvent = new UserLoginEvent(habbo, this.client.getHabbo().getHabboInfo().getIpLogin());
|
||||
Emulator.getPluginManager().fireEvent(userLoginEvent);
|
||||
// Skip login-only events on session resume (welcome alerts, login events, etc.)
|
||||
if (!isSessionResume) {
|
||||
UserLoginEvent userLoginEvent = new UserLoginEvent(habbo, this.client.getHabbo().getHabboInfo().getIpLogin());
|
||||
Emulator.getPluginManager().fireEvent(userLoginEvent);
|
||||
|
||||
if(userLoginEvent.isCancelled()) {
|
||||
Emulator.getGameServer().getGameClientManager().disposeClient(this.client);
|
||||
return;
|
||||
}
|
||||
if(userLoginEvent.isCancelled()) {
|
||||
Emulator.getGameServer().getGameClientManager().disposeClient(this.client);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Emulator.getConfig().getBoolean("hotel.welcome.alert.enabled")) {
|
||||
final Habbo finalHabbo = habbo;
|
||||
Emulator.getThreading().run(() -> {
|
||||
if (Emulator.getConfig().getBoolean("hotel.welcome.alert.oldstyle")) {
|
||||
SecureLoginEvent.this.client.sendResponse(new MessagesForYouComposer(HabboManager.WELCOME_MESSAGE.replace("%username%", finalHabbo.getHabboInfo().getUsername()).replace("%user%", finalHabbo.getHabboInfo().getUsername()).split("<br/>")));
|
||||
} else {
|
||||
SecureLoginEvent.this.client.sendResponse(new GenericAlertComposer(HabboManager.WELCOME_MESSAGE.replace("%username%", finalHabbo.getHabboInfo().getUsername()).replace("%user%", finalHabbo.getHabboInfo().getUsername())));
|
||||
}
|
||||
}, Emulator.getConfig().getInt("hotel.welcome.alert.delay", 5000));
|
||||
}
|
||||
if (Emulator.getConfig().getBoolean("hotel.welcome.alert.enabled")) {
|
||||
final Habbo finalHabbo = habbo;
|
||||
Emulator.getThreading().run(() -> {
|
||||
if (Emulator.getConfig().getBoolean("hotel.welcome.alert.oldstyle")) {
|
||||
SecureLoginEvent.this.client.sendResponse(new MessagesForYouComposer(HabboManager.WELCOME_MESSAGE.replace("%username%", finalHabbo.getHabboInfo().getUsername()).replace("%user%", finalHabbo.getHabboInfo().getUsername()).split("<br/>")));
|
||||
} else {
|
||||
SecureLoginEvent.this.client.sendResponse(new GenericAlertComposer(HabboManager.WELCOME_MESSAGE.replace("%username%", finalHabbo.getHabboInfo().getUsername()).replace("%user%", finalHabbo.getHabboInfo().getUsername())));
|
||||
}
|
||||
}, Emulator.getConfig().getInt("hotel.welcome.alert.delay", 5000));
|
||||
}
|
||||
|
||||
if(SubscriptionHabboClub.HC_PAYDAY_ENABLED) {
|
||||
SubscriptionHabboClub.processUnclaimed(habbo);
|
||||
}
|
||||
if(SubscriptionHabboClub.HC_PAYDAY_ENABLED) {
|
||||
SubscriptionHabboClub.processUnclaimed(habbo);
|
||||
}
|
||||
|
||||
SubscriptionHabboClub.processClubBadge(habbo);
|
||||
SubscriptionHabboClub.processClubBadge(habbo);
|
||||
|
||||
Messenger.checkFriendSizeProgress(habbo);
|
||||
Messenger.checkFriendSizeProgress(habbo);
|
||||
|
||||
if (!habbo.getHabboStats().hasGottenDefaultSavedSearches) {
|
||||
habbo.getHabboStats().hasGottenDefaultSavedSearches = true;
|
||||
Emulator.getThreading().run(habbo.getHabboStats());
|
||||
if (!habbo.getHabboStats().hasGottenDefaultSavedSearches) {
|
||||
habbo.getHabboStats().hasGottenDefaultSavedSearches = true;
|
||||
Emulator.getThreading().run(habbo.getHabboStats());
|
||||
|
||||
habbo.getHabboInfo().addSavedSearch(new NavigatorSavedSearch("official-root", ""));
|
||||
habbo.getHabboInfo().addSavedSearch(new NavigatorSavedSearch("my", ""));
|
||||
habbo.getHabboInfo().addSavedSearch(new NavigatorSavedSearch("favorites", ""));
|
||||
habbo.getHabboInfo().addSavedSearch(new NavigatorSavedSearch("official-root", ""));
|
||||
habbo.getHabboInfo().addSavedSearch(new NavigatorSavedSearch("my", ""));
|
||||
habbo.getHabboInfo().addSavedSearch(new NavigatorSavedSearch("favorites", ""));
|
||||
|
||||
this.client.sendResponse(new NewNavigatorSavedSearchesComposer(this.client.getHabbo().getHabboInfo().getSavedSearches()));
|
||||
this.client.sendResponse(new NewNavigatorSavedSearchesComposer(this.client.getHabbo().getHabboInfo().getSavedSearches()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Emulator.getGameServer().getGameClientManager().disposeClient(this.client);
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.eu.habbo.messages.incoming.inventory.prefixes;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.users.UserPrefix;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
import com.eu.habbo.messages.outgoing.inventory.prefixes.UserPrefixesComposer;
|
||||
|
||||
public class DeletePrefixEvent extends MessageHandler {
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
int prefixId = this.packet.readInt();
|
||||
|
||||
UserPrefix prefix = this.client.getHabbo().getInventory().getPrefixesComponent().getPrefix(prefixId);
|
||||
|
||||
if (prefix == null) return;
|
||||
|
||||
this.client.getHabbo().getInventory().getPrefixesComponent().removePrefix(prefix);
|
||||
prefix.needsDelete(true);
|
||||
Emulator.getThreading().run(prefix);
|
||||
|
||||
this.client.sendResponse(new UserPrefixesComposer(this.client.getHabbo()));
|
||||
}
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
package com.eu.habbo.messages.incoming.inventory.prefixes;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.UserPrefix;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
import com.eu.habbo.messages.outgoing.generic.alerts.BubbleAlertKeys;
|
||||
import com.eu.habbo.messages.outgoing.generic.alerts.BubbleAlertComposer;
|
||||
import com.eu.habbo.messages.outgoing.inventory.prefixes.PrefixReceivedComposer;
|
||||
import com.eu.habbo.messages.outgoing.users.UserCreditsComposer;
|
||||
import com.eu.habbo.messages.outgoing.users.UserCurrencyComposer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class PurchasePrefixEvent extends MessageHandler {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PurchasePrefixEvent.class);
|
||||
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 500;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
String text = this.packet.readString();
|
||||
String color = this.packet.readString();
|
||||
String icon = this.packet.readString();
|
||||
String effect = this.packet.readString();
|
||||
|
||||
Habbo habbo = this.client.getHabbo();
|
||||
|
||||
if (habbo == null) return;
|
||||
|
||||
// Load settings
|
||||
int maxLength = getSettingInt("max_length", 15);
|
||||
int minRank = getSettingInt("min_rank_to_buy", 1);
|
||||
int priceCredits = getSettingInt("price_credits", 5);
|
||||
int pricePoints = getSettingInt("price_points", 0);
|
||||
int pointsType = getSettingInt("points_type", 0);
|
||||
|
||||
// Validate text
|
||||
text = text.trim();
|
||||
|
||||
if (text.isEmpty() || text.length() > maxLength) {
|
||||
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FURNITURE_PLACEMENT_ERROR.key, "Prefix text is invalid or too long (max " + maxLength + " characters)."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate color (single hex or comma-separated multi hex for per-letter colors)
|
||||
String[] colorParts = color.split(",");
|
||||
for (String part : colorParts) {
|
||||
if (!part.matches("^#[0-9A-Fa-f]{6}$")) {
|
||||
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FURNITURE_PLACEMENT_ERROR.key, "Invalid color format."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check rank
|
||||
if (habbo.getHabboInfo().getRank().getId() < minRank) {
|
||||
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FURNITURE_PLACEMENT_ERROR.key, "Your rank is too low to purchase prefixes."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check blacklist
|
||||
if (isBlacklisted(text)) {
|
||||
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FURNITURE_PLACEMENT_ERROR.key, "This prefix contains a blocked word."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check credits
|
||||
if (priceCredits > 0 && habbo.getHabboInfo().getCredits() < priceCredits) {
|
||||
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FURNITURE_PLACEMENT_ERROR.key, "Not enough credits."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check points
|
||||
if (pricePoints > 0 && habbo.getHabboInfo().getCurrencyAmount(pointsType) < pricePoints) {
|
||||
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FURNITURE_PLACEMENT_ERROR.key, "Not enough points."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Deduct currency
|
||||
if (priceCredits > 0) {
|
||||
habbo.getHabboInfo().addCredits(-priceCredits);
|
||||
this.client.sendResponse(new UserCreditsComposer(habbo));
|
||||
}
|
||||
|
||||
if (pricePoints > 0) {
|
||||
habbo.getHabboInfo().addCurrencyAmount(pointsType, -pricePoints);
|
||||
this.client.sendResponse(new UserCurrencyComposer(habbo));
|
||||
}
|
||||
|
||||
// Validate icon (allow empty or known icon names)
|
||||
if (icon == null) icon = "";
|
||||
icon = icon.trim();
|
||||
|
||||
// Validate effect
|
||||
if (effect == null) effect = "";
|
||||
effect = effect.trim();
|
||||
|
||||
// Create prefix
|
||||
UserPrefix prefix = new UserPrefix(habbo.getHabboInfo().getId(), text, color, icon, effect);
|
||||
prefix.run(); // Insert into DB synchronously to get the ID
|
||||
habbo.getInventory().getPrefixesComponent().addPrefix(prefix);
|
||||
|
||||
this.client.sendResponse(new PrefixReceivedComposer(prefix));
|
||||
}
|
||||
|
||||
private int getSettingInt(String key, int defaultValue) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT `value` FROM custom_prefix_settings WHERE key_name = ?")) {
|
||||
statement.setString(1, key);
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
if (set.next()) {
|
||||
return Integer.parseInt(set.getString("value"));
|
||||
}
|
||||
}
|
||||
} catch (SQLException | NumberFormatException e) {
|
||||
LOGGER.error("Error reading prefix setting: " + key, e);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private boolean isBlacklisted(String text) {
|
||||
String lowerText = text.toLowerCase();
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT word FROM custom_prefix_blacklist")) {
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
while (set.next()) {
|
||||
if (lowerText.contains(set.getString("word").toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Error checking prefix blacklist", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.eu.habbo.messages.incoming.inventory.prefixes;
|
||||
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
import com.eu.habbo.messages.outgoing.inventory.prefixes.UserPrefixesComposer;
|
||||
|
||||
public class RequestUserPrefixesEvent extends MessageHandler {
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
this.client.sendResponse(new UserPrefixesComposer(this.client.getHabbo()));
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.eu.habbo.messages.incoming.inventory.prefixes;
|
||||
|
||||
import com.eu.habbo.habbohotel.users.UserPrefix;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
import com.eu.habbo.messages.outgoing.inventory.prefixes.ActivePrefixUpdatedComposer;
|
||||
|
||||
public class SetActivePrefixEvent extends MessageHandler {
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
int prefixId = this.packet.readInt();
|
||||
|
||||
if (prefixId == 0) {
|
||||
this.client.getHabbo().getInventory().getPrefixesComponent().deactivateAll();
|
||||
this.client.sendResponse(new ActivePrefixUpdatedComposer(null));
|
||||
return;
|
||||
}
|
||||
|
||||
UserPrefix prefix = this.client.getHabbo().getInventory().getPrefixesComponent().getPrefix(prefixId);
|
||||
|
||||
if (prefix == null) return;
|
||||
|
||||
this.client.getHabbo().getInventory().getPrefixesComponent().setActive(prefixId);
|
||||
this.client.sendResponse(new ActivePrefixUpdatedComposer(prefix));
|
||||
}
|
||||
}
|
||||
+5
@@ -7,6 +7,11 @@ import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
|
||||
public class ModToolIssueDefaultSanctionEvent extends MessageHandler {
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 2000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
if (this.client.getHabbo().hasPermission(Permission.ACC_SUPPORTTOOL)) {
|
||||
|
||||
@@ -4,6 +4,11 @@ import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
|
||||
public class ModToolKickEvent extends MessageHandler {
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 2000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
Emulator.getGameEnvironment().getModToolManager().kick(this.client.getHabbo(), Emulator.getGameEnvironment().getHabboManager().getHabbo(this.packet.readInt()), this.packet.readString());
|
||||
|
||||
+5
@@ -12,6 +12,11 @@ import gnu.trove.map.hash.THashMap;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ModToolSanctionAlertEvent extends MessageHandler {
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 2000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
int userId = this.packet.readInt();
|
||||
|
||||
+5
@@ -12,6 +12,11 @@ import gnu.trove.map.hash.THashMap;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ModToolSanctionBanEvent extends MessageHandler {
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 2000;
|
||||
}
|
||||
|
||||
public static final int BAN_18_HOURS = 3;
|
||||
public static final int BAN_7_DAYS = 4;
|
||||
public static final int BAN_30_DAYS_STEP_1 = 5;
|
||||
|
||||
+5
@@ -14,6 +14,11 @@ import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
public class ModToolSanctionMuteEvent extends MessageHandler {
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 2000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
int userId = this.packet.readInt();
|
||||
|
||||
+5
@@ -12,6 +12,11 @@ import gnu.trove.map.hash.THashMap;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ModToolSanctionTradeLockEvent extends MessageHandler {
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 2000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
int userId = this.packet.readInt();
|
||||
|
||||
@@ -8,6 +8,11 @@ import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
import com.eu.habbo.plugin.events.support.SupportUserAlertedReason;
|
||||
|
||||
public class ModToolWarnEvent extends MessageHandler {
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 2000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
if (this.client.getHabbo().hasPermission(Permission.ACC_SUPPORTTOOL)) {
|
||||
|
||||
+4
@@ -13,6 +13,10 @@ import org.slf4j.LoggerFactory;
|
||||
public class RequestCreateRoomEvent extends MessageHandler {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RequestCreateRoomEvent.class);
|
||||
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 3000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
|
||||
+56
-3
@@ -2,18 +2,38 @@ package com.eu.habbo.messages.incoming.rooms;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomTile;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class RequestRoomLoadEvent extends MessageHandler {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RequestRoomLoadEvent.class);
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
int roomId = this.packet.readInt();
|
||||
String password = this.packet.readString();
|
||||
|
||||
// Optional spawn coordinates from the client (for future reconnection support).
|
||||
int spawnX = -1;
|
||||
int spawnY = -1;
|
||||
|
||||
try {
|
||||
int remaining = this.packet.getBuffer().readableBytes();
|
||||
if (remaining >= 8) {
|
||||
spawnX = this.packet.readInt();
|
||||
spawnY = this.packet.readInt();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
spawnX = -1;
|
||||
spawnY = -1;
|
||||
}
|
||||
|
||||
// Reset stale loadingRoom if timestamp has expired (indicates failed/stuck load)
|
||||
if (this.client.getHabbo().getHabboInfo().getLoadingRoom() != 0
|
||||
&& this.client.getHabbo().getHabboStats().roomEnterTimestamp + 5000 < System.currentTimeMillis()) {
|
||||
if (this.client.getHabbo().getHabboInfo().getLoadingRoom() != 0
|
||||
&& this.client.getHabbo().getHabboStats().roomEnterTimestamp + 5000 < System.currentTimeMillis()) {
|
||||
this.client.getHabbo().getHabboInfo().setLoadingRoom(0);
|
||||
}
|
||||
|
||||
@@ -30,6 +50,18 @@ public class RequestRoomLoadEvent extends MessageHandler {
|
||||
|
||||
Room room = this.client.getHabbo().getHabboInfo().getCurrentRoom();
|
||||
if (room != null) {
|
||||
// If re-entering the same room (session resume / reconnect), capture
|
||||
// the user's current position before removal so we can respawn there.
|
||||
if (room.getId() == roomId && spawnX < 0 && spawnY < 0
|
||||
&& this.client.getHabbo().getRoomUnit() != null
|
||||
&& this.client.getHabbo().getRoomUnit().getCurrentLocation() != null) {
|
||||
RoomTile currentLoc = this.client.getHabbo().getRoomUnit().getCurrentLocation();
|
||||
spawnX = currentLoc.x;
|
||||
spawnY = currentLoc.y;
|
||||
LOGGER.info("[RequestRoomLoadEvent] Re-entering same room {} — preserving position ({}, {})",
|
||||
roomId, spawnX, spawnY);
|
||||
}
|
||||
|
||||
Emulator.getGameEnvironment().getRoomManager().logExit(this.client.getHabbo());
|
||||
|
||||
room.removeHabbo(this.client.getHabbo(), true);
|
||||
@@ -41,7 +73,28 @@ public class RequestRoomLoadEvent extends MessageHandler {
|
||||
this.client.getHabbo().getRoomUnit().isTeleporting = false;
|
||||
}
|
||||
|
||||
Emulator.getGameEnvironment().getRoomManager().enterRoom(this.client.getHabbo(), roomId, password);
|
||||
// Resolve spawn tile from coordinates (either from client or from saved position above)
|
||||
RoomTile spawnTile = null;
|
||||
|
||||
if (spawnX >= 0 && spawnY >= 0) {
|
||||
Room targetRoom = Emulator.getGameEnvironment().getRoomManager().getRoom(roomId);
|
||||
if (targetRoom == null) {
|
||||
targetRoom = Emulator.getGameEnvironment().getRoomManager().loadRoom(roomId);
|
||||
}
|
||||
if (targetRoom != null && targetRoom.getLayout() != null) {
|
||||
RoomTile tile = targetRoom.getLayout().getTile((short) spawnX, (short) spawnY);
|
||||
if (tile != null && tile.isWalkable()) {
|
||||
spawnTile = tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isReconnect = spawnTile != null;
|
||||
LOGGER.debug("[RequestRoomLoadEvent] Entering room {} (spawnTile={}, isReconnect={})",
|
||||
roomId,
|
||||
spawnTile != null ? "(" + spawnTile.x + "," + spawnTile.y + ")" : "door",
|
||||
isReconnect);
|
||||
Emulator.getGameEnvironment().getRoomManager().enterRoom(this.client.getHabbo(), roomId, password, false, spawnTile, isReconnect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,4 +555,10 @@ public class Outgoing {
|
||||
public static final int SnowStormUserRematchedComposer = 5029;
|
||||
|
||||
|
||||
// Custom Prefixes
|
||||
public static final int UserPrefixesComposer = 7001;
|
||||
public static final int PrefixReceivedComposer = 7002;
|
||||
public static final int ActivePrefixUpdatedComposer = 7003;
|
||||
public static final int AvailableCommandsComposer = 4050;
|
||||
|
||||
}
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.eu.habbo.messages.outgoing.commands;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.commands.Command;
|
||||
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 AvailableCommandsComposer extends MessageComposer {
|
||||
private final List<Command> commands;
|
||||
|
||||
public AvailableCommandsComposer(List<Command> commands) {
|
||||
this.commands = commands;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServerMessage composeInternal() {
|
||||
this.response.init(Outgoing.AvailableCommandsComposer);
|
||||
this.response.appendInt(this.commands.size());
|
||||
|
||||
for (Command cmd : this.commands) {
|
||||
this.response.appendString(cmd.keys[0]);
|
||||
this.response.appendString(
|
||||
Emulator.getTexts().getValue("commands.description." + cmd.permission, cmd.permission)
|
||||
);
|
||||
}
|
||||
|
||||
return this.response;
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.eu.habbo.messages.outgoing.inventory.prefixes;
|
||||
|
||||
import com.eu.habbo.habbohotel.users.UserPrefix;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.outgoing.MessageComposer;
|
||||
import com.eu.habbo.messages.outgoing.Outgoing;
|
||||
|
||||
public class ActivePrefixUpdatedComposer extends MessageComposer {
|
||||
private final UserPrefix prefix;
|
||||
|
||||
public ActivePrefixUpdatedComposer(UserPrefix prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServerMessage composeInternal() {
|
||||
this.response.init(Outgoing.ActivePrefixUpdatedComposer);
|
||||
|
||||
if (this.prefix != null) {
|
||||
this.response.appendInt(this.prefix.getId());
|
||||
this.response.appendString(this.prefix.getText());
|
||||
this.response.appendString(this.prefix.getColor());
|
||||
this.response.appendString(this.prefix.getIcon());
|
||||
this.response.appendString(this.prefix.getEffect());
|
||||
} else {
|
||||
this.response.appendInt(0);
|
||||
this.response.appendString("");
|
||||
this.response.appendString("");
|
||||
this.response.appendString("");
|
||||
this.response.appendString("");
|
||||
}
|
||||
|
||||
return this.response;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.eu.habbo.messages.outgoing.inventory.prefixes;
|
||||
|
||||
import com.eu.habbo.habbohotel.users.UserPrefix;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.outgoing.MessageComposer;
|
||||
import com.eu.habbo.messages.outgoing.Outgoing;
|
||||
|
||||
public class PrefixReceivedComposer extends MessageComposer {
|
||||
private final UserPrefix prefix;
|
||||
|
||||
public PrefixReceivedComposer(UserPrefix prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServerMessage composeInternal() {
|
||||
this.response.init(Outgoing.PrefixReceivedComposer);
|
||||
this.response.appendInt(this.prefix.getId());
|
||||
this.response.appendString(this.prefix.getText());
|
||||
this.response.appendString(this.prefix.getColor());
|
||||
this.response.appendString(this.prefix.getIcon());
|
||||
this.response.appendString(this.prefix.getEffect());
|
||||
return this.response;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.eu.habbo.messages.outgoing.inventory.prefixes;
|
||||
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.UserPrefix;
|
||||
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 UserPrefixesComposer extends MessageComposer {
|
||||
private final Habbo habbo;
|
||||
|
||||
public UserPrefixesComposer(Habbo habbo) {
|
||||
this.habbo = habbo;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServerMessage composeInternal() {
|
||||
if (this.habbo == null) return null;
|
||||
|
||||
List<UserPrefix> prefixes = this.habbo.getInventory().getPrefixesComponent().getPrefixes();
|
||||
|
||||
this.response.init(Outgoing.UserPrefixesComposer);
|
||||
this.response.appendInt(prefixes.size());
|
||||
|
||||
for (UserPrefix prefix : prefixes) {
|
||||
this.response.appendInt(prefix.getId());
|
||||
this.response.appendString(prefix.getText());
|
||||
this.response.appendString(prefix.getColor());
|
||||
this.response.appendString(prefix.getIcon());
|
||||
this.response.appendString(prefix.getEffect());
|
||||
this.response.appendInt(prefix.isActive() ? 1 : 0);
|
||||
}
|
||||
|
||||
return this.response;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user