diff --git a/Emulator/sqlupdates/custom_prefixes_setup.sql b/Emulator/sqlupdates/custom_prefixes_setup.sql new file mode 100644 index 00000000..7d5b22c5 --- /dev/null +++ b/Emulator/sqlupdates/custom_prefixes_setup.sql @@ -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 [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 '), + ('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 '), + ('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 [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'); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java index d68cec11..643b3f44 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java @@ -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); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogPageLayouts.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogPageLayouts.java index ff6d01aa..f0456c1c 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogPageLayouts.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogPageLayouts.java @@ -43,5 +43,6 @@ public enum CatalogPageLayouts { builders_club_loyalty, monkey, niko, - mad_money + mad_money, + custom_prefix } diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/catalog/layouts/CustomPrefixLayout.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/catalog/layouts/CustomPrefixLayout.java new file mode 100644 index 00000000..8152b89c --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/catalog/layouts/CustomPrefixLayout.java @@ -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()); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/CommandHandler.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/CommandHandler.java index 2137439a..3f26738b 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/CommandHandler.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/CommandHandler.java @@ -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()); } diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/GivePrefixCommand.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/GivePrefixCommand.java new file mode 100644 index 00000000..eba65376 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/GivePrefixCommand.java @@ -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; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/ListPrefixesCommand.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/ListPrefixesCommand.java new file mode 100644 index 00000000..caa78b6e --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/ListPrefixesCommand.java @@ -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 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; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/PrefixBlacklistCommand.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/PrefixBlacklistCommand.java new file mode 100644 index 00000000..dc8bbd69 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/PrefixBlacklistCommand.java @@ -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; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/RemovePrefixCommand.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/RemovePrefixCommand.java new file mode 100644 index 00000000..9396d18d --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/RemovePrefixCommand.java @@ -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 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; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessage.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessage.java index ebd915b7..b6f83d43 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessage.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomChatMessage.java @@ -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); } diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/users/HabboInventory.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/users/HabboInventory.java index 7eaf048d..6fdba07d 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/users/HabboInventory.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/users/HabboInventory.java @@ -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) { diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/users/UserPrefix.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/users/UserPrefix.java new file mode 100644 index 00000000..6879d1be --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/users/UserPrefix.java @@ -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; } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/users/inventory/PrefixesComponent.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/users/inventory/PrefixesComponent.java new file mode 100644 index 00000000..28889ede --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/users/inventory/PrefixesComponent.java @@ -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 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 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(); + } + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java b/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java index 757e1636..3fc3dcff 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java @@ -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 { diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java index 12c69575..b0b43567 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java @@ -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; } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/PurchaseTargetOfferEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/PurchaseTargetOfferEvent.java index 89fbfb3c..13fc307f 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/PurchaseTargetOfferEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/PurchaseTargetOfferEvent.java @@ -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(); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/BuyItemEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/BuyItemEvent.java index b9af0be8..5d604fb4 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/BuyItemEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/BuyItemEvent.java @@ -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(); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/RequestCreditsEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/RequestCreditsEvent.java index b03fda10..af98004a 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/RequestCreditsEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/RequestCreditsEvent.java @@ -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); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/TakeBackItemEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/TakeBackItemEvent.java index 7586afc4..12e7b1ef 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/TakeBackItemEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/catalog/marketplace/TakeBackItemEvent.java @@ -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(); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/DeletePrefixEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/DeletePrefixEvent.java new file mode 100644 index 00000000..7cac1bf1 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/DeletePrefixEvent.java @@ -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())); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/PurchasePrefixEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/PurchasePrefixEvent.java new file mode 100644 index 00000000..8e04000f --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/PurchasePrefixEvent.java @@ -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; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/RequestUserPrefixesEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/RequestUserPrefixesEvent.java new file mode 100644 index 00000000..b3169f70 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/RequestUserPrefixesEvent.java @@ -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())); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/SetActivePrefixEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/SetActivePrefixEvent.java new file mode 100644 index 00000000..9ec5710a --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/inventory/prefixes/SetActivePrefixEvent.java @@ -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)); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolIssueDefaultSanctionEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolIssueDefaultSanctionEvent.java index eb533cf9..48beb3c7 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolIssueDefaultSanctionEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolIssueDefaultSanctionEvent.java @@ -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)) { diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolKickEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolKickEvent.java index 3e1e234e..77370b36 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolKickEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolKickEvent.java @@ -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()); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionAlertEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionAlertEvent.java index 808a25de..4c901c46 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionAlertEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionAlertEvent.java @@ -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(); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionBanEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionBanEvent.java index a451a2ad..1814041b 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionBanEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionBanEvent.java @@ -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; diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionMuteEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionMuteEvent.java index 62cf7929..e9356fdf 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionMuteEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionMuteEvent.java @@ -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(); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionTradeLockEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionTradeLockEvent.java index 2666f6e6..0cece3ce 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionTradeLockEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolSanctionTradeLockEvent.java @@ -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(); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolWarnEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolWarnEvent.java index e5f0b102..a8dae64f 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolWarnEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/modtool/ModToolWarnEvent.java @@ -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)) { diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/navigator/RequestCreateRoomEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/navigator/RequestCreateRoomEvent.java index 79eebb68..66d0480b 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/navigator/RequestCreateRoomEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/navigator/RequestCreateRoomEvent.java @@ -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 { diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java index 310a1404..3305bad8 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java @@ -555,4 +555,9 @@ 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; + } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/inventory/prefixes/ActivePrefixUpdatedComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/inventory/prefixes/ActivePrefixUpdatedComposer.java new file mode 100644 index 00000000..13017e93 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/inventory/prefixes/ActivePrefixUpdatedComposer.java @@ -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; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/inventory/prefixes/PrefixReceivedComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/inventory/prefixes/PrefixReceivedComposer.java new file mode 100644 index 00000000..98bdf055 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/inventory/prefixes/PrefixReceivedComposer.java @@ -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; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/inventory/prefixes/UserPrefixesComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/inventory/prefixes/UserPrefixesComposer.java new file mode 100644 index 00000000..747e63b6 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/inventory/prefixes/UserPrefixesComposer.java @@ -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 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; + } +} diff --git a/Latest_Compiled_Version/Habbo-4.0.5-jar-with-dependencies.jar b/Latest_Compiled_Version/Habbo-4.0.5-jar-with-dependencies.jar deleted file mode 100644 index 828852a8..00000000 Binary files a/Latest_Compiled_Version/Habbo-4.0.5-jar-with-dependencies.jar and /dev/null differ