Merge branch 'dev' into fix/wired-movement-effect-payloads

This commit is contained in:
DuckieTM
2026-06-18 12:50:10 +02:00
committed by GitHub
241 changed files with 4947 additions and 696 deletions
@@ -166,6 +166,7 @@ public final class Emulator {
Emulator.config.register("rcon.rate_limit.timeout_ms", "0");
Emulator.config.register("rcon.execute_command.denied_permissions", "cmd_shutdown;cmd_give_rank");
Emulator.config.register("rcon.execute_command.allowed_permissions", "");
Emulator.config.register("rcon.max_payload_bytes", "65536");
registerEarningsSettings();
String hotelTimezoneId = Emulator.getConfig().getValue("hotel.timezone", java.time.ZoneId.systemDefault().getId());
System.out.println(startupCard(hotelTimezoneId));
@@ -174,6 +174,14 @@ public class CatalogItem implements ISerialize, Runnable, Comparable<CatalogItem
return this.offerId;
}
public int getSearchOfferId() {
if (this.offerId > 0) {
return this.offerId;
}
return haveOffer(this) ? this.id : -1;
}
public boolean isLimited() {
return this.limitedStack > 0;
}
@@ -494,10 +494,11 @@ public class CatalogManager {
item = new CatalogItem(set);
page.addItem(item);
if (item.getOfferId() != -1) {
page.addOfferId(item.getOfferId());
int searchOfferId = item.getSearchOfferId();
if (searchOfferId != -1) {
page.addOfferId(searchOfferId);
this.offerDefs.put(item.getOfferId(), item.getId());
this.offerDefs.put(searchOfferId, item.getId());
}
} else
item.update(set);
@@ -58,6 +58,10 @@ public class MarketPlace {
public static void takeBackItem(Habbo habbo, int offerId) {
MarketPlaceOffer offer = habbo.getInventory().getOffer(offerId);
if (offer == null) {
return;
}
if (!Emulator.getPluginManager().fireEvent(new MarketPlaceItemCancelledEvent(offer)).isCancelled()) {
takeBackItem(habbo, offer);
}
@@ -32,6 +32,11 @@ public class AlertCommand extends Command {
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(targetUsername);
if (habbo != null) {
if (!CommandTargetGuard.canTarget(gameClient.getHabbo(), habbo)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_ban.target_rank_higher"), RoomChatMessageBubbles.ALERT);
return true;
}
habbo.alert(message + "\r\n -" + gameClient.getHabbo().getHabboInfo().getUsername());
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.succes.cmd_alert.message_send").replace("%user%", targetUsername), RoomChatMessageBubbles.ALERT);
} else {
@@ -60,7 +60,7 @@ public class BanCommand extends Command {
return true;
}
if (target.getRank().getId() >= gameClient.getHabbo().getHabboInfo().getRank().getId()) {
if (!CommandTargetGuard.canTarget(gameClient.getHabbo(), target)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_ban.target_rank_higher"), RoomChatMessageBubbles.ALERT);
return true;
}
@@ -0,0 +1,46 @@
package com.eu.habbo.habbohotel.commands;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.permissions.Rank;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboInfo;
final class CommandTargetGuard {
private CommandTargetGuard() {
}
static boolean canTarget(Habbo moderator, Habbo target) {
return target != null && canTarget(moderator, target.getHabboInfo());
}
static boolean canTarget(Habbo moderator, HabboInfo target) {
if (moderator == null || target == null || moderator.getHabboInfo().getId() == target.getId()) {
return false;
}
int moderatorRankId = moderator.getHabboInfo().getRank().getId();
int targetRankId = target.getRank().getId();
return targetRankId < moderatorRankId || isCoreRank(moderatorRankId) && targetRankId <= moderatorRankId;
}
static boolean canAssignRank(Habbo moderator, Rank rank) {
if (moderator == null || rank == null) {
return false;
}
int moderatorRankId = moderator.getHabboInfo().getRank().getId();
int targetRankId = rank.getId();
return targetRankId < moderatorRankId || isCoreRank(moderatorRankId) && targetRankId <= moderatorRankId;
}
private static boolean isCoreRank(int rankId) {
int highestRankId = Emulator.getGameEnvironment().getPermissionsManager().getAllRanks().stream()
.mapToInt(Rank::getId)
.max()
.orElse(0);
return highestRankId > 0 && rankId >= highestRankId;
}
}
@@ -29,7 +29,7 @@ public class DisconnectCommand extends Command {
return true;
}
if (target.getHabboInfo().getRank().getId() > gameClient.getHabbo().getHabboInfo().getRank().getId()) {
if (!CommandTargetGuard.canTarget(gameClient.getHabbo(), target)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_disconnect.higher_rank"), RoomChatMessageBubbles.ALERT);
return true;
}
@@ -47,6 +47,11 @@ public class GivePrefixCommand extends Command {
return true;
}
if (!CommandTargetGuard.canTarget(gameClient.getHabbo(), target)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_ban.target_rank_higher"), RoomChatMessageBubbles.ALERT);
return true;
}
UserPrefix prefix = new UserPrefix(target.getHabboInfo().getId(), text, color, icon, effect);
prefix.run();
target.getInventory().getPrefixesComponent().addPrefix(prefix);
@@ -36,7 +36,7 @@ public class GiveRankCommand extends Command {
}
if (rank != null) {
if (rank.getId() > gameClient.getHabbo().getHabboInfo().getRank().getId()) {
if (!CommandTargetGuard.canAssignRank(gameClient.getHabbo(), rank)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_give_rank.higher").replace("%username%", params[1]).replace("%id%", rank.getName()), RoomChatMessageBubbles.ALERT);
return true;
}
@@ -44,7 +44,7 @@ public class GiveRankCommand extends Command {
HabboInfo habbo = HabboManager.getOfflineHabboInfo(params[1]);
if (habbo != null) {
if (habbo.getRank().getId() > gameClient.getHabbo().getHabboInfo().getRank().getId()) {
if (!CommandTargetGuard.canTarget(gameClient.getHabbo(), habbo)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_give_rank.higher.other").replace("%username%", params[1]).replace("%id%", rank.getName()), RoomChatMessageBubbles.ALERT);
return true;
}
@@ -47,7 +47,7 @@ public class IPBanCommand extends Command {
return true;
}
if (habbo.getRank().getId() >= gameClient.getHabbo().getHabboInfo().getRank().getId()) {
if (!CommandTargetGuard.canTarget(gameClient.getHabbo(), habbo)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_ban.target_rank_higher"), RoomChatMessageBubbles.ALERT);
return true;
}
@@ -43,7 +43,7 @@ public class MachineBanCommand extends Command {
return true;
}
if (habbo.getRank().getId() >= gameClient.getHabbo().getHabboInfo().getRank().getId()) {
if (!CommandTargetGuard.canTarget(gameClient.getHabbo(), habbo)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_ban.target_rank_higher"), RoomChatMessageBubbles.ALERT);
return true;
}
@@ -29,6 +29,11 @@ public class MuteCommand extends Command {
return true;
}
if (!CommandTargetGuard.canTarget(gameClient.getHabbo(), habbo)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_ban.target_rank_higher"), RoomChatMessageBubbles.ALERT);
return true;
}
int duration = Integer.MAX_VALUE;
if (params.length == 3) {
@@ -31,6 +31,11 @@ public class RemovePrefixCommand extends Command {
return true;
}
if (!CommandTargetGuard.canTarget(gameClient.getHabbo(), target)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_ban.target_rank_higher"), RoomChatMessageBubbles.ALERT);
return true;
}
if (prefixIdStr.equalsIgnoreCase("all")) {
List<UserPrefix> prefixes = target.getInventory().getPrefixesComponent().getPrefixes();
for (UserPrefix prefix : prefixes) {
@@ -41,7 +41,7 @@ public class SuperbanCommand extends Command {
return true;
}
if (habbo.getRank().getId() >= gameClient.getHabbo().getHabboInfo().getRank().getId()) {
if (!CommandTargetGuard.canTarget(gameClient.getHabbo(), habbo)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_ban.target_rank_higher"), RoomChatMessageBubbles.ALERT);
return true;
}
@@ -23,6 +23,11 @@ public class UnmuteCommand extends Command {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_unmute.not_found").replace("%user%", params[1]), RoomChatMessageBubbles.ALERT);
return true;
} else {
if (!CommandTargetGuard.canTarget(gameClient.getHabbo(), habbo)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_ban.target_rank_higher"), RoomChatMessageBubbles.ALERT);
return true;
}
if (!habbo.getHabboStats().allowTalk() || (habbo.getHabboInfo().getCurrentRoom() != null && habbo.getHabboInfo().getCurrentRoom().isMuted(habbo))) {
if (!habbo.getHabboStats().allowTalk()) {
habbo.unMute();
@@ -14,6 +14,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
public class GameClient {
@@ -24,6 +25,7 @@ public class GameClient {
private final LatencyTracker latencyTracker;
private Habbo habbo;
private final AtomicBoolean disposed = new AtomicBoolean(false);
private boolean handshakeFinished;
private String machineId = "";
private String ssoTicket = "";
@@ -153,6 +155,10 @@ public class GameClient {
}
public void dispose(boolean allowSessionResume) {
if (!this.disposed.compareAndSet(false, true)) {
return;
}
try {
this.channel.close();
@@ -441,7 +441,7 @@ public class GuildManager {
public int getGuildMembersCount(Guild guild, int page, int levelId, String query) {
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT COUNT(*) FROM guilds_members INNER JOIN users ON guilds_members.user_id = users.id WHERE guilds_members.guild_id = ? " + (rankQuery(levelId)) + " AND users.username LIKE ? ORDER BY level_id, member_since ASC")) {
statement.setInt(1, guild.getId());
statement.setString(2, "%" + query + "%");
statement.setString(2, "%" + com.eu.habbo.util.SqlLikeEscaper.escape(query) + "%");
try (ResultSet set = statement.executeQuery()) {
while (set.next()) {
@@ -45,7 +45,7 @@ public class Item implements ISerialize {
}
public static boolean isPet(Item item) {
return item.getName().toLowerCase().startsWith("a0 pet");
return item != null && item.getName() != null && item.getName().toLowerCase().startsWith("a0 pet");
}
public static boolean isBot(Item item) {
@@ -121,26 +121,19 @@ public class Item implements ISerialize {
this.customParams = set.getString("customparams");
this.clothingOnWalk = set.getString("clothing_on_walk");
if (!set.getString("vending_ids").isEmpty()) {
int[] vendingIds = ItemDataGuard.parsePositiveIntList(set.getString("vending_ids"));
if (vendingIds.length > 0) {
this.vendingItems = new TIntArrayList();
String[] vendingIds = set.getString("vending_ids").replace(";", ",").replace(".", ",").split(",");
for (String s : vendingIds) {
this.vendingItems.add(Integer.parseInt(s.replace(" ", "")));
for (int vendingId : vendingIds) {
this.vendingItems.add(vendingId);
}
} else {
this.vendingItems = new TIntArrayList();
}
//if(this.interactionType.getType() == InteractionMultiHeight.class || this.interactionType.getType().isAssignableFrom(InteractionMultiHeight.class))
{
if (set.getString("multiheight").contains(";")) {
String[] s = set.getString("multiheight").split(";");
this.multiHeights = new double[s.length];
for (int i = 0; i < s.length; i++) {
this.multiHeights[i] = Double.parseDouble(s[i]);
}
} else {
this.multiHeights = new double[0];
}
this.multiHeights = ItemDataGuard.parseHeights(set.getString("multiheight"));
}
this.rotations = 4;
@@ -254,6 +247,10 @@ public class Item implements ISerialize {
}
public int getRandomVendingItem() {
if (this.vendingItems == null || this.vendingItems.isEmpty()) {
return 0;
}
return this.vendingItems.get(Emulator.getRandom().nextInt(this.vendingItems.size()));
}
@@ -273,21 +270,23 @@ public class Item implements ISerialize {
@Override
public void serialize(ServerMessage message) {
message.appendString(this.type.code.toLowerCase());
message.appendString(this.type == null ? "" : this.type.code.toLowerCase());
if (type == FurnitureType.BADGE) {
message.appendString(this.customParams);
message.appendString(ItemDataGuard.safeString(this.customParams));
} else {
message.appendInt(this.spriteId);
if (this.getName().contains("wallpaper_single") || this.getName().contains("floor_single") || this.getName().contains("landscape_single")) {
message.appendString(this.name.split("_")[2]);
String itemName = ItemDataGuard.safeString(this.getName());
if (itemName.contains("wallpaper_single") || itemName.contains("floor_single") || itemName.contains("landscape_single")) {
String[] nameParts = itemName.split("_");
message.appendString(nameParts.length > 2 ? nameParts[2] : "");
} else if (type == FurnitureType.ROBOT) {
message.appendString(this.customParams);
} else if (name.equalsIgnoreCase("poster")) {
message.appendString(this.customParams);
} else if (name.startsWith("SONG ")) {
message.appendString(this.customParams);
message.appendString(ItemDataGuard.safeString(this.customParams));
} else if (itemName.equalsIgnoreCase("poster")) {
message.appendString(ItemDataGuard.safeString(this.customParams));
} else if (itemName.startsWith("SONG ")) {
message.appendString(ItemDataGuard.safeString(this.customParams));
} else {
message.appendString("");
}
@@ -0,0 +1,82 @@
package com.eu.habbo.habbohotel.items;
final class ItemDataGuard {
static final int MAX_EXTRA_DATA_LENGTH = 1000;
private ItemDataGuard() {
}
static String safeString(String value) {
return value == null ? "" : value;
}
static String normalizeExtraData(String value) {
String safe = safeString(value);
return safe.length() > MAX_EXTRA_DATA_LENGTH ? safe.substring(0, MAX_EXTRA_DATA_LENGTH) : safe;
}
static int parsePositiveInt(String value) {
try {
int parsed = Integer.parseInt(safeString(value).trim());
return parsed > 0 ? parsed : 0;
} catch (NumberFormatException e) {
return 0;
}
}
static int[] parsePositiveIntList(String value) {
String safe = safeString(value).replace(";", ",").replace(".", ",");
if (safe.isBlank()) {
return new int[0];
}
String[] parts = safe.split(",");
int[] parsed = new int[parts.length];
int count = 0;
for (String part : parts) {
int id = parsePositiveInt(part);
if (id > 0) {
parsed[count++] = id;
}
}
if (count == parsed.length) {
return parsed;
}
int[] compact = new int[count];
System.arraycopy(parsed, 0, compact, 0, count);
return compact;
}
static double[] parseHeights(String value) {
String safe = safeString(value);
if (safe.isBlank() || !safe.contains(";")) {
return new double[0];
}
String[] parts = safe.split(";");
double[] parsed = new double[parts.length];
int count = 0;
for (String part : parts) {
try {
double height = Double.parseDouble(part.trim());
if (Double.isFinite(height)) {
parsed[count++] = height;
}
} catch (NumberFormatException e) {
// Ignore malformed DB values and keep the remaining heights usable.
}
}
if (count == parsed.length) {
return parsed;
}
double[] compact = new double[count];
System.arraycopy(parsed, 0, compact, 0, count);
return compact;
}
}
@@ -566,6 +566,10 @@ public class ItemManager {
public int calculateCrackState(int count, int max, Item baseItem) {
if (count <= 0 || max <= 0 || baseItem == null || baseItem.getStateCount() <= 0) {
return 0;
}
return (int) Math.floor((1.0D / ((double) max / (double) count) * baseItem.getStateCount()));
}
@@ -574,7 +578,8 @@ public class ItemManager {
}
public Item getCrackableReward(int itemId) {
return this.getItem(this.crackableRewards.get(itemId).getRandomReward());
CrackableReward reward = this.crackableRewards.get(itemId);
return reward == null ? null : this.getItem(reward.getRandomReward());
}
@@ -604,6 +609,12 @@ public class ItemManager {
}
public HabboItem createItem(int habboId, Item item, int limitedStack, int limitedSells, String extraData) {
if (habboId <= 0 || item == null) {
return null;
}
extraData = ItemDataGuard.normalizeExtraData(extraData);
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO items (user_id, item_id, extra_data, limited_data) VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS)) {
statement.setInt(1, habboId);
statement.setInt(2, item.getId());
@@ -673,6 +684,12 @@ public class ItemManager {
}
public HabboItem handleRecycle(Habbo habbo, String itemId) {
int rewardItemId = ItemDataGuard.parsePositiveInt(itemId);
if (habbo == null || habbo.getHabboInfo() == null || rewardItemId <= 0
|| Emulator.getGameEnvironment().getCatalogManager().ecotronItem == null) {
return null;
}
String extradata = Calendar.getInstance().get(Calendar.DAY_OF_MONTH) + "-" + (Calendar.getInstance().get(Calendar.MONTH) + 1) + "-" + Calendar.getInstance().get(Calendar.YEAR);
HabboItem item = null;
@@ -686,7 +703,7 @@ public class ItemManager {
try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO items_presents (item_id, base_item_reward) VALUES (?, ?)")) {
while (set.next() && item == null) {
preparedStatement.setInt(1, set.getInt(1));
preparedStatement.setInt(2, Integer.parseInt(itemId));
preparedStatement.setInt(2, rewardItemId);
preparedStatement.addBatch();
item = new InteractionDefault(set.getInt(1), habbo.getHabboInfo().getId(), Emulator.getGameEnvironment().getCatalogManager().ecotronItem, extradata, 0, 0);
}
@@ -829,6 +846,10 @@ public class ItemManager {
}
public HabboItem createGift(String username, Item item, String extraData, int limitedStack, int limitedSells) {
if (username == null || username.isBlank() || item == null) {
return null;
}
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(username);
int userId = 0;
@@ -857,13 +878,13 @@ public class ItemManager {
}
public HabboItem createGift(int userId, Item item, String extraData, int limitedStack, int limitedSells) {
if (userId == 0)
if (userId <= 0 || item == null)
return null;
if (extraData.length() > 1000) {
if (extraData != null && extraData.length() > ItemDataGuard.MAX_EXTRA_DATA_LENGTH) {
LOGGER.error("Extradata exceeds maximum length of 1000 characters: {}", extraData);
extraData = extraData.substring(0, 1000);
}
extraData = ItemDataGuard.normalizeExtraData(extraData);
HabboItem gift = this.createItem(userId, item, limitedStack, limitedSells, extraData);
@@ -879,7 +900,7 @@ public class ItemManager {
}
public Item getItem(int itemId) {
if (itemId < 0)
if (itemId <= 0)
return null;
return this.items.get(itemId);
@@ -890,12 +911,16 @@ public class ItemManager {
}
public Item getItem(String itemName) {
if (itemName == null || itemName.isBlank()) {
return null;
}
TIntObjectIterator<Item> item = this.items.iterator();
for (int i = this.items.size(); i-- > 0; ) {
try {
item.advance();
if (item.value().getName().equalsIgnoreCase(itemName)) {
if (item.value() != null && item.value().getName() != null && item.value().getName().equalsIgnoreCase(itemName)) {
return item.value();
}
} catch (NoSuchElementException e) {
@@ -2,6 +2,7 @@ package com.eu.habbo.habbohotel.items.interactions;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredInputGuard;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
@@ -230,39 +231,18 @@ public abstract class InteractionWired extends InteractionDefault {
public static WiredSettings readSettings(ClientMessage packet, boolean isEffect)
{
int intParamCount = packet.readInt();
if (intParamCount < 0 || intParamCount > 100) {
throw new IllegalArgumentException("Invalid intParamCount: " + intParamCount);
}
int[] intParams = new int[intParamCount];
for(int i = 0; i < intParamCount; i++)
{
intParams[i] = packet.readInt();
}
String stringParam = packet.readString();
int itemCount = packet.readInt();
int selectionLimit = Emulator.getConfig() != null ? Emulator.getConfig().getInt("hotel.wired.furni.selection.count", 5) : 5;
if (itemCount < 0 || itemCount > selectionLimit * 20) {
throw new IllegalArgumentException("Invalid itemCount: " + itemCount + " exceeds maximum allowed limit");
}
int[] itemIds = new int[itemCount];
for(int i = 0; i < itemCount; i++)
{
itemIds[i] = packet.readInt();
}
int[] intParams = WiredInputGuard.readIntParams(packet);
String stringParam = WiredInputGuard.readStringParam(packet);
int[] itemIds = WiredInputGuard.readFurniIds(packet);
WiredSettings settings = new WiredSettings(intParams, stringParam, itemIds, -1);
if(isEffect)
{
settings.setDelay(packet.readInt());
settings.setDelay(WiredInputGuard.normalizeDelay(packet.readInt()));
}
settings.setStuffTypeSelectionCode(packet.readInt());
settings.setStuffTypeSelectionCode(WiredInputGuard.normalizeStuffSelectionCode(packet.readInt()));
return settings;
}
}
@@ -0,0 +1,90 @@
package com.eu.habbo.habbohotel.items.interactions.wired;
import com.eu.habbo.Emulator;
import com.eu.habbo.messages.ClientMessage;
import java.util.Arrays;
public final class WiredInputGuard {
public static final int MAX_INT_PARAMS = 100;
public static final int MAX_STRING_PARAM_LENGTH = 1024;
public static final int MAX_ABSOLUTE_FURNI_IDS = 100;
public static final int DEFAULT_MAX_DELAY = 20;
public static final int MAX_ABSOLUTE_DELAY = 3600;
public static final int MIN_STUFF_SELECTION_CODE = -1;
public static final int MAX_STUFF_SELECTION_CODE = 2;
private WiredInputGuard() {
}
public static int[] readIntParams(ClientMessage packet) {
int count = packet.readInt();
if (count < 0 || count > MAX_INT_PARAMS) {
throw new IllegalArgumentException("Invalid wired int param count");
}
int[] values = new int[count];
for (int i = 0; i < count; i++) {
values[i] = packet.readInt();
}
return values;
}
public static String readStringParam(ClientMessage packet) {
String value = packet.readString();
if (value == null || value.isEmpty()) {
return "";
}
return value.length() > MAX_STRING_PARAM_LENGTH
? value.substring(0, MAX_STRING_PARAM_LENGTH)
: value;
}
public static int[] readFurniIds(ClientMessage packet) {
int count = packet.readInt();
int maxCount = maxFurniSelectionCount();
if (count < 0 || count > maxCount) {
throw new IllegalArgumentException("Invalid wired furni selection count");
}
int[] values = new int[count];
int accepted = 0;
for (int i = 0; i < count; i++) {
int itemId = packet.readInt();
if (itemId > 0) {
values[accepted++] = itemId;
}
}
return accepted == values.length ? values : Arrays.copyOf(values, accepted);
}
public static int normalizeDelay(int delay) {
return Math.max(0, Math.min(delay, maxDelay()));
}
public static int normalizeStuffSelectionCode(int code) {
if (code < MIN_STUFF_SELECTION_CODE || code > MAX_STUFF_SELECTION_CODE) {
return MIN_STUFF_SELECTION_CODE;
}
return code;
}
public static int maxFurniSelectionCount() {
int selectionLimit = Emulator.getConfig() != null
? Emulator.getConfig().getInt("hotel.wired.furni.selection.count", 5)
: 5;
selectionLimit = Math.max(1, selectionLimit);
return Math.min(MAX_ABSOLUTE_FURNI_IDS, selectionLimit * 20);
}
public static int maxDelay() {
int configured = Emulator.getConfig() != null
? Emulator.getConfig().getInt("hotel.wired.max_delay", DEFAULT_MAX_DELAY)
: DEFAULT_MAX_DELAY;
configured = Math.max(0, configured);
return Math.min(MAX_ABSOLUTE_DELAY, configured);
}
}
@@ -0,0 +1,48 @@
package com.eu.habbo.habbohotel.items.interactions.wired;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.users.HabboItem;
import java.util.ArrayList;
import java.util.List;
public final class WiredLegacyDataGuard {
public static final int DEFAULT_MAX_DELAY = 20;
private WiredLegacyDataGuard() {
}
public static int parseDelay(String value) {
try {
int parsed = Integer.parseInt(value == null ? "" : value.trim());
return Math.max(0, Math.min(parsed, DEFAULT_MAX_DELAY));
} catch (NumberFormatException e) {
return 0;
}
}
public static List<HabboItem> parseRoomItems(String value, Room room) {
List<HabboItem> items = new ArrayList<>();
if (room == null || value == null || value.isBlank()) {
return items;
}
for (String part : value.split(";")) {
try {
int itemId = Integer.parseInt(part.trim());
if (itemId <= 0) {
continue;
}
HabboItem item = room.getHabboItem(itemId);
if (item != null) {
items.add(item);
}
} catch (NumberFormatException e) {
// Ignore malformed legacy ids and keep loading the remaining items.
}
}
return items;
}
}
@@ -0,0 +1,38 @@
package com.eu.habbo.habbohotel.items.interactions.wired;
import com.eu.habbo.Emulator;
public final class WiredNumericInputGuard {
public static final int DEFAULT_MAX_REWARD_AMOUNT = 1000;
public static final int DEFAULT_MAX_RESPECT_AMOUNT = 100;
public static final int MAX_ABSOLUTE_AMOUNT = 100000;
private WiredNumericInputGuard() {
}
public static int parsePositiveAmount(String value, int maxAmount) {
try {
int parsed = Integer.parseInt(value == null ? "" : value.trim());
if (parsed <= 0) {
return 0;
}
return Math.min(parsed, Math.max(1, Math.min(maxAmount, MAX_ABSOLUTE_AMOUNT)));
} catch (NumberFormatException e) {
return 0;
}
}
public static int maxRewardAmount() {
return configuredMax("hotel.wired.reward.max_amount", DEFAULT_MAX_REWARD_AMOUNT);
}
public static int maxRespectAmount() {
return configuredMax("hotel.wired.respect.max_amount", DEFAULT_MAX_RESPECT_AMOUNT);
}
private static int configuredMax(String key, int fallback) {
int configured = Emulator.getConfig() != null ? Emulator.getConfig().getInt(key, fallback) : fallback;
return Math.max(1, Math.min(configured, MAX_ABSOLUTE_AMOUNT));
}
}
@@ -0,0 +1,45 @@
package com.eu.habbo.habbohotel.items.interactions.wired;
public final class WiredTimerInputGuard {
public static final int MAX_TIMER_MS = 24 * 60 * 60 * 1000;
private WiredTimerInputGuard() {
}
public static int fromClientUnits(int units, int stepMs, int minMs) {
return fromClientUnits(units, stepMs, minMs, MAX_TIMER_MS);
}
public static int fromClientUnits(int units, int stepMs, int minMs, int maxMs) {
if (units < 1 || stepMs < 1) {
return minMs;
}
long value = (long) units * stepMs;
return clamp(value, minMs, maxMs);
}
public static int normalizeStoredMillis(Integer millis, int minMs, int fallbackMs) {
return normalizeStoredMillis(millis, minMs, fallbackMs, MAX_TIMER_MS);
}
public static int normalizeStoredMillis(Integer millis, int minMs, int fallbackMs, int maxMs) {
if (millis == null || millis < minMs) {
return fallbackMs;
}
return clamp(millis.longValue(), minMs, maxMs);
}
private static int clamp(long value, int minMs, int maxMs) {
if (value < minMs) {
return minMs;
}
if (value > maxMs) {
return maxMs;
}
return (int) value;
}
}
@@ -111,7 +111,13 @@ public class WiredConditionActorDir extends InteractionWiredCondition {
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException exception) {
this.onPickUp();
return;
}
if (data == null) {
return;
@@ -157,15 +163,15 @@ public class WiredConditionActorDir extends InteractionWiredCondition {
return (this.directionMask & (1 << direction)) != 0;
}
private int normalizeDirectionMask(int value) {
int normalizeDirectionMask(int value) {
return value & ALL_DIRECTIONS_MASK;
}
private int normalizeUserSource(int value) {
int normalizeUserSource(int value) {
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
}
private int normalizeQuantifier(int value) {
int normalizeQuantifier(int value) {
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL;
}
@@ -111,19 +111,21 @@ public class WiredConditionCounterTimeMatches extends InteractionWiredCondition
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.items.clear();
this.comparison = COMPARISON_EQUAL;
this.minutes = 0;
this.halfSecondSteps = 0;
this.furniSource = WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = QUANTIFIER_ALL;
this.resetSettings();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) {
return;
}
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException exception) {
this.resetSettings();
return;
}
if (data == null) {
return;
}
@@ -131,7 +133,7 @@ public class WiredConditionCounterTimeMatches extends InteractionWiredCondition
this.comparison = this.normalizeComparison(data.comparison);
this.minutes = this.normalizeMinutes(data.minutes);
this.halfSecondSteps = this.normalizeHalfSecondSteps(data.halfSecondSteps);
this.furniSource = data.furniSource;
this.furniSource = this.normalizeFurniSource(data.furniSource);
this.quantifier = this.normalizeQuantifier(data.quantifier);
if (data.itemIds == null) {
@@ -139,6 +141,10 @@ public class WiredConditionCounterTimeMatches extends InteractionWiredCondition
}
for (Integer id : data.itemIds) {
if (id == null) {
continue;
}
HabboItem item = room.getHabboItem(id);
if (item instanceof InteractionGameUpCounter) {
this.items.add(item);
@@ -195,7 +201,7 @@ public class WiredConditionCounterTimeMatches extends InteractionWiredCondition
this.comparison = (params.length > 0) ? this.normalizeComparison(params[0]) : COMPARISON_EQUAL;
this.minutes = (params.length > 1) ? this.normalizeMinutes(params[1]) : 0;
this.halfSecondSteps = (params.length > 2) ? this.normalizeHalfSecondSteps(params[2]) : 0;
this.furniSource = (params.length > 3) ? params[3] : WiredSourceUtil.SOURCE_TRIGGER;
this.furniSource = (params.length > 3) ? this.normalizeFurniSource(params[3]) : WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = (params.length > 4) ? this.normalizeQuantifier(params[4]) : QUANTIFIER_ALL;
this.items.clear();
@@ -224,6 +230,15 @@ public class WiredConditionCounterTimeMatches extends InteractionWiredCondition
return true;
}
private void resetSettings() {
this.items.clear();
this.comparison = COMPARISON_EQUAL;
this.minutes = 0;
this.halfSecondSteps = 0;
this.furniSource = WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = QUANTIFIER_ALL;
}
private void refresh(Room room) {
THashSet<HabboItem> remove = new THashSet<>();
@@ -256,7 +271,7 @@ public class WiredConditionCounterTimeMatches extends InteractionWiredCondition
}
}
private int normalizeComparison(int value) {
int normalizeComparison(int value) {
if (value < COMPARISON_LESS || value > COMPARISON_GREATER) {
return COMPARISON_EQUAL;
}
@@ -264,18 +279,30 @@ public class WiredConditionCounterTimeMatches extends InteractionWiredCondition
return value;
}
private int normalizeMinutes(int value) {
int normalizeMinutes(int value) {
return Math.max(0, Math.min(MAX_MINUTES, value));
}
private int normalizeHalfSecondSteps(int value) {
int normalizeHalfSecondSteps(int value) {
return Math.max(0, Math.min(MAX_HALF_SECOND_STEPS, value));
}
private int normalizeQuantifier(int value) {
int normalizeQuantifier(int value) {
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL;
}
int normalizeFurniSource(int value) {
switch (value) {
case WiredSourceUtil.SOURCE_SELECTED:
case WiredSourceUtil.SOURCE_SELECTOR:
case WiredSourceUtil.SOURCE_SIGNAL:
case WiredSourceUtil.SOURCE_TRIGGER:
return value;
default:
return WiredSourceUtil.SOURCE_TRIGGER;
}
}
static class JsonData {
int comparison;
int minutes;
@@ -53,8 +53,7 @@ public class WiredConditionDateRangeActive extends InteractionWiredCondition {
@Override
public boolean saveData(WiredSettings settings) {
if(settings.getIntParams().length < 2) return false;
this.startDate = settings.getIntParams()[0];
this.endDate = settings.getIntParams()[1];
this.applyRange(settings.getIntParams()[0], settings.getIntParams()[1]);
return true;
}
@@ -80,20 +79,28 @@ public class WiredConditionDateRangeActive extends InteractionWiredCondition {
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
this.applyRange(0, 0);
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.startDate = data.startDate;
this.endDate = data.endDate;
if (data == null) {
this.applyRange(0, 0);
return;
}
this.applyRange(data.startDate, data.endDate);
} else {
String[] data = wiredData.split("\t");
if (data.length == 2) {
try {
this.startDate = Integer.parseInt(data[0]);
this.endDate = Integer.parseInt(data[1]);
this.applyRange(Integer.parseInt(data[0]), Integer.parseInt(data[1]));
} catch (Exception e) {
this.applyRange(0, 0);
}
}
}
@@ -105,6 +112,12 @@ public class WiredConditionDateRangeActive extends InteractionWiredCondition {
this.endDate = 0;
}
private void applyRange(int startDate, int endDate) {
int[] range = WiredDateRangeInputGuard.normalizeRange(startDate, endDate);
this.startDate = range[0];
this.endDate = range[1];
}
static class JsonData {
int startDate;
int endDate;
@@ -92,21 +92,37 @@ public class WiredConditionFurniHaveFurni extends InteractionWiredCondition {
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.all = data.all;
this.furniSource = data.furniSource;
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException exception) {
this.onPickUp();
return;
}
for(int id : data.itemIds) {
if (data == null) {
return;
}
this.all = data.all;
this.furniSource = WiredFurniConditionInputGuard.normalizeFurniSource(data.furniSource);
for(int id : WiredFurniConditionInputGuard.sanitizeItemIds(data.itemIds, WiredManager.MAXIMUM_FURNI_SELECTION)) {
HabboItem item = room.getHabboItem(id);
HabboItem item = room.getHabboItem(id);
if (item != null) {
this.items.add(item);
}
}
}
} else {
String[] data = wiredData.split(":");
@@ -114,21 +130,19 @@ public class WiredConditionFurniHaveFurni extends InteractionWiredCondition {
this.all = (data[0].equals("1"));
if (data.length == 2) {
String[] items = data[1].split(";");
for (String s : items) {
HabboItem item = room.getHabboItem(Integer.parseInt(s));
for (int id : WiredFurniConditionInputGuard.parseLegacyItemIds(data[1], WiredManager.MAXIMUM_FURNI_SELECTION)) {
HabboItem item = room.getHabboItem(id);
if (item != null)
this.items.add(item);
} catch (NumberFormatException ignored) {
}
}
}
}
this.furniSource = this.items.isEmpty() ? WiredSourceUtil.SOURCE_TRIGGER : WiredSourceUtil.SOURCE_SELECTED;
}
if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
this.furniSource = WiredFurniConditionInputGuard.selectedOrNormalizedFurniSource(this.furniSource, !this.items.isEmpty());
}
@Override
@@ -172,14 +186,12 @@ public class WiredConditionFurniHaveFurni extends InteractionWiredCondition {
int[] params = settings.getIntParams();
this.all = params[0] == 1;
this.furniSource = (params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER;
this.furniSource = (params.length > 1) ? WiredFurniConditionInputGuard.normalizeFurniSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER;
int count = settings.getFurniIds().length;
if (count > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) return false;
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
this.furniSource = WiredFurniConditionInputGuard.selectedOrNormalizedFurniSource(this.furniSource, count > 0);
this.items.clear();
@@ -198,6 +210,18 @@ public class WiredConditionFurniHaveFurni extends InteractionWiredCondition {
return true;
}
int normalizeFurniSource(int value) {
switch (value) {
case WiredSourceUtil.SOURCE_SELECTED:
case WiredSourceUtil.SOURCE_SELECTOR:
case WiredSourceUtil.SOURCE_SIGNAL:
case WiredSourceUtil.SOURCE_TRIGGER:
return value;
default:
return WiredSourceUtil.SOURCE_TRIGGER;
}
}
private void refresh() {
THashSet<HabboItem> items = new THashSet<>();
@@ -89,41 +89,43 @@ public class WiredConditionFurniHaveHabbo extends InteractionWiredCondition {
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.items.clear();
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.furniSource = data.furniSource;
this.furniSource = WiredFurniConditionInputGuard.normalizeFurniSource(data.furniSource);
this.all = data.all;
for(int id : data.itemIds) {
for(int id : WiredFurniConditionInputGuard.sanitizeItemIds(data.itemIds, WiredManager.MAXIMUM_FURNI_SELECTION)) {
HabboItem item = room.getHabboItem(id);
HabboItem item = room.getHabboItem(id);
if (item != null) {
this.items.add(item);
}
}
}
} else {
String[] data = wiredData.split(":");
if (data.length >= 1) {
String[] items = data[1].split(";");
for (String s : items) {
HabboItem item = room.getHabboItem(Integer.parseInt(s));
if (data.length >= 2) {
for (int id : WiredFurniConditionInputGuard.parseLegacyItemIds(data[1], WiredManager.MAXIMUM_FURNI_SELECTION)) {
HabboItem item = room.getHabboItem(id);
if (item != null)
this.items.add(item);
} catch (NumberFormatException ignored) {
}
}
}
this.furniSource = this.items.isEmpty() ? WiredSourceUtil.SOURCE_TRIGGER : WiredSourceUtil.SOURCE_SELECTED;
this.all = false;
}
if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
this.furniSource = WiredFurniConditionInputGuard.selectedOrNormalizedFurniSource(this.furniSource, !this.items.isEmpty());
}
@Override
@@ -162,11 +164,9 @@ public class WiredConditionFurniHaveHabbo extends InteractionWiredCondition {
int[] params = settings.getIntParams();
this.all = (params.length > 0) && (params[0] == 1);
this.furniSource = (params.length > 1) ? params[1] : ((params.length > 0 && params[0] > 1) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER);
this.furniSource = (params.length > 1) ? WiredFurniConditionInputGuard.normalizeFurniSource(params[1]) : ((params.length > 0 && params[0] > 1) ? WiredFurniConditionInputGuard.normalizeFurniSource(params[0]) : WiredSourceUtil.SOURCE_TRIGGER);
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
this.furniSource = WiredFurniConditionInputGuard.selectedOrNormalizedFurniSource(this.furniSource, count > 0);
this.items.clear();
@@ -186,6 +186,18 @@ public class WiredConditionFurniHaveHabbo extends InteractionWiredCondition {
return true;
}
int normalizeFurniSource(int value) {
switch (value) {
case WiredSourceUtil.SOURCE_SELECTED:
case WiredSourceUtil.SOURCE_SELECTOR:
case WiredSourceUtil.SOURCE_SIGNAL:
case WiredSourceUtil.SOURCE_TRIGGER:
return value;
default:
return WiredSourceUtil.SOURCE_TRIGGER;
}
}
protected boolean hasAvatarOnItem(HabboItem item, Room room, Collection<Habbo> habbos, Collection<Bot> bots, Collection<Pet> pets) {
RoomTile baseTile = room.getLayout().getTile(item.getX(), item.getY());
if (baseTile == null) return false;
@@ -52,6 +52,10 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition {
@Override
public boolean evaluate(WiredContext ctx) {
if (ctx == null) {
return false;
}
if (this.quantifier == QUANTIFIER_ANY) {
return this.evaluateAnyMatches(ctx);
}
@@ -158,7 +162,14 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition {
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException exception) {
this.onPickUp();
return;
}
if (data == null) {
return;
}
@@ -310,8 +321,8 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition {
}
}
private void loadItems(Room room, List<Integer> itemIds, THashSet<HabboItem> target) {
if (itemIds == null) {
void loadItems(Room room, List<Integer> itemIds, THashSet<HabboItem> target) {
if (room == null || itemIds == null || target == null) {
return;
}
@@ -335,7 +346,7 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition {
.collect(Collectors.joining(";"));
}
private List<Integer> parseIds(String value) {
List<Integer> parseIds(String value) {
List<Integer> result = new ArrayList<>();
if (value == null || value.isEmpty()) {
return result;
@@ -16,6 +16,7 @@ import java.sql.SQLException;
public class WiredConditionHabboCount extends InteractionWiredCondition {
public static final WiredConditionType type = WiredConditionType.USER_COUNT;
static final int MAX_USER_COUNT_LIMIT = 1000;
private int lowerLimit = 0;
private int upperLimit = 50;
@@ -31,6 +32,10 @@ public class WiredConditionHabboCount extends InteractionWiredCondition {
@Override
public boolean evaluate(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
int count = (this.userSource == WiredSourceUtil.SOURCE_TRIGGER)
? ctx.room().getUserCount()
: WiredSourceUtil.resolveUsers(ctx, this.userSource).size();
@@ -55,26 +60,29 @@ public class WiredConditionHabboCount extends InteractionWiredCondition {
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.lowerLimit = data.lowerLimit;
this.upperLimit = data.upperLimit;
this.userSource = data.userSource;
this.applyLimits(data.lowerLimit, data.upperLimit);
this.userSource = WiredConditionInputGuard.normalizeUserSource(data.userSource);
} else {
String[] data = wiredData.split(":");
if (data.length >= 2) {
try {
this.lowerLimit = Integer.parseInt(data[0].trim());
this.upperLimit = Integer.parseInt(data[1].trim());
this.applyLimits(Integer.parseInt(data[0].trim()), Integer.parseInt(data[1].trim()));
} catch (NumberFormatException ignored) {
// malformed legacy data keep the constructed defaults
}
}
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
}
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
}
@Override
@@ -110,14 +118,19 @@ public class WiredConditionHabboCount extends InteractionWiredCondition {
@Override
public boolean saveData(WiredSettings settings) {
if(settings.getIntParams().length < 2) return false;
this.lowerLimit = settings.getIntParams()[0];
this.upperLimit = settings.getIntParams()[1];
int[] params = settings.getIntParams();
this.userSource = (params.length > 2) ? params[2] : WiredSourceUtil.SOURCE_TRIGGER;
this.applyLimits(params[0], params[1]);
this.userSource = (params.length > 2) ? WiredConditionInputGuard.normalizeUserSource(params[2]) : WiredSourceUtil.SOURCE_TRIGGER;
return true;
}
private void applyLimits(int lowerLimit, int upperLimit) {
int[] limits = WiredConditionInputGuard.normalizeUserCountRange(lowerLimit, upperLimit);
this.lowerLimit = limits[0];
this.upperLimit = limits[1];
}
static class JsonData {
int lowerLimit;
int upperLimit;
@@ -18,6 +18,7 @@ import java.util.List;
public class WiredConditionHabboHasEffect extends InteractionWiredCondition {
protected static final int QUANTIFIER_ALL = 0;
protected static final int QUANTIFIER_ANY = 1;
protected static final int MAX_EFFECT_ID = 10_000;
public static final WiredConditionType type = WiredConditionType.ACTOR_WEARS_EFFECT;
@@ -86,15 +87,34 @@ public class WiredConditionHabboHasEffect extends InteractionWiredCondition {
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
this.onPickUp();
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.effectId = data.effectId;
this.userSource = data.userSource;
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException ignored) {
this.onPickUp();
return;
}
if (data == null) {
this.onPickUp();
return;
}
this.effectId = WiredUserConditionInputGuard.normalizeEffectId(data.effectId);
this.userSource = WiredUserConditionInputGuard.normalizeUserSource(data.userSource);
this.quantifier = this.normalizeQuantifier(data.quantifier, QUANTIFIER_ANY);
} else {
this.effectId = Integer.parseInt(wiredData);
try {
this.effectId = WiredUserConditionInputGuard.normalizeEffectId(Integer.parseInt(wiredData));
} catch (NumberFormatException ignored) {
this.effectId = 0;
}
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = QUANTIFIER_ANY;
}
@@ -134,8 +154,8 @@ public class WiredConditionHabboHasEffect extends InteractionWiredCondition {
public boolean saveData(WiredSettings settings) {
if(settings.getIntParams().length < 1) return false;
int[] params = settings.getIntParams();
this.effectId = params[0];
this.userSource = (params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER;
this.effectId = WiredUserConditionInputGuard.normalizeEffectId(params[0]);
this.userSource = (params.length > 1) ? WiredUserConditionInputGuard.normalizeUserSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = (params.length > 2) ? this.normalizeQuantifier(params[2], QUANTIFIER_ANY) : QUANTIFIER_ANY;
return true;
@@ -153,6 +173,14 @@ public class WiredConditionHabboHasEffect extends InteractionWiredCondition {
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL;
}
protected int normalizeEffectId(int value) {
return Math.max(0, Math.min(MAX_EFFECT_ID, value));
}
protected int normalizeUserSource(int value) {
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
}
static class JsonData {
int effectId;
int userSource;
@@ -10,17 +10,15 @@ import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
public class WiredConditionHabboHasHandItem extends InteractionWiredCondition {
private static final Logger LOGGER = LoggerFactory.getLogger(WiredConditionHabboHasHandItem.class);
protected static final int QUANTIFIER_ALL = 0;
protected static final int QUANTIFIER_ANY = 1;
protected static final int MAX_HAND_ITEM_ID = 10_000;
public static final WiredConditionType type = WiredConditionType.ACTOR_HAS_HANDITEM;
@@ -62,9 +60,9 @@ public class WiredConditionHabboHasHandItem extends InteractionWiredCondition {
@Override
public boolean saveData(WiredSettings settings) {
if(settings.getIntParams().length < 1) return false;
this.handItem = this.normalizeHandItem(settings.getIntParams()[0]);
this.handItem = WiredUserConditionInputGuard.normalizeHandItemId(settings.getIntParams()[0]);
int[] params = settings.getIntParams();
this.userSource = (params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER;
this.userSource = (params.length > 1) ? WiredUserConditionInputGuard.normalizeUserSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = (params.length > 2) ? this.normalizeQuantifier(params[2]) : QUANTIFIER_ALL;
return true;
@@ -99,22 +97,36 @@ public class WiredConditionHabboHasHandItem extends InteractionWiredCondition {
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
try {
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
this.onPickUp();
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.handItem = this.normalizeHandItem(data.handItemId);
this.userSource = data.userSource;
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException ignored) {
this.onPickUp();
return;
}
if (data == null) {
this.onPickUp();
return;
}
this.handItem = WiredUserConditionInputGuard.normalizeHandItemId(data.handItemId);
this.userSource = WiredUserConditionInputGuard.normalizeUserSource(data.userSource);
this.quantifier = this.normalizeQuantifier(data.quantifier);
} else {
this.handItem = this.normalizeHandItem(Integer.parseInt(wiredData));
try {
this.handItem = WiredUserConditionInputGuard.normalizeHandItemId(Integer.parseInt(wiredData));
} catch (NumberFormatException ignored) {
this.handItem = 0;
}
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = QUANTIFIER_ALL;
}
} catch (Exception e) {
LOGGER.error("Caught exception", e);
}
}
@Override
@@ -156,14 +168,14 @@ public class WiredConditionHabboHasHandItem extends InteractionWiredCondition {
return true;
}
protected int normalizeHandItem(int value) {
return Math.max(0, value);
}
protected int normalizeQuantifier(int value) {
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL;
}
protected int normalizeUserSource(int value) {
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
}
static class JsonData {
int handItemId;
int userSource;
@@ -20,6 +20,7 @@ import java.util.List;
public class WiredConditionHabboWearsBadge extends InteractionWiredCondition {
protected static final int QUANTIFIER_ALL = 0;
protected static final int QUANTIFIER_ANY = 1;
protected static final int MAX_BADGE_CODE_LENGTH = 64;
public static final WiredConditionType type = WiredConditionType.ACTOR_WEARS_BADGE;
@@ -37,6 +38,10 @@ public class WiredConditionHabboWearsBadge extends InteractionWiredCondition {
@Override
public boolean evaluate(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
Room room = ctx.room();
List<RoomUnit> targets = WiredSourceUtil.resolveUsers(ctx, this.userSource);
if (targets.isEmpty()) return false;
@@ -102,15 +107,30 @@ public class WiredConditionHabboWearsBadge extends InteractionWiredCondition {
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null) {
this.onPickUp();
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.badge = data.badge;
this.userSource = data.userSource;
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException ignored) {
this.onPickUp();
return;
}
if (data == null) {
this.onPickUp();
return;
}
this.badge = WiredUserConditionInputGuard.normalizeBadgeCode(data.badge);
this.userSource = WiredUserConditionInputGuard.normalizeUserSource(data.userSource);
this.quantifier = this.normalizeQuantifier(data.quantifier, QUANTIFIER_ANY);
} else {
this.badge = wiredData;
this.badge = WiredUserConditionInputGuard.normalizeBadgeCode(wiredData);
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = QUANTIFIER_ANY;
}
@@ -147,9 +167,9 @@ public class WiredConditionHabboWearsBadge extends InteractionWiredCondition {
@Override
public boolean saveData(WiredSettings settings) {
this.badge = settings.getStringParam();
this.badge = WiredUserConditionInputGuard.normalizeBadgeCode(settings.getStringParam());
int[] params = settings.getIntParams();
this.userSource = (params.length > 0) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER;
this.userSource = (params.length > 0) ? WiredUserConditionInputGuard.normalizeUserSource(params[0]) : WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = (params.length > 1) ? this.normalizeQuantifier(params[1], QUANTIFIER_ANY) : QUANTIFIER_ANY;
return true;
@@ -167,6 +187,19 @@ public class WiredConditionHabboWearsBadge extends InteractionWiredCondition {
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL;
}
protected String normalizeBadge(String value) {
if (value == null) {
return "";
}
String normalized = value.trim();
return normalized.length() <= MAX_BADGE_CODE_LENGTH ? normalized : normalized.substring(0, MAX_BADGE_CODE_LENGTH);
}
protected int normalizeUserSource(int value) {
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
}
static class JsonData {
String badge;
int userSource;
@@ -97,7 +97,14 @@ public class WiredConditionHasAltitude extends InteractionWiredCondition {
return;
}
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException exception) {
this.onPickUp();
return;
}
if (data == null) {
return;
}
@@ -112,6 +119,10 @@ public class WiredConditionHasAltitude extends InteractionWiredCondition {
}
for (Integer id : data.itemIds) {
if (id == null) {
continue;
}
HabboItem item = room.getHabboItem(id);
if (item != null) {
this.items.add(item);
@@ -225,7 +236,7 @@ public class WiredConditionHasAltitude extends InteractionWiredCondition {
}
}
private int normalizeComparison(int value) {
int normalizeComparison(int value) {
if (value < COMPARISON_LESS || value > COMPARISON_GREATER) {
return COMPARISON_EQUAL;
}
@@ -233,11 +244,11 @@ public class WiredConditionHasAltitude extends InteractionWiredCondition {
return value;
}
private int normalizeQuantifier(int value) {
int normalizeQuantifier(int value) {
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL;
}
private int normalizeFurniSource(int value) {
int normalizeFurniSource(int value) {
switch (value) {
case WiredSourceUtil.SOURCE_SELECTED:
case WiredSourceUtil.SOURCE_SELECTOR:
@@ -249,12 +260,12 @@ public class WiredConditionHasAltitude extends InteractionWiredCondition {
}
}
private double normalizeAltitude(double value) {
double normalizeAltitude(double value) {
double clampedValue = Math.max(0.0D, Math.min(Room.MAXIMUM_FURNI_HEIGHT, value));
return BigDecimal.valueOf(clampedValue).setScale(2, RoundingMode.HALF_UP).doubleValue();
}
private double parseAltitudeOrDefault(String value) {
double parseAltitudeOrDefault(String value) {
if (value == null || value.trim().isEmpty()) {
return 0.0D;
}
@@ -266,7 +277,7 @@ public class WiredConditionHasAltitude extends InteractionWiredCondition {
}
}
private String formatAltitude(double value) {
String formatAltitude(double value) {
BigDecimal decimal = BigDecimal.valueOf(this.normalizeAltitude(value)).stripTrailingZeros();
return (decimal.scale() < 0 ? decimal.setScale(0, RoundingMode.DOWN) : decimal).toPlainString();
}
@@ -0,0 +1,57 @@
package com.eu.habbo.habbohotel.items.interactions.wired.conditions;
import com.eu.habbo.habbohotel.games.GameTeamColors;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
public final class WiredConditionInputGuard {
public static final int MAX_USER_COUNT_LIMIT = 1000;
public static final int MAX_TIMER_CYCLES = 24 * 60 * 60 * 2;
private WiredConditionInputGuard() {
}
public static GameTeamColors normalizeTeamColor(GameTeamColors value, GameTeamColors fallback) {
return (value != null) ? value : fallback;
}
public static GameTeamColors normalizeTeamColorType(int value, GameTeamColors fallback) {
for (GameTeamColors color : GameTeamColors.values()) {
if (color.type == value) {
return color;
}
}
return fallback;
}
public static int normalizeUserSource(int value) {
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
}
public static int normalizeTimerCycles(int value) {
if (value < 0) {
return 0;
}
return Math.min(value, MAX_TIMER_CYCLES);
}
public static int[] normalizeUserCountRange(int lowerLimit, int upperLimit) {
int lower = clampUserCount(lowerLimit);
int upper = clampUserCount(upperLimit);
if (lower > upper) {
return new int[]{upper, lower};
}
return new int[]{lower, upper};
}
private static int clampUserCount(int value) {
if (value < 0) {
return 0;
}
return Math.min(value, MAX_USER_COUNT_LIMIT);
}
}
@@ -52,12 +52,13 @@ public class WiredConditionLessTimeElapsed extends InteractionWiredCondition {
try {
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.cycles = data.cycles;
this.cycles = WiredConditionInputGuard.normalizeTimerCycles(data.cycles);
} else {
if (!wiredData.equals(""))
this.cycles = Integer.parseInt(wiredData);
this.cycles = WiredConditionInputGuard.normalizeTimerCycles(Integer.parseInt(wiredData));
}
} catch (Exception e) {
this.cycles = 0;
}
}
@@ -90,10 +91,14 @@ public class WiredConditionLessTimeElapsed extends InteractionWiredCondition {
@Override
public boolean saveData(WiredSettings settings) {
if(settings.getIntParams().length < 1) return false;
this.cycles = settings.getIntParams()[0];
this.cycles = WiredConditionInputGuard.normalizeTimerCycles(settings.getIntParams()[0]);
return true;
}
int normalizeCycles(int value) {
return Math.max(0, Math.min(WiredConditionMoreTimeElapsed.MAX_CYCLES, value));
}
static class JsonData {
int cycles;
@@ -125,7 +125,14 @@ public class WiredConditionMatchDate extends InteractionWiredCondition {
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException exception) {
this.reset();
return;
}
if (data == null) {
return;
}
@@ -193,7 +200,7 @@ public class WiredConditionMatchDate extends InteractionWiredCondition {
}
}
private int normalizeMode(int value) {
int normalizeMode(int value) {
if (value < MODE_SKIP || value > MODE_RANGE) {
return MODE_SKIP;
}
@@ -201,20 +208,20 @@ public class WiredConditionMatchDate extends InteractionWiredCondition {
return value;
}
private int normalizeDay(int value) {
int normalizeDay(int value) {
return Math.max(1, Math.min(31, value));
}
private int normalizeYear(int value) {
int normalizeYear(int value) {
return Math.max(1, Math.min(9999, value));
}
private int normalizeWeekdayMask(int value) {
int normalizeWeekdayMask(int value) {
int normalized = value & ALL_WEEKDAYS_MASK;
return (normalized == 0) ? ALL_WEEKDAYS_MASK : normalized;
}
private int normalizeMonthMask(int value) {
int normalizeMonthMask(int value) {
int normalized = value & ALL_MONTHS_MASK;
return (normalized == 0) ? ALL_MONTHS_MASK : normalized;
}
@@ -87,7 +87,7 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
this.direction = params[1] == 1;
this.position = params[2] == 1;
this.altitude = (params.length > 3) && (params[3] == 1);
this.furniSource = (params.length > 4) ? params[4] : ((params.length > 3 && params[3] > 1) ? params[3] : WiredSourceUtil.SOURCE_TRIGGER);
this.furniSource = (params.length > 4) ? WiredMatchPositionInputGuard.normalizeFurniSource(params[4], false) : ((params.length > 3 && params[3] > 1) ? WiredMatchPositionInputGuard.normalizeFurniSource(params[3], false) : WiredSourceUtil.SOURCE_TRIGGER);
this.quantifier = (params.length > 5) ? this.normalizeQuantifier(params[5]) : QUANTIFIER_ALL;
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
@@ -108,11 +108,17 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
this.settings.add(new WiredMatchFurniSetting(item.getId(), item.getExtradata(), item.getRotation(), item.getX(), item.getY(), item.getZ()));
}
this.furniSource = WiredMatchPositionInputGuard.normalizeFurniSource(this.furniSource, !this.settings.isEmpty());
return true;
}
@Override
public boolean evaluate(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
this.refresh();
if (this.settings.isEmpty())
@@ -126,6 +132,10 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
}
protected boolean evaluateAllTargetsMatch(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
Room room = ctx.room();
if (this.furniSource != WiredSourceUtil.SOURCE_SELECTED) {
@@ -159,6 +169,10 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
}
protected boolean evaluateAnyTargetMatches(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
Room room = ctx.room();
if (this.furniSource != WiredSourceUtil.SOURCE_SELECTED) {
@@ -247,35 +261,46 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException exception) {
this.onPickUp();
return;
}
if (data == null) {
return;
}
this.state = data.state;
this.position = data.position;
this.direction = data.direction;
this.altitude = data.altitude;
if (data.settings != null) {
this.settings.addAll(data.settings);
}
this.furniSource = data.furniSource;
this.settings.addAll(WiredMatchPositionInputGuard.sanitizeSettings(data.settings, room));
this.furniSource = WiredMatchPositionInputGuard.normalizeFurniSource(data.furniSource, !this.settings.isEmpty());
this.quantifier = this.normalizeQuantifier(data.quantifier);
} else {
String[] data = wiredData.split(":");
if (data.length >= 5) {
try {
int itemCount = Integer.parseInt(data[0]);
int itemCount = Math.min(Integer.parseInt(data[0]), WiredManager.MAXIMUM_FURNI_SELECTION);
String[] items = data[1].split(";");
for (int i = 0; i < itemCount && i < items.length; i++) {
String[] stuff = items[i].split("-");
if (stuff.length >= 6)
this.settings.add(new WiredMatchFurniSetting(Integer.parseInt(stuff[0]), stuff[1], Integer.parseInt(stuff[2]), Integer.parseInt(stuff[3]), Integer.parseInt(stuff[4]), Double.parseDouble(stuff[5])));
else if (stuff.length >= 5)
this.settings.add(new WiredMatchFurniSetting(Integer.parseInt(stuff[0]), stuff[1], Integer.parseInt(stuff[2]), Integer.parseInt(stuff[3]), Integer.parseInt(stuff[4])));
WiredMatchFurniSetting setting = this.parseLegacySetting(items[i], room);
if (setting != null) {
this.settings.add(setting);
}
}
this.state = data[2].equals("1");
@@ -287,11 +312,33 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
}
this.altitude = false;
this.furniSource = this.settings.isEmpty() ? WiredSourceUtil.SOURCE_TRIGGER : WiredSourceUtil.SOURCE_SELECTED;
this.furniSource = WiredMatchPositionInputGuard.normalizeFurniSource(WiredSourceUtil.SOURCE_TRIGGER, !this.settings.isEmpty());
this.quantifier = QUANTIFIER_ALL;
}
}
private WiredMatchFurniSetting parseLegacySetting(String value, Room room) {
String[] parts = value.split("-", 6);
if (parts.length < 5) {
return null;
}
try {
double z = (parts.length >= 6) ? Double.parseDouble(parts[5]) : 0.0D;
return WiredMatchPositionInputGuard.sanitizeParts(
Integer.parseInt(parts[0]),
parts[1],
Integer.parseInt(parts[2]),
Integer.parseInt(parts[3]),
Integer.parseInt(parts[4]),
z,
room
);
} catch (NumberFormatException ignored) {
return null;
}
}
@Override
public void onPickUp() {
this.settings.clear();
@@ -303,10 +350,58 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
this.quantifier = QUANTIFIER_ALL;
}
private int normalizeQuantifier(int value) {
int normalizeQuantifier(int value) {
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL;
}
int normalizeFurniSource(int value) {
switch (value) {
case WiredSourceUtil.SOURCE_TRIGGER:
case WiredSourceUtil.SOURCE_SELECTED:
case WiredSourceUtil.SOURCE_SELECTOR:
case WiredSourceUtil.SOURCE_SIGNAL:
return value;
default:
return WiredSourceUtil.SOURCE_TRIGGER;
}
}
WiredMatchFurniSetting normalizeSetting(WiredMatchFurniSetting setting) {
if (setting == null || setting.item_id <= 0) {
return null;
}
int rotation = Math.max(0, Math.min(7, setting.rotation));
int x = Math.max(0, setting.x);
int y = Math.max(0, setting.y);
double z = Math.max(0.0D, Math.min(Room.MAXIMUM_FURNI_HEIGHT, setting.z));
return new WiredMatchFurniSetting(setting.item_id, setting.state, rotation, x, y, z);
}
WiredMatchFurniSetting parseLegacySetting(String[] values) {
if (values == null || values.length < 5) {
return null;
}
try {
int itemId = Integer.parseInt(values[0]);
if (itemId <= 0) {
return null;
}
String state = values[1];
int rotation = Integer.parseInt(values[2]);
int x = Integer.parseInt(values[3]);
int y = Integer.parseInt(values[4]);
double z = values.length >= 6 ? Double.parseDouble(values[5]) : 0.0D;
return this.normalizeSetting(new WiredMatchFurniSetting(itemId, state, rotation, x, y, z));
} catch (RuntimeException exception) {
return null;
}
}
protected void refresh() {
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
@@ -126,7 +126,14 @@ public class WiredConditionMatchTime extends InteractionWiredCondition {
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException exception) {
this.reset();
return;
}
if (data == null) {
return;
}
@@ -195,7 +202,7 @@ public class WiredConditionMatchTime extends InteractionWiredCondition {
}
}
private int normalizeMode(int value) {
int normalizeMode(int value) {
if (value < MODE_SKIP || value > MODE_RANGE) {
return MODE_SKIP;
}
@@ -203,11 +210,11 @@ public class WiredConditionMatchTime extends InteractionWiredCondition {
return value;
}
private int normalizeHour(int value) {
int normalizeHour(int value) {
return Math.max(0, Math.min(23, value));
}
private int normalizeMinuteOrSecond(int value) {
int normalizeMinuteOrSecond(int value) {
return Math.max(0, Math.min(59, value));
}
@@ -16,6 +16,7 @@ import java.sql.SQLException;
public class WiredConditionMoreTimeElapsed extends InteractionWiredCondition {
private static final WiredConditionType type = WiredConditionType.TIME_MORE_THAN;
static final int MAX_CYCLES = 1_000_000;
private int cycles;
@@ -52,12 +53,13 @@ public class WiredConditionMoreTimeElapsed extends InteractionWiredCondition {
try {
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.cycles = data.cycles;
this.cycles = WiredConditionInputGuard.normalizeTimerCycles(data.cycles);
} else {
if (!wiredData.equals(""))
this.cycles = Integer.parseInt(wiredData);
this.cycles = WiredConditionInputGuard.normalizeTimerCycles(Integer.parseInt(wiredData));
}
} catch (Exception e) {
this.cycles = 0;
}
}
@@ -90,10 +92,14 @@ public class WiredConditionMoreTimeElapsed extends InteractionWiredCondition {
@Override
public boolean saveData(WiredSettings settings) {
if(settings.getIntParams().length < 1) return false;
this.cycles = settings.getIntParams()[0];
this.cycles = WiredConditionInputGuard.normalizeTimerCycles(settings.getIntParams()[0]);
return true;
}
int normalizeCycles(int value) {
return Math.max(0, Math.min(MAX_CYCLES, value));
}
static class JsonData {
int cycles;
@@ -99,9 +99,9 @@ public class WiredConditionNotFurniHaveFurni extends InteractionWiredCondition {
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.all = data.all;
this.furniSource = data.furniSource;
this.furniSource = WiredFurniConditionInputGuard.normalizeFurniSource(data.furniSource);
for (int id : data.itemIds) {
for (int id : WiredFurniConditionInputGuard.sanitizeItemIds(data.itemIds, WiredManager.MAXIMUM_FURNI_SELECTION)) {
HabboItem item = room.getHabboItem(id);
if (item != null) {
@@ -115,10 +115,8 @@ public class WiredConditionNotFurniHaveFurni extends InteractionWiredCondition {
this.all = (data[0].equals("1"));
if (data.length == 2) {
String[] items = data[1].split(";");
for (String s : items) {
HabboItem item = room.getHabboItem(Integer.parseInt(s));
for (int id : WiredFurniConditionInputGuard.parseLegacyItemIds(data[1], WiredManager.MAXIMUM_FURNI_SELECTION)) {
HabboItem item = room.getHabboItem(id);
if (item != null)
this.items.add(item);
@@ -127,9 +125,7 @@ public class WiredConditionNotFurniHaveFurni extends InteractionWiredCondition {
}
this.furniSource = this.items.isEmpty() ? WiredSourceUtil.SOURCE_TRIGGER : WiredSourceUtil.SOURCE_SELECTED;
}
if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
this.furniSource = WiredFurniConditionInputGuard.selectedOrNormalizedFurniSource(this.furniSource, !this.items.isEmpty());
}
@Override
@@ -172,14 +168,12 @@ public class WiredConditionNotFurniHaveFurni extends InteractionWiredCondition {
if(settings.getIntParams().length < 1) return false;
int[] params = settings.getIntParams();
this.all = params[0] == 1;
this.furniSource = (params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER;
this.furniSource = (params.length > 1) ? WiredFurniConditionInputGuard.normalizeFurniSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER;
int count = settings.getFurniIds().length;
if (count > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) return false;
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
this.furniSource = WiredFurniConditionInputGuard.selectedOrNormalizedFurniSource(this.furniSource, count > 0);
this.items.clear();
@@ -95,10 +95,10 @@ public class WiredConditionNotFurniHaveHabbo extends InteractionWiredCondition {
if (wiredData.startsWith("{")) {
WiredConditionFurniHaveHabbo.JsonData data = WiredManager.getGson().fromJson(wiredData, WiredConditionFurniHaveHabbo.JsonData.class);
this.furniSource = data.furniSource;
this.furniSource = WiredFurniConditionInputGuard.normalizeFurniSource(data.furniSource);
this.all = data.all;
for(int id : data.itemIds) {
for(int id : WiredFurniConditionInputGuard.sanitizeItemIds(data.itemIds, WiredManager.MAXIMUM_FURNI_SELECTION)) {
HabboItem item = room.getHabboItem(id);
if (item != null) {
@@ -108,11 +108,9 @@ public class WiredConditionNotFurniHaveHabbo extends InteractionWiredCondition {
} else {
String[] data = wiredData.split(":");
if (data.length >= 1) {
String[] items = data[1].split(";");
for (String s : items) {
HabboItem item = room.getHabboItem(Integer.parseInt(s));
if (data.length >= 2) {
for (int id : WiredFurniConditionInputGuard.parseLegacyItemIds(data[1], WiredManager.MAXIMUM_FURNI_SELECTION)) {
HabboItem item = room.getHabboItem(id);
if (item != null)
this.items.add(item);
@@ -121,9 +119,7 @@ public class WiredConditionNotFurniHaveHabbo extends InteractionWiredCondition {
this.furniSource = this.items.isEmpty() ? WiredSourceUtil.SOURCE_TRIGGER : WiredSourceUtil.SOURCE_SELECTED;
this.all = false;
}
if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
this.furniSource = WiredFurniConditionInputGuard.selectedOrNormalizedFurniSource(this.furniSource, !this.items.isEmpty());
}
@Override
@@ -161,11 +157,9 @@ public class WiredConditionNotFurniHaveHabbo extends InteractionWiredCondition {
int[] params = settings.getIntParams();
this.all = (params.length > 0) && (params[0] == 1);
this.furniSource = (params.length > 1) ? params[1] : ((params.length > 0 && params[0] > 1) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER);
this.furniSource = (params.length > 1) ? WiredFurniConditionInputGuard.normalizeFurniSource(params[1]) : ((params.length > 0 && params[0] > 1) ? WiredFurniConditionInputGuard.normalizeFurniSource(params[0]) : WiredSourceUtil.SOURCE_TRIGGER);
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
this.furniSource = WiredFurniConditionInputGuard.selectedOrNormalizedFurniSource(this.furniSource, count > 0);
this.items.clear();
@@ -20,6 +20,10 @@ public class WiredConditionNotFurniTypeMatch extends WiredConditionFurniTypeMatc
@Override
public boolean evaluate(WiredContext ctx) {
if (ctx == null) {
return false;
}
if (this.getQuantifier() == QUANTIFIER_ANY) {
return !this.evaluateAllMatches(ctx);
}
@@ -6,8 +6,8 @@ import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.wired.WiredConditionType;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
@@ -31,6 +31,10 @@ public class WiredConditionNotHabboCount extends InteractionWiredCondition {
@Override
public boolean evaluate(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
int count = (this.userSource == WiredSourceUtil.SOURCE_TRIGGER)
? ctx.room().getUserCount()
: WiredSourceUtil.resolveUsers(ctx, this.userSource).size();
@@ -55,31 +59,34 @@ public class WiredConditionNotHabboCount extends InteractionWiredCondition {
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
return;
}
if (wiredData.startsWith("{")) {
WiredConditionHabboCount.JsonData data = WiredManager.getGson().fromJson(wiredData, WiredConditionHabboCount.JsonData.class);
this.lowerLimit = data.lowerLimit;
this.upperLimit = data.upperLimit;
this.userSource = data.userSource;
this.applyLimits(data.lowerLimit, data.upperLimit);
this.userSource = WiredConditionInputGuard.normalizeUserSource(data.userSource);
} else {
String[] data = wiredData.split(":");
if (data.length >= 2) {
try {
this.lowerLimit = Integer.parseInt(data[0].trim());
this.upperLimit = Integer.parseInt(data[1].trim());
this.applyLimits(Integer.parseInt(data[0].trim()), Integer.parseInt(data[1].trim()));
} catch (NumberFormatException ignored) {
// malformed legacy data keep the constructed defaults
}
}
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
}
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
}
@Override
public void onPickUp() {
this.upperLimit = 0;
this.lowerLimit = 20;
this.lowerLimit = 10;
this.upperLimit = 20;
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
}
@@ -109,14 +116,19 @@ public class WiredConditionNotHabboCount extends InteractionWiredCondition {
@Override
public boolean saveData(WiredSettings settings) {
if(settings.getIntParams().length < 2) return false;
this.lowerLimit = settings.getIntParams()[0];
this.upperLimit = settings.getIntParams()[1];
int[] params = settings.getIntParams();
this.userSource = (params.length > 2) ? params[2] : WiredSourceUtil.SOURCE_TRIGGER;
this.applyLimits(params[0], params[1]);
this.userSource = (params.length > 2) ? WiredConditionInputGuard.normalizeUserSource(params[2]) : WiredSourceUtil.SOURCE_TRIGGER;
return true;
}
private void applyLimits(int lowerLimit, int upperLimit) {
int[] limits = WiredConditionInputGuard.normalizeUserCountRange(lowerLimit, upperLimit);
this.lowerLimit = limits[0];
this.upperLimit = limits[1];
}
static class JsonData {
int lowerLimit;
int upperLimit;
@@ -22,6 +22,10 @@ public class WiredConditionNotMatchStatePosition extends WiredConditionMatchStat
@Override
public boolean evaluate(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
this.refresh();
if (this.getMatchFurniSettings().isEmpty()) {
@@ -29,6 +29,7 @@ abstract class WiredConditionTeamGameBase extends InteractionWiredCondition {
protected static final int COMPARISON_EQUAL = 1;
protected static final int COMPARISON_HIGHER = 2;
protected static final int TEAM_TRIGGERER = 0;
protected static final int MAX_SCORE = 1_000_000;
private static final GameTeamColors[] SUPPORTED_TEAM_COLORS = new GameTeamColors[] {
GameTeamColors.RED,
@@ -96,7 +97,11 @@ abstract class WiredConditionTeamGameBase extends InteractionWiredCondition {
}
protected int normalizeScore(int value) {
return Math.max(0, value);
if (value < 0) {
return 0;
}
return Math.min(value, MAX_SCORE);
}
protected int normalizeExplicitTeamType(int value) {
@@ -65,7 +65,13 @@ public class WiredConditionTeamHasRank extends WiredConditionTeamGameBase {
return;
}
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException ignored) {
this.resetSettings();
return;
}
if (data == null) {
return;
}
@@ -66,7 +66,13 @@ public class WiredConditionTeamHasScore extends WiredConditionTeamGameBase {
return;
}
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException ignored) {
this.resetSettings();
return;
}
if (data == null) {
return;
}
@@ -97,12 +97,12 @@ public class WiredConditionTeamMember extends InteractionWiredCondition {
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.teamColor = data.teamColor;
this.userSource = data.userSource;
this.teamColor = WiredConditionInputGuard.normalizeTeamColor(data.teamColor, GameTeamColors.RED);
this.userSource = WiredConditionInputGuard.normalizeUserSource(data.userSource);
this.quantifier = this.normalizeQuantifier(data.quantifier, QUANTIFIER_ANY);
} else {
if (!wiredData.equals(""))
this.teamColor = GameTeamColors.values()[Integer.parseInt(wiredData)];
this.teamColor = WiredConditionInputGuard.normalizeTeamColorType(Integer.parseInt(wiredData), GameTeamColors.RED);
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = QUANTIFIER_ANY;
}
@@ -147,8 +147,8 @@ public class WiredConditionTeamMember extends InteractionWiredCondition {
public boolean saveData(WiredSettings settings) {
if(settings.getIntParams().length < 1) return false;
int[] params = settings.getIntParams();
this.teamColor = GameTeamColors.values()[params[0]];
this.userSource = (params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER;
this.teamColor = WiredConditionInputGuard.normalizeTeamColorType(params[0], GameTeamColors.RED);
this.userSource = (params.length > 1) ? WiredConditionInputGuard.normalizeUserSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = (params.length > 2) ? this.normalizeQuantifier(params[2], QUANTIFIER_ALL) : QUANTIFIER_ANY;
return true;
@@ -42,6 +42,10 @@ public class WiredConditionTriggerOnFurni extends InteractionWiredCondition {
@Override
public boolean evaluate(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
this.refresh();
List<RoomUnit> userTargets = WiredSourceUtil.resolveUsers(ctx, this.userSource);
@@ -104,39 +108,42 @@ public class WiredConditionTriggerOnFurni extends InteractionWiredCondition {
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.items.clear();
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.furniSource = data.furniSource;
this.userSource = data.userSource;
this.furniSource = WiredFurniConditionInputGuard.normalizeFurniSource(data.furniSource);
this.userSource = WiredFurniConditionInputGuard.normalizeUserSource(data.userSource);
this.quantifier = this.normalizeQuantifier(data.quantifier);
for(int id : data.itemIds) {
for(int id : WiredFurniConditionInputGuard.sanitizeItemIds(data.itemIds, WiredManager.MAXIMUM_FURNI_SELECTION)) {
HabboItem item = room.getHabboItem(id);
HabboItem item = room.getHabboItem(id);
if (item != null) {
this.items.add(item);
}
}
}
} else {
for (int id : WiredFurniConditionInputGuard.parseLegacyItemIds(wiredData, WiredManager.MAXIMUM_FURNI_SELECTION)) {
HabboItem item = room.getHabboItem(id);
if (item != null) {
this.items.add(item);
}
}
} else {
String[] data = wiredData.split(";");
for (String s : data) {
HabboItem item = room.getHabboItem(Integer.parseInt(s));
if (item != null) {
this.items.add(item);
} catch (NumberFormatException ignored) {
}
}
this.furniSource = this.items.isEmpty() ? WiredSourceUtil.SOURCE_TRIGGER : WiredSourceUtil.SOURCE_SELECTED;
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = QUANTIFIER_ALL;
}
if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
this.furniSource = WiredFurniConditionInputGuard.selectedOrNormalizedFurniSource(this.furniSource, !this.items.isEmpty());
}
@Override
@@ -182,13 +189,11 @@ public class WiredConditionTriggerOnFurni extends InteractionWiredCondition {
if (count > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) return false;
int[] params = settings.getIntParams();
this.furniSource = (params.length > 0) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER;
this.userSource = (params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER;
this.furniSource = (params.length > 0) ? WiredFurniConditionInputGuard.normalizeFurniSource(params[0]) : WiredSourceUtil.SOURCE_TRIGGER;
this.userSource = (params.length > 1) ? WiredFurniConditionInputGuard.normalizeUserSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER;
this.quantifier = (params.length > 2) ? this.normalizeQuantifier(params[2]) : QUANTIFIER_ALL;
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
this.furniSource = WiredFurniConditionInputGuard.selectedOrNormalizedFurniSource(this.furniSource, count > 0);
this.items.clear();
@@ -233,6 +238,22 @@ public class WiredConditionTriggerOnFurni extends InteractionWiredCondition {
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL;
}
int normalizeFurniSource(int value) {
switch (value) {
case WiredSourceUtil.SOURCE_SELECTED:
case WiredSourceUtil.SOURCE_SELECTOR:
case WiredSourceUtil.SOURCE_SIGNAL:
case WiredSourceUtil.SOURCE_TRIGGER:
return value;
default:
return WiredSourceUtil.SOURCE_TRIGGER;
}
}
int normalizeUserSource(int value) {
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
}
@Override
public WiredConditionOperator operator() {
return WiredConditionOperator.AND;
@@ -33,6 +33,7 @@ public class WiredConditionTriggererMatch extends InteractionWiredCondition {
protected static final int QUANTIFIER_ALL = 0;
protected static final int QUANTIFIER_ANY = 1;
protected static final int SOURCE_SPECIFIED_USERNAME = 101;
protected static final int MAX_USERNAME_LENGTH = 64;
public static final WiredConditionType type = WiredConditionType.TRIGGERER_MATCH;
@@ -84,7 +85,14 @@ public class WiredConditionTriggererMatch extends InteractionWiredCondition {
return;
}
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException exception) {
this.resetSettings();
return;
}
if (data == null) {
return;
}
@@ -284,7 +292,7 @@ public class WiredConditionTriggererMatch extends InteractionWiredCondition {
return "";
}
private int normalizeEntityType(int value) {
int normalizeEntityType(int value) {
switch (value) {
case ENTITY_HABBO:
case ENTITY_PET:
@@ -295,19 +303,19 @@ public class WiredConditionTriggererMatch extends InteractionWiredCondition {
}
}
private int normalizeAvatarMode(int value) {
int normalizeAvatarMode(int value) {
return (value == AVATAR_MODE_CERTAIN) ? AVATAR_MODE_CERTAIN : AVATAR_MODE_ANY;
}
private int normalizeQuantifier(int value) {
int normalizeQuantifier(int value) {
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL;
}
private int normalizePrimaryUserSource(int value) {
int normalizePrimaryUserSource(int value) {
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
}
private int normalizeCompareUserSource(int value) {
int normalizeCompareUserSource(int value) {
switch (value) {
case WiredSourceUtil.SOURCE_CLICKED_USER:
case SOURCE_SPECIFIED_USERNAME:
@@ -317,8 +325,13 @@ public class WiredConditionTriggererMatch extends InteractionWiredCondition {
}
}
private String normalizeUsername(String value) {
return (value == null) ? "" : value.trim();
String normalizeUsername(String value) {
if (value == null) {
return "";
}
String normalized = value.trim();
return normalized.length() <= MAX_USERNAME_LENGTH ? normalized : normalized.substring(0, MAX_USERNAME_LENGTH);
}
protected static class MatchResult {
@@ -87,7 +87,13 @@ public class WiredConditionUserPerformsAction extends InteractionWiredCondition
return;
}
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException ignored) {
this.resetSettings();
return;
}
if (data == null) {
return;
@@ -253,7 +259,7 @@ public class WiredConditionUserPerformsAction extends InteractionWiredCondition
}
long timestamp = (Long) timestampValue;
if ((System.currentTimeMillis() - timestamp) > TRANSIENT_ACTION_WINDOW_MS) {
if (!WiredUserActionInputGuard.isRecentTimestamp(timestamp, System.currentTimeMillis(), TRANSIENT_ACTION_WINDOW_MS)) {
return false;
}
@@ -35,6 +35,7 @@ public class WiredConditionVariableAgeMatch extends WiredConditionHasVariable {
private static final int DURATION_UNIT_WEEKS = 5;
private static final int DURATION_UNIT_MONTHS = 6;
private static final int DURATION_UNIT_YEARS = 7;
static final int MAX_DURATION_AMOUNT = 1_000_000;
protected int compareValue = COMPARE_VALUE_CREATED;
protected int comparison = COMPARISON_LOWER_THAN;
@@ -97,7 +98,7 @@ public class WiredConditionVariableAgeMatch extends WiredConditionHasVariable {
this.targetType = (params.length > 0) ? normalizeTargetTypeExtended(params[0]) : TARGET_USER;
this.compareValue = (params.length > 1) ? normalizeCompareValue(params[1]) : COMPARE_VALUE_CREATED;
this.comparison = (params.length > 2) ? normalizeComparison(params[2]) : COMPARISON_LOWER_THAN;
this.durationAmount = Math.max(0, (params.length > 3) ? params[3] : 0);
this.durationAmount = normalizeDurationAmount((params.length > 3) ? params[3] : 0);
this.durationUnit = (params.length > 4) ? normalizeDurationUnit(params[4]) : DURATION_UNIT_SECONDS;
this.userSource = (params.length > 5) ? normalizeUserSource(params[5]) : WiredSourceUtil.SOURCE_TRIGGER;
this.furniSource = (params.length > 6) ? normalizeFurniSource(params[6]) : WiredSourceUtil.SOURCE_TRIGGER;
@@ -130,6 +131,10 @@ public class WiredConditionVariableAgeMatch extends WiredConditionHasVariable {
@Override
public boolean evaluate(WiredContext ctx) {
if (ctx == null) {
return false;
}
Room room = ctx.room();
if (room == null || this.variableToken == null || this.variableToken.isEmpty() || !isCustomVariableToken(this.variableToken)) {
@@ -192,7 +197,7 @@ public class WiredConditionVariableAgeMatch extends WiredConditionHasVariable {
this.targetType = normalizeTargetTypeExtended(data.targetType);
this.compareValue = normalizeCompareValue(data.compareValue);
this.comparison = normalizeComparison(data.comparison);
this.durationAmount = Math.max(0, data.durationAmount);
this.durationAmount = normalizeDurationAmount(data.durationAmount);
this.durationUnit = normalizeDurationUnit(data.durationUnit);
this.userSource = normalizeUserSource(data.userSource);
this.furniSource = normalizeFurniSource(data.furniSource);
@@ -345,8 +350,8 @@ public class WiredConditionVariableAgeMatch extends WiredConditionHasVariable {
return Math.max(0L, System.currentTimeMillis() - timestampMs);
}
private static long durationToMillis(int amount, int unit) {
long normalizedAmount = Math.max(0L, amount);
static long durationToMillis(int amount, int unit) {
long normalizedAmount = normalizeDurationAmount(amount);
return switch (unit) {
case DURATION_UNIT_MILLISECONDS -> normalizedAmount;
@@ -367,22 +372,26 @@ public class WiredConditionVariableAgeMatch extends WiredConditionHasVariable {
return left * right;
}
private static int normalizeTargetTypeExtended(int value) {
static int normalizeDurationAmount(int value) {
return Math.max(0, Math.min(MAX_DURATION_AMOUNT, value));
}
static int normalizeTargetTypeExtended(int value) {
return switch (value) {
case TARGET_FURNI, TARGET_CONTEXT, TARGET_ROOM -> value;
default -> TARGET_USER;
};
}
private static int normalizeCompareValue(int value) {
static int normalizeCompareValue(int value) {
return (value == COMPARE_VALUE_UPDATED) ? COMPARE_VALUE_UPDATED : COMPARE_VALUE_CREATED;
}
private static int normalizeComparison(int value) {
static int normalizeComparison(int value) {
return (value == COMPARISON_HIGHER_THAN) ? COMPARISON_HIGHER_THAN : COMPARISON_LOWER_THAN;
}
private static int normalizeDurationUnit(int value) {
static int normalizeDurationUnit(int value) {
return switch (value) {
case DURATION_UNIT_MILLISECONDS, DURATION_UNIT_SECONDS, DURATION_UNIT_MINUTES, DURATION_UNIT_HOURS,
DURATION_UNIT_DAYS, DURATION_UNIT_WEEKS, DURATION_UNIT_MONTHS, DURATION_UNIT_YEARS -> value;
@@ -51,6 +51,7 @@ public class WiredConditionVariableValueMatch extends WiredConditionHasVariable
private static final int COMPARISON_NOT_EQUAL = 5;
private static final String DELIM = "\t";
private static final String FURNI_DELIM = ";";
static final int MAX_ABS_REFERENCE_CONSTANT = 1_000_000_000;
protected int comparison = COMPARISON_EQUAL;
protected int referenceMode = REFERENCE_CONSTANT;
@@ -123,7 +124,7 @@ public class WiredConditionVariableValueMatch extends WiredConditionHasVariable
int nextTargetType = normalizeTargetTypeExtended(param(params, 0, TARGET_USER));
int nextComparison = normalizeComparison(param(params, 1, COMPARISON_EQUAL));
int nextReferenceMode = normalizeReferenceMode(param(params, 2, REFERENCE_CONSTANT));
int nextReferenceConstantValue = param(params, 3, 0);
int nextReferenceConstantValue = normalizeReferenceConstantValue(param(params, 3, 0));
int nextReferenceTargetType = normalizeTargetTypeExtended(param(params, 4, TARGET_USER));
int nextUserSource = normalizeUserSource(param(params, 5, WiredSourceUtil.SOURCE_TRIGGER));
int nextFurniSource = normalizeFurniSource(param(params, 6, WiredSourceUtil.SOURCE_TRIGGER));
@@ -168,6 +169,10 @@ public class WiredConditionVariableValueMatch extends WiredConditionHasVariable
@Override
public boolean evaluate(WiredContext ctx) {
if (ctx == null) {
return false;
}
Room room = ctx.room();
if (room == null || this.variableToken == null || this.variableToken.isEmpty()) {
@@ -220,14 +225,21 @@ public class WiredConditionVariableValueMatch extends WiredConditionHasVariable
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) return;
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data;
try {
data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
} catch (RuntimeException exception) {
this.onPickUp();
return;
}
if (data == null) return;
this.targetType = normalizeTargetTypeExtended(data.targetType);
this.setVariableToken(normalizeVariableToken((data.variableToken != null) ? data.variableToken : ((data.variableItemId > 0) ? String.valueOf(data.variableItemId) : "")));
this.comparison = normalizeComparison(data.comparison);
this.referenceMode = normalizeReferenceMode(data.referenceMode);
this.referenceConstantValue = data.referenceConstantValue;
this.referenceConstantValue = normalizeReferenceConstantValue(data.referenceConstantValue);
this.referenceTargetType = normalizeTargetTypeExtended(data.referenceTargetType);
this.setReferenceVariableToken(normalizeVariableToken((data.referenceVariableToken != null) ? data.referenceVariableToken : ((data.referenceVariableItemId > 0) ? String.valueOf(data.referenceVariableItemId) : "")));
this.userSource = normalizeUserSource(data.userSource);
@@ -737,32 +749,36 @@ public class WiredConditionVariableValueMatch extends WiredConditionHasVariable
return (params.length > index) ? params[index] : fallback;
}
private static int normalizeTargetTypeExtended(int value) {
static int normalizeTargetTypeExtended(int value) {
return switch (value) {
case TARGET_FURNI, TARGET_CONTEXT, TARGET_ROOM -> value;
default -> TARGET_USER;
};
}
private static int normalizeReferenceMode(int value) {
static int normalizeReferenceMode(int value) {
return (value == REFERENCE_VARIABLE) ? REFERENCE_VARIABLE : REFERENCE_CONSTANT;
}
private static int normalizeReferenceFurniSource(int value) {
static int normalizeReferenceFurniSource(int value) {
return switch (value) {
case SOURCE_SECONDARY_SELECTED, WiredSourceUtil.SOURCE_SELECTOR, WiredSourceUtil.SOURCE_SIGNAL -> value;
default -> WiredSourceUtil.SOURCE_TRIGGER;
};
}
private static int normalizeComparison(int value) {
static int normalizeComparison(int value) {
return switch (value) {
case COMPARISON_GREATER_THAN, COMPARISON_GREATER_THAN_OR_EQUAL, COMPARISON_LESS_THAN_OR_EQUAL, COMPARISON_LESS_THAN, COMPARISON_NOT_EQUAL -> value;
default -> COMPARISON_EQUAL;
};
}
private static int parseInteger(String value) {
static int normalizeReferenceConstantValue(int value) {
return Math.max(-MAX_ABS_REFERENCE_CONSTANT, Math.min(MAX_ABS_REFERENCE_CONSTANT, value));
}
static int parseInteger(String value) {
try {
return (value == null || value.trim().isEmpty()) ? 0 : Integer.parseInt(value.trim());
} catch (NumberFormatException e) {
@@ -0,0 +1,21 @@
package com.eu.habbo.habbohotel.items.interactions.wired.conditions;
public final class WiredDateRangeInputGuard {
private WiredDateRangeInputGuard() {
}
public static int[] normalizeRange(int startDate, int endDate) {
int start = normalizeTimestamp(startDate);
int end = normalizeTimestamp(endDate);
if (start > end) {
return new int[]{0, 0};
}
return new int[]{start, end};
}
public static int normalizeTimestamp(int value) {
return Math.max(0, value);
}
}
@@ -0,0 +1,76 @@
package com.eu.habbo.habbohotel.items.interactions.wired.conditions;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public final class WiredFurniConditionInputGuard {
private WiredFurniConditionInputGuard() {
}
public static int normalizeFurniSource(int value) {
switch (value) {
case WiredSourceUtil.SOURCE_SELECTED:
case WiredSourceUtil.SOURCE_SELECTOR:
case WiredSourceUtil.SOURCE_SIGNAL:
case WiredSourceUtil.SOURCE_TRIGGER:
return value;
default:
return WiredSourceUtil.SOURCE_TRIGGER;
}
}
public static int normalizeUserSource(int value) {
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
}
public static int selectedOrNormalizedFurniSource(int value, boolean hasSelectedItems) {
int source = normalizeFurniSource(value);
return (hasSelectedItems && source == WiredSourceUtil.SOURCE_TRIGGER)
? WiredSourceUtil.SOURCE_SELECTED
: source;
}
public static List<Integer> sanitizeItemIds(Collection<Integer> itemIds, int maxCount) {
List<Integer> result = new ArrayList<>();
if (itemIds == null || maxCount < 1) {
return result;
}
for (Integer itemId : itemIds) {
if (itemId == null || itemId < 1 || result.size() >= maxCount) {
continue;
}
result.add(itemId);
}
return result;
}
public static List<Integer> parseLegacyItemIds(String value, int maxCount) {
List<Integer> result = new ArrayList<>();
if (value == null || value.isBlank() || maxCount < 1) {
return result;
}
for (String part : value.split("[;,:\\t]")) {
if (result.size() >= maxCount) {
break;
}
try {
int id = Integer.parseInt(part.trim());
if (id > 0) {
result.add(id);
}
} catch (NumberFormatException ignored) {
// Ignore malformed legacy item ids.
}
}
return result;
}
}
@@ -0,0 +1,92 @@
package com.eu.habbo.habbohotel.items.interactions.wired.conditions;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.WiredMatchFurniSetting;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public final class WiredMatchPositionInputGuard {
public static final int MAX_STATE_LENGTH = 512;
private WiredMatchPositionInputGuard() {
}
public static int normalizeFurniSource(int value, boolean hasSelectedSettings) {
int source = switch (value) {
case WiredSourceUtil.SOURCE_SELECTED, WiredSourceUtil.SOURCE_SELECTOR,
WiredSourceUtil.SOURCE_SIGNAL, WiredSourceUtil.SOURCE_TRIGGER -> value;
default -> WiredSourceUtil.SOURCE_TRIGGER;
};
return (hasSelectedSettings && source == WiredSourceUtil.SOURCE_TRIGGER)
? WiredSourceUtil.SOURCE_SELECTED
: source;
}
public static List<WiredMatchFurniSetting> sanitizeSettings(Collection<WiredMatchFurniSetting> settings, Room room) {
List<WiredMatchFurniSetting> result = new ArrayList<>();
if (settings == null || room == null) {
return result;
}
for (WiredMatchFurniSetting setting : settings) {
WiredMatchFurniSetting normalized = sanitizeSetting(setting, room);
if (normalized != null) {
result.add(normalized);
}
if (result.size() >= WiredManager.MAXIMUM_FURNI_SELECTION) {
break;
}
}
return result;
}
public static WiredMatchFurniSetting sanitizeSetting(WiredMatchFurniSetting setting, Room room) {
if (setting == null || room == null) {
return null;
}
return sanitizeParts(setting.item_id, setting.state, setting.rotation, setting.x, setting.y, setting.z, room);
}
public static WiredMatchFurniSetting sanitizeParts(int itemId, String state, int rotation, int x, int y, double z, Room room) {
if (itemId < 1 || room == null) {
return null;
}
HabboItem item = room.getHabboItem(itemId);
if (item == null || rotation < 0 || rotation > 7 || !Double.isFinite(z)) {
return null;
}
if (x < Short.MIN_VALUE || x > Short.MAX_VALUE || y < Short.MIN_VALUE || y > Short.MAX_VALUE) {
return null;
}
if (room.getLayout() != null && room.getLayout().getTile((short) x, (short) y) == null) {
return null;
}
return new WiredMatchFurniSetting(itemId, normalizeState(state), rotation, x, y, z);
}
public static String normalizeState(String state) {
if (state == null) {
return "";
}
String normalized = state.replace('\t', ' ').replace('\r', ' ').replace('\n', ' ');
if (normalized.length() > MAX_STATE_LENGTH) {
return normalized.substring(0, MAX_STATE_LENGTH);
}
return normalized;
}
}
@@ -0,0 +1,14 @@
package com.eu.habbo.habbohotel.items.interactions.wired.conditions;
public final class WiredUserActionInputGuard {
private WiredUserActionInputGuard() {
}
public static boolean isRecentTimestamp(long timestamp, long now, long windowMs) {
if (timestamp < 1 || timestamp > now || windowMs < 1) {
return false;
}
return (now - timestamp) <= windowMs;
}
}
@@ -0,0 +1,45 @@
package com.eu.habbo.habbohotel.items.interactions.wired.conditions;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
public final class WiredUserConditionInputGuard {
public static final int MAX_BADGE_CODE_LENGTH = 64;
public static final int MAX_EFFECT_ID = 10_000;
public static final int MAX_HAND_ITEM_ID = 10_000;
private WiredUserConditionInputGuard() {
}
public static String normalizeBadgeCode(String value) {
if (value == null) {
return "";
}
String normalized = value.trim().replace('\t', ' ').replace('\r', ' ').replace('\n', ' ');
if (normalized.length() > MAX_BADGE_CODE_LENGTH) {
return normalized.substring(0, MAX_BADGE_CODE_LENGTH);
}
return normalized;
}
public static int normalizeUserSource(int value) {
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
}
public static int normalizeEffectId(int value) {
if (value < 0) {
return 0;
}
return Math.min(value, MAX_EFFECT_ID);
}
public static int normalizeHandItemId(int value) {
if (value < 0) {
return 0;
}
return Math.min(value, MAX_HAND_ITEM_ID);
}
}
@@ -93,16 +93,17 @@ public class WiredEffectAdjustClock extends InteractionWiredEffect {
this.items.clear();
String wiredData = set.getString("wired_data");
if (wiredData != null && wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay);
this.operator = this.normalizeOperator(data.operator);
this.furniSource = data.furniSource;
this.minutes = this.normalizeMinutes(data.minutes);
this.halfSecondSteps = this.normalizeHalfSecondSteps(data.halfSecondSteps);
JsonData jsonData = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class);
if (jsonData != null) {
this.setDelay(WiredUtilityPayloadGuard.delay(jsonData.delay));
this.operator = this.normalizeOperator(jsonData.operator);
this.furniSource = WiredUtilityPayloadGuard.furniSource(jsonData.furniSource);
this.minutes = this.normalizeMinutes(jsonData.minutes);
this.halfSecondSteps = this.normalizeHalfSecondSteps(jsonData.halfSecondSteps);
if (data.itemIds != null) {
for (Integer id : data.itemIds) {
if (jsonData.itemIds != null) {
for (Integer id : jsonData.itemIds) {
if (id == null) continue;
HabboItem item = room.getHabboItem(id);
if (item != null) {
@@ -106,21 +106,21 @@ public class WiredEffectBotClothes extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay);
this.botName = data.bot_name;
this.botLook = data.look;
this.botSource = (data.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(data.botSource)
JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
if(jsonData != null) {
this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.botLook = jsonData.look != null ? jsonData.look : "";
this.botSource = (jsonData.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource)
: WiredBotSourceUtil.SOURCE_BOT_NAME;
}
else {
String[] data = wiredData.split(((char) 9) + "");
String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0];
if (data.length >= 3) {
this.setDelay(Integer.parseInt(data[0]));
this.botName = data[1];
this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0]));
this.botName = WiredEffectPayloadGuard.text(data[1]);
this.botLook = data[2];
}
@@ -143,23 +143,23 @@ public class WiredEffectBotFollowHabbo extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay);
this.mode = data.mode;
this.botName = data.bot_name;
this.userSource = data.userSource;
this.botSource = (data.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(data.botSource)
JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
if(jsonData != null) {
this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.mode = WiredEffectPayloadGuard.mode(jsonData.mode);
this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.userSource = WiredSourceUtil.isDefaultUserSource(jsonData.userSource) ? jsonData.userSource : WiredSourceUtil.SOURCE_TRIGGER;
this.botSource = (jsonData.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource)
: WiredBotSourceUtil.SOURCE_BOT_NAME;
}
else {
String[] data = wiredData.split(((char) 9) + "");
String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0];
if (data.length == 3) {
this.setDelay(Integer.parseInt(data[0]));
this.mode = (data[1].equalsIgnoreCase("1") ? 1 : 0);
this.botName = data[2];
this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0]));
this.mode = WiredEffectPayloadGuard.mode(WiredEffectPayloadGuard.parseInt(data[1], 0));
this.botName = WiredEffectPayloadGuard.text(data[2]);
}
this.needsUpdate(true);
@@ -153,23 +153,23 @@ public class WiredEffectBotGiveHandItem extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay);
this.itemId = this.normalizeHandItem(data.item_id);
this.botName = data.bot_name;
this.userSource = this.normalizeUserSource(data.userSource);
this.botSource = ((data.botSource == WiredSourceUtil.SOURCE_TRIGGER) && this.botName != null && !this.botName.isEmpty())
JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
if(jsonData != null) {
this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.itemId = this.normalizeHandItem(jsonData.item_id);
this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.userSource = this.normalizeUserSource(jsonData.userSource);
this.botSource = ((jsonData.botSource == WiredSourceUtil.SOURCE_TRIGGER) && this.botName != null && !this.botName.isEmpty())
? BOT_SOURCE_NAME
: this.normalizeBotSource(data.botSource);
: this.normalizeBotSource(jsonData.botSource);
}
else {
String[] data = wiredData.split(((char) 9) + "");
String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0];
if (data.length == 3) {
this.setDelay(Integer.parseInt(data[0]));
this.itemId = this.normalizeHandItem(Integer.parseInt(data[1]));
this.botName = data[2];
this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0]));
this.itemId = this.normalizeHandItem(WiredEffectPayloadGuard.parseInt(data[1], 0));
this.botName = WiredEffectPayloadGuard.text(data[2]);
}
this.needsUpdate(true);
@@ -144,23 +144,23 @@ public class WiredEffectBotTalk extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay);
this.mode = data.mode;
this.botName = data.bot_name;
this.message = data.message;
this.botSource = (data.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(data.botSource)
JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
if(jsonData != null) {
this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.mode = WiredEffectPayloadGuard.mode(jsonData.mode);
this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.message = jsonData.message != null ? jsonData.message : "";
this.botSource = (jsonData.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource)
: WiredBotSourceUtil.SOURCE_BOT_NAME;
}
else {
String[] data = wiredData.split(((char) 9) + "");
String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0];
if (data.length == 4) {
this.setDelay(Integer.parseInt(data[0]));
this.mode = data[1].equalsIgnoreCase("1") ? 1 : 0;
this.botName = data[2];
this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0]));
this.mode = WiredEffectPayloadGuard.mode(WiredEffectPayloadGuard.parseInt(data[1], 0));
this.botName = WiredEffectPayloadGuard.text(data[2]);
this.message = data[3];
}
@@ -168,22 +168,22 @@ public class WiredEffectBotTalkToHabbo extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay);
this.mode = data.mode;
this.botName = data.bot_name;
this.message = data.message;
this.userSource = data.userSource;
this.botSource = (data.botSource != null) ? WiredBotSourceUtil.normalizeBotSource(data.botSource) : WiredBotSourceUtil.SOURCE_BOT_NAME;
JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
if(jsonData != null) {
this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.mode = WiredEffectPayloadGuard.mode(jsonData.mode);
this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.message = jsonData.message != null ? jsonData.message : "";
this.userSource = WiredSourceUtil.isDefaultUserSource(jsonData.userSource) ? jsonData.userSource : WiredSourceUtil.SOURCE_TRIGGER;
this.botSource = (jsonData.botSource != null) ? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource) : WiredBotSourceUtil.SOURCE_BOT_NAME;
}
else {
String[] data = wiredData.split(((char) 9) + "");
String[] data = wiredData != null ? wiredData.split(((char) 9) + "") : new String[0];
if (data.length == 4) {
this.setDelay(Integer.parseInt(data[0]));
this.mode = data[1].equalsIgnoreCase("1") ? 1 : 0;
this.botName = data[2];
this.setDelay(WiredEffectPayloadGuard.parseDelay(data[0]));
this.mode = WiredEffectPayloadGuard.mode(WiredEffectPayloadGuard.parseInt(data[1], 0));
this.botName = WiredEffectPayloadGuard.text(data[2]);
this.message = data[3];
}
@@ -231,37 +231,40 @@ public class WiredEffectBotTeleport extends InteractionWiredEffect {
String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay);
this.botName = data.bot_name;
this.furniSource = data.furniSource;
this.botSource = (data.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(data.botSource)
JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
if(jsonData != null) {
this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.furniSource = WiredEffectPayloadGuard.furniSource(jsonData.furniSource);
this.botSource = (jsonData.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource)
: WiredBotSourceUtil.SOURCE_BOT_NAME;
for(int itemId : data.items) {
if (jsonData.items != null) {
for(int itemId : jsonData.items) {
HabboItem item = room.getHabboItem(itemId);
if (item != null)
this.items.add(item);
}
}
if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
}
else {
String[] wiredDataSplit = set.getString("wired_data").split("\t");
String[] wiredDataSplit = wiredData != null ? wiredData.split("\t") : new String[0];
if (wiredDataSplit.length >= 2) {
this.setDelay(Integer.parseInt(wiredDataSplit[0]));
this.setDelay(WiredEffectPayloadGuard.parseDelay(wiredDataSplit[0]));
String[] data = wiredDataSplit[1].split(";");
if (data.length > 1) {
this.botName = data[0];
this.botName = WiredEffectPayloadGuard.text(data[0]);
for (int i = 1; i < data.length; i++) {
HabboItem item = room.getHabboItem(Integer.parseInt(data[i]));
int itemId = WiredEffectPayloadGuard.parseInt(data[i], 0);
HabboItem item = itemId > 0 ? room.getHabboItem(itemId) : null;
if (item != null)
this.items.add(item);
@@ -181,37 +181,40 @@ public class WiredEffectBotWalkToFurni extends InteractionWiredEffect {
String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay);
this.botName = data.bot_name;
this.furniSource = data.furniSource;
this.botSource = (data.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(data.botSource)
JsonData jsonData = WiredEffectPayloadGuard.fromJson(wiredData, JsonData.class);
if(jsonData != null) {
this.setDelay(WiredEffectPayloadGuard.delay(jsonData.delay));
this.botName = WiredEffectPayloadGuard.text(jsonData.bot_name);
this.furniSource = WiredEffectPayloadGuard.furniSource(jsonData.furniSource);
this.botSource = (jsonData.botSource != null)
? WiredBotSourceUtil.normalizeBotSource(jsonData.botSource)
: WiredBotSourceUtil.SOURCE_BOT_NAME;
for(int itemId : data.items) {
if (jsonData.items != null) {
for(int itemId : jsonData.items) {
HabboItem item = room.getHabboItem(itemId);
if (item != null)
this.items.add(item);
}
}
if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.items.isEmpty()) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
}
else {
String[] wiredDataSplit = set.getString("wired_data").split("\t");
String[] wiredDataSplit = wiredData != null ? wiredData.split("\t") : new String[0];
if (wiredDataSplit.length >= 2) {
this.setDelay(Integer.parseInt(wiredDataSplit[0]));
this.setDelay(WiredEffectPayloadGuard.parseDelay(wiredDataSplit[0]));
String[] data = wiredDataSplit[1].split(";");
if (data.length > 1) {
this.botName = data[0];
this.botName = WiredEffectPayloadGuard.text(data[0]);
for (int i = 1; i < data.length; i++) {
HabboItem item = room.getHabboItem(Integer.parseInt(data[i]));
int itemId = WiredEffectPayloadGuard.parseInt(data[i], 0);
HabboItem item = itemId > 0 ? room.getHabboItem(itemId) : null;
if (item != null)
this.items.add(item);
@@ -298,7 +298,7 @@ public class WiredEffectChangeVariableValue extends InteractionWiredEffect {
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) return;
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class);
if (data == null) return;
this.destinationTargetType = normalizeTargetType(data.destinationTargetType);
@@ -312,7 +312,7 @@ public class WiredEffectChangeVariableValue extends InteractionWiredEffect {
this.destinationFurniSource = normalizeDestinationFurniSource(data.destinationFurniSource);
this.referenceUserSource = normalizeUserSource(data.referenceUserSource);
this.referenceFurniSource = normalizeReferenceFurniSource(data.referenceFurniSource);
this.setDelay(Math.max(0, data.delay));
this.setDelay(WiredUtilityPayloadGuard.delay(data.delay));
if (room != null) {
try {
@@ -5,6 +5,7 @@ import com.eu.habbo.habbohotel.gameclients.GameClient;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredNumericInputGuard;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
@@ -72,11 +73,11 @@ public class WiredEffectGiveHotelviewBonusRarePoints extends InteractionWiredEff
@Override
public boolean saveData(WiredSettings settings, GameClient gameClient) {
try {
this.amount = Integer.parseInt(settings.getStringParam());
} catch (Exception e) {
int nextAmount = WiredNumericInputGuard.parsePositiveAmount(settings.getStringParam(), WiredNumericInputGuard.maxRewardAmount());
if (nextAmount <= 0) {
return false;
}
this.amount = nextAmount;
int[] params = settings.getIntParams();
this.userSource = (params.length > 0) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER;
@@ -5,6 +5,7 @@ import com.eu.habbo.habbohotel.gameclients.GameClient;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredNumericInputGuard;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
@@ -71,11 +72,11 @@ public class WiredEffectGiveHotelviewHofPoints extends InteractionWiredEffect {
@Override
public boolean saveData(WiredSettings settings, GameClient gameClient) {
try {
this.amount = Integer.parseInt(settings.getStringParam());
} catch (Exception e) {
int nextAmount = WiredNumericInputGuard.parsePositiveAmount(settings.getStringParam(), WiredNumericInputGuard.maxRewardAmount());
if (nextAmount <= 0) {
return false;
}
this.amount = nextAmount;
int[] params = settings.getIntParams();
this.userSource = (params.length > 0) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER;
@@ -6,6 +6,7 @@ import com.eu.habbo.habbohotel.gameclients.GameClient;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredNumericInputGuard;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
@@ -72,11 +73,11 @@ public class WiredEffectGiveRespect extends InteractionWiredEffect {
@Override
public boolean saveData(WiredSettings settings, GameClient gameClient) {
try {
this.respects = Integer.parseInt(settings.getStringParam());
} catch (Exception e) {
int nextRespects = WiredNumericInputGuard.parsePositiveAmount(settings.getStringParam(), WiredNumericInputGuard.maxRespectAmount());
if (nextRespects <= 0) {
return false;
}
this.respects = nextRespects;
int[] params = settings.getIntParams();
this.userSource = (params.length > 0) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER;
@@ -0,0 +1,67 @@
package com.eu.habbo.habbohotel.items.interactions.wired.effects;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
final class WiredEffectPayloadGuard {
static final int MAX_LOAD_DELAY = 3600;
private WiredEffectPayloadGuard() {
}
static int delay(int value) {
if (value < 0) {
return 0;
}
return Math.min(value, MAX_LOAD_DELAY);
}
static int parseDelay(String value) {
return delay(parseInt(value, 0));
}
static int parseInt(String value, int fallback) {
if (value == null) {
return fallback;
}
try {
return Integer.parseInt(value.trim());
} catch (RuntimeException e) {
return fallback;
}
}
static int mode(int value) {
return value == 1 ? 1 : 0;
}
static int furniSource(int value) {
switch (value) {
case WiredSourceUtil.SOURCE_TRIGGER:
case WiredSourceUtil.SOURCE_SELECTED:
case WiredSourceUtil.SOURCE_SELECTOR:
case WiredSourceUtil.SOURCE_SIGNAL:
return value;
default:
return WiredSourceUtil.SOURCE_TRIGGER;
}
}
static String text(String value) {
return value == null ? "" : value.replace("\t", "");
}
static <T> T fromJson(String wiredData, Class<T> type) {
if (wiredData == null || !wiredData.startsWith("{")) {
return null;
}
try {
return WiredManager.getGson().fromJson(wiredData, type);
} catch (RuntimeException e) {
return null;
}
}
}
@@ -260,14 +260,14 @@ public class WiredEffectRemoveVariable extends InteractionWiredEffect {
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
JsonData data = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class);
if (data != null) {
this.variableItemId = Math.max(0, data.variableItemId);
this.targetType = normalizeTargetType(data.targetType);
this.userSource = normalizeUserSource(data.userSource);
this.furniSource = normalizeFurniSource(data.furniSource);
this.setDelay(Math.max(0, data.delay));
this.setDelay(WiredUtilityPayloadGuard.delay(data.delay));
if (room != null && data.selectedFurniIds != null) {
for (Integer itemId : data.selectedFurniIds) {
@@ -96,19 +96,16 @@ public class WiredEffectResetTimers extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.delay = data.delay;
JsonData jsonData = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class);
if (jsonData != null) {
this.delay = WiredUtilityPayloadGuard.delay(jsonData.delay);
} else {
try {
if (!wiredData.equals("")) {
this.delay = Integer.parseInt(wiredData);
}
} catch (Exception e) {
if (wiredData != null && !wiredData.equals("")) {
this.delay = WiredUtilityPayloadGuard.parseDelay(wiredData);
}
}
this.setDelay(this.delay);
this.setDelay(WiredUtilityPayloadGuard.delay(this.delay));
}
@Override
@@ -350,9 +350,9 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
this.forwardItems = new THashSet<>();
String wiredData = set.getString("wired_data");
if (wiredData != null && wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay);
JsonData data = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class);
if (data != null) {
this.setDelay(WiredUtilityPayloadGuard.delay(data.delay));
this.antennaSource = data.antennaSource;
this.furniForward = normalizeSource(data.furniForward);
this.userForward = normalizeSource(data.userForward);
@@ -100,15 +100,16 @@ public class WiredEffectSetAltitude extends InteractionWiredEffect {
this.items.clear();
String wiredData = set.getString("wired_data");
if (wiredData != null && wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay);
this.operator = this.normalizeOperator(data.operator);
this.altitude = this.parseAltitudeOrDefault(data.altitude);
this.furniSource = data.furniSource;
JsonData jsonData = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class);
if (jsonData != null) {
this.setDelay(WiredUtilityPayloadGuard.delay(jsonData.delay));
this.operator = this.normalizeOperator(jsonData.operator);
this.altitude = this.parseAltitudeOrDefault(jsonData.altitude);
this.furniSource = WiredUtilityPayloadGuard.furniSource(jsonData.furniSource);
if (data.itemIds != null) {
for (Integer id : data.itemIds) {
if (jsonData.itemIds != null) {
for (Integer id : jsonData.itemIds) {
if (id == null) continue;
HabboItem item = room.getHabboItem(id);
if (item != null) {
@@ -5,6 +5,7 @@ import com.eu.habbo.habbohotel.gameclients.GameClient;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredLegacyDataGuard;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.pets.RideablePet;
import com.eu.habbo.habbohotel.rooms.*;
@@ -290,17 +291,11 @@ public class WiredEffectTeleport extends InteractionWiredEffect {
String[] wiredDataOld = wiredData != null ? wiredData.split("\t") : new String[0];
if (wiredDataOld.length >= 1) {
this.setDelay(WiredMovementPayloadGuard.parseDelay(wiredDataOld[0]));
this.setDelay(WiredLegacyDataGuard.parseDelay(wiredDataOld[0]));
}
if (wiredDataOld.length == 2) {
if (wiredDataOld[1].contains(";")) {
for (String s : wiredDataOld[1].split(";")) {
int itemId = WiredMovementPayloadGuard.parseInt(s, 0);
HabboItem item = itemId > 0 ? room.getHabboItem(itemId) : null;
if (item != null)
this.items.add(item);
}
this.items.addAll(WiredLegacyDataGuard.parseRoomItems(wiredDataOld[1], room));
}
}
this.fastTeleport = false;
@@ -15,6 +15,7 @@ import com.eu.habbo.habbohotel.items.interactions.games.freeze.InteractionFreeze
import com.eu.habbo.habbohotel.items.interactions.games.tag.InteractionTagField;
import com.eu.habbo.habbohotel.items.interactions.games.tag.InteractionTagPole;
import com.eu.habbo.habbohotel.items.interactions.pets.*;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredLegacyDataGuard;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
@@ -275,18 +276,14 @@ public class WiredEffectToggleFurni extends InteractionWiredEffect {
String[] wiredDataOld = wiredData != null ? wiredData.split("\t") : new String[0];
if (wiredDataOld.length >= 1) {
this.setDelay(WiredMovementPayloadGuard.parseDelay(wiredDataOld[0]));
this.setDelay(WiredLegacyDataGuard.parseDelay(wiredDataOld[0]));
}
if (wiredDataOld.length == 2) {
if (wiredDataOld[1].contains(";")) {
for (String s : wiredDataOld[1].split(";")) {
int itemId = WiredMovementPayloadGuard.parseInt(s, 0);
HabboItem item = itemId > 0 ? room.getHabboItem(itemId) : null;
for (HabboItem item : WiredLegacyDataGuard.parseRoomItems(wiredDataOld[1], room)) {
if (item instanceof InteractionFreezeBlock || item instanceof InteractionFreezeTile || item instanceof InteractionCrackable)
continue;
if (item != null)
this.items.add(item);
}
}
@@ -272,22 +272,23 @@ public class WiredEffectWhisper extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
if(wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay);
this.message = data.message;
this.userSource = (data.userSource != null) ? data.userSource : WiredSourceUtil.SOURCE_TRIGGER;
this.visibilitySelection = (data.visibilitySelection != null && data.visibilitySelection == VISIBILITY_ALL_ROOM_USERS)
JsonData jsonData = WiredUtilityPayloadGuard.fromJson(wiredData, JsonData.class);
if(jsonData != null) {
this.setDelay(WiredUtilityPayloadGuard.delay(jsonData.delay));
this.message = WiredUtilityPayloadGuard.text(jsonData.message);
this.userSource = (jsonData.userSource != null) ? WiredUtilityPayloadGuard.userSource(jsonData.userSource) : WiredSourceUtil.SOURCE_TRIGGER;
this.visibilitySelection = (jsonData.visibilitySelection != null && jsonData.visibilitySelection == VISIBILITY_ALL_ROOM_USERS)
? VISIBILITY_ALL_ROOM_USERS
: VISIBILITY_SOURCE_USERS;
this.bubbleStyle = (data.bubbleStyle != null) ? data.bubbleStyle : RoomChatMessageBubbles.WIRED.getType();
this.bubbleStyle = (jsonData.bubbleStyle != null) ? jsonData.bubbleStyle : RoomChatMessageBubbles.WIRED.getType();
}
else {
this.message = "";
if (wiredData.split("\t").length >= 2) {
super.setDelay(Integer.parseInt(wiredData.split("\t")[0]));
this.message = wiredData.split("\t")[1];
String[] wiredDataSplit = wiredData != null ? wiredData.split("\t") : new String[0];
if (wiredDataSplit.length >= 2) {
super.setDelay(WiredUtilityPayloadGuard.parseDelay(wiredDataSplit[0]));
this.message = wiredDataSplit[1];
}
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
@@ -0,0 +1,67 @@
package com.eu.habbo.habbohotel.items.interactions.wired.effects;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
final class WiredUtilityPayloadGuard {
static final int MAX_LOAD_DELAY = 3600;
private WiredUtilityPayloadGuard() {
}
static int delay(int value) {
if (value < 0) {
return 0;
}
return Math.min(value, MAX_LOAD_DELAY);
}
static int parseDelay(String value) {
return delay(parseInt(value, 0));
}
static int parseInt(String value, int fallback) {
if (value == null) {
return fallback;
}
try {
return Integer.parseInt(value.trim());
} catch (RuntimeException e) {
return fallback;
}
}
static int userSource(int value) {
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
}
static int furniSource(int value) {
switch (value) {
case WiredSourceUtil.SOURCE_TRIGGER:
case WiredSourceUtil.SOURCE_SELECTED:
case WiredSourceUtil.SOURCE_SELECTOR:
case WiredSourceUtil.SOURCE_SIGNAL:
return value;
default:
return WiredSourceUtil.SOURCE_TRIGGER;
}
}
static String text(String value) {
return value == null ? "" : value;
}
static <T> T fromJson(String wiredData, Class<T> type) {
if (wiredData == null || !wiredData.startsWith("{")) {
return null;
}
try {
return WiredManager.getGson().fromJson(wiredData, type);
} catch (RuntimeException e) {
return null;
}
}
}
@@ -4,6 +4,7 @@ import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredTimerInputGuard;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredTriggerReset;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
@@ -29,6 +30,9 @@ import java.util.List;
*/
public class WiredTriggerAtSetTime extends InteractionWiredTrigger implements WiredTickable, WiredTriggerReset {
public static final WiredTriggerType type = WiredTriggerType.AT_GIVEN_TIME;
private static final int STEP_MS = 500;
private static final int MIN_DELAY = STEP_MS;
private static final int LEGACY_FALLBACK_DELAY = 20 * STEP_MS;
/** The time in milliseconds until the trigger fires */
public int executeTime;
@@ -67,19 +71,22 @@ public class WiredTriggerAtSetTime extends InteractionWiredTrigger implements Wi
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
this.executeTime = parseExecuteTime(wiredData);
if (wiredData.startsWith("{")) {
Integer storedExecuteTime = null;
try {
if (wiredData != null && wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.executeTime = data.executeTime;
} else {
if (wiredData.length() >= 1) {
this.executeTime = (Integer.parseInt(wiredData));
storedExecuteTime = data != null ? data.executeTime : null;
} else if (wiredData != null && wiredData.length() >= 1) {
storedExecuteTime = Integer.parseInt(wiredData);
}
} catch (RuntimeException ignored) {
storedExecuteTime = null;
}
}
if (this.executeTime < 500) {
this.executeTime = 20 * 500;
}
this.executeTime = WiredTimerInputGuard.normalizeStoredMillis(storedExecuteTime, MIN_DELAY, LEGACY_FALLBACK_DELAY);
// Initialize for tick system - will be registered by RoomItemManager
this.accumulatedTime = 0;
@@ -134,13 +141,22 @@ public class WiredTriggerAtSetTime extends InteractionWiredTrigger implements Wi
@Override
public boolean saveData(WiredSettings settings) {
if (settings.getIntParams().length < 1) return false;
this.executeTime = settings.getIntParams()[0] * 500;
this.executeTime = WiredTimerInputGuard.fromClientUnits(settings.getIntParams()[0], STEP_MS, MIN_DELAY);
this.resetTimer();
return true;
}
private static int safeMultiply(int value, int factor) {
if (value <= 0) {
return DEFAULT_EXECUTE_TIME;
}
long multiplied = (long) value * factor;
return multiplied > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) multiplied;
}
// ========== WiredTickable Implementation ==========
@Override
@@ -4,6 +4,7 @@ import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredTimerInputGuard;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredTriggerReset;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
@@ -29,6 +30,9 @@ import java.util.List;
*/
public class WiredTriggerAtTimeLong extends InteractionWiredTrigger implements WiredTickable, WiredTriggerReset {
private static final WiredTriggerType type = WiredTriggerType.AT_GIVEN_TIME;
private static final int STEP_MS = 500;
private static final int MIN_DELAY = STEP_MS;
private static final int LEGACY_FALLBACK_DELAY = 20 * STEP_MS;
/** The time in milliseconds until the trigger fires */
private int executeTime;
@@ -67,19 +71,22 @@ public class WiredTriggerAtTimeLong extends InteractionWiredTrigger implements W
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
this.executeTime = parseExecuteTime(wiredData);
if (wiredData.startsWith("{")) {
Integer storedExecuteTime = null;
try {
if (wiredData != null && wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.executeTime = data.executeTime;
} else {
if (wiredData.length() >= 1) {
this.executeTime = (Integer.parseInt(wiredData));
storedExecuteTime = data != null ? data.executeTime : null;
} else if (wiredData != null && wiredData.length() >= 1) {
storedExecuteTime = Integer.parseInt(wiredData);
}
} catch (RuntimeException ignored) {
storedExecuteTime = null;
}
}
if (this.executeTime < 500) {
this.executeTime = 20 * 500;
}
this.executeTime = WiredTimerInputGuard.normalizeStoredMillis(storedExecuteTime, MIN_DELAY, LEGACY_FALLBACK_DELAY);
// Initialize for tick system
this.accumulatedTime = 0;
@@ -134,13 +141,22 @@ public class WiredTriggerAtTimeLong extends InteractionWiredTrigger implements W
@Override
public boolean saveData(WiredSettings settings) {
if (settings.getIntParams().length < 1) return false;
this.executeTime = settings.getIntParams()[0] * 500;
this.executeTime = WiredTimerInputGuard.fromClientUnits(settings.getIntParams()[0], STEP_MS, MIN_DELAY);
this.resetTimer();
return true;
}
private static int safeMultiply(int value, int factor) {
if (value <= 0) {
return DEFAULT_EXECUTE_TIME;
}
long multiplied = (long) value * factor;
return multiplied > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) multiplied;
}
// ========== WiredTickable Implementation ==========
@Override
@@ -4,6 +4,7 @@ import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredTimerInputGuard;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredTriggerReset;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
@@ -30,6 +31,9 @@ import java.util.List;
public class WiredTriggerRepeater extends InteractionWiredTrigger implements WiredTickable, WiredTriggerReset {
public static final WiredTriggerType type = WiredTriggerType.PERIODICALLY;
public static final int DEFAULT_DELAY = 10 * 500; // 5 seconds default
private static final int STEP_MS = 500;
private static final int MIN_DELAY = STEP_MS;
private static final int LEGACY_FALLBACK_DELAY = 20 * STEP_MS;
/** The interval in milliseconds between triggers */
protected int repeatTime = DEFAULT_DELAY;
@@ -62,19 +66,23 @@ public class WiredTriggerRepeater extends InteractionWiredTrigger implements Wir
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
this.repeatTime = parseRepeatTime(wiredData);
}
if (wiredData.startsWith("{")) {
Integer storedRepeatTime = null;
try {
if (wiredData != null && wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.repeatTime = data.repeatTime;
} else {
if (wiredData.length() >= 1) {
this.repeatTime = (Integer.parseInt(wiredData));
storedRepeatTime = data != null ? data.repeatTime : null;
} else if (wiredData != null && wiredData.length() >= 1) {
storedRepeatTime = Integer.parseInt(wiredData);
}
} catch (RuntimeException ignored) {
storedRepeatTime = null;
}
}
if (this.repeatTime < 500) {
this.repeatTime = 20 * 500;
}
this.repeatTime = WiredTimerInputGuard.normalizeStoredMillis(storedRepeatTime, MIN_DELAY, LEGACY_FALLBACK_DELAY);
}
@Override
@@ -123,15 +131,10 @@ public class WiredTriggerRepeater extends InteractionWiredTrigger implements Wir
@Override
public boolean saveData(WiredSettings settings) {
if (settings.getIntParams().length < 1) return false;
int newRepeatTime = settings.getIntParams()[0] * 500;
this.repeatTime = WiredTimerInputGuard.fromClientUnits(settings.getIntParams()[0], STEP_MS, MIN_DELAY);
if (newRepeatTime < 500) {
newRepeatTime = 500;
}
this.repeatTime = newRepeatTime;
return true;
long multiplied = (long) value * factor;
return multiplied > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) multiplied;
}
// ========== WiredTickable Implementation ==========
@@ -4,6 +4,7 @@ import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredTimerInputGuard;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredTriggerReset;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
@@ -29,6 +30,9 @@ import java.util.List;
*/
public class WiredTriggerRepeaterLong extends InteractionWiredTrigger implements WiredTickable, WiredTriggerReset {
public static final int DEFAULT_DELAY = 10 * 5000; // 50 seconds default
private static final int STEP_MS = 5000;
private static final int MIN_DELAY = STEP_MS;
private static final int LEGACY_FALLBACK_DELAY = 20 * STEP_MS;
private static final WiredTriggerType type = WiredTriggerType.PERIODICALLY_LONG;
/** The interval in milliseconds between triggers */
@@ -62,19 +66,23 @@ public class WiredTriggerRepeaterLong extends InteractionWiredTrigger implements
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
this.repeatTime = parseRepeatTime(wiredData);
}
if (wiredData.startsWith("{")) {
Integer storedRepeatTime = null;
try {
if (wiredData != null && wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.repeatTime = data.repeatTime;
} else {
if (wiredData.length() >= 1) {
this.repeatTime = (Integer.parseInt(wiredData));
storedRepeatTime = data != null ? data.repeatTime : null;
} else if (wiredData != null && wiredData.length() >= 1) {
storedRepeatTime = Integer.parseInt(wiredData);
}
} catch (RuntimeException ignored) {
storedRepeatTime = null;
}
}
if (this.repeatTime < 5000) {
this.repeatTime = 20 * 5000;
}
this.repeatTime = WiredTimerInputGuard.normalizeStoredMillis(storedRepeatTime, MIN_DELAY, LEGACY_FALLBACK_DELAY);
}
@Override
@@ -123,15 +131,20 @@ public class WiredTriggerRepeaterLong extends InteractionWiredTrigger implements
@Override
public boolean saveData(WiredSettings settings) {
if (settings.getIntParams().length < 1) return false;
int interval = settings.getIntParams()[0];
if (interval < 1) {
interval = 1;
}
this.repeatTime = interval * 5000;
this.repeatTime = WiredTimerInputGuard.fromClientUnits(settings.getIntParams()[0], STEP_MS, MIN_DELAY);
// No accumulated time reset needed - using global tick count
return true;
}
private static int safeMultiply(int value, int factor) {
if (value <= 0) {
return DEFAULT_DELAY;
}
long multiplied = (long) value * factor;
return multiplied > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) multiplied;
}
// ========== WiredTickable Implementation ==========
@Override
@@ -3,6 +3,7 @@ package com.eu.habbo.habbohotel.items.interactions.wired.triggers;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredTimerInputGuard;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.wired.WiredTriggerType;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
@@ -94,8 +95,7 @@ public class WiredTriggerRepeaterShort extends WiredTriggerRepeater {
public boolean saveData(WiredSettings settings) {
if (settings.getIntParams().length < 1) return false;
int newRepeatTime = settings.getIntParams()[0] * STEP_MS;
this.repeatTime = clampRepeatTime(newRepeatTime);
this.repeatTime = WiredTimerInputGuard.fromClientUnits(settings.getIntParams()[0], STEP_MS, MIN_DELAY, MAX_DELAY);
return true;
}
@@ -18,6 +18,7 @@ import java.sql.SQLException;
public class WiredTriggerScoreAchieved extends InteractionWiredTrigger {
private static final WiredTriggerType type = WiredTriggerType.SCORE_ACHIEVED;
static final int MAX_SCORE = 1_000_000;
private int score = 0;
private int teamType = GameTeamColors.NONE.type;
@@ -71,17 +72,27 @@ public class WiredTriggerScoreAchieved extends InteractionWiredTrigger {
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
String wiredData = set.getString("wired_data");
JsonData data = parseData(wiredData);
this.score = data.score;
this.teamType = data.teamType;
}
static JsonData parseData(String wiredData) {
if (wiredData == null || wiredData.isBlank()) {
return new JsonData(0, GameTeamColors.NONE.type);
}
try {
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.score = data.score;
this.teamType = normalizeTeamType(data.teamType);
} else {
try {
this.score = Integer.parseInt(wiredData);
} catch (Exception e) {
return data != null
? new JsonData(clampScore(data.score), normalizeTeamType(data.teamType))
: new JsonData(0, GameTeamColors.NONE.type);
}
this.teamType = GameTeamColors.NONE.type;
return new JsonData(clampScore(Integer.parseInt(wiredData)), GameTeamColors.NONE.type);
} catch (RuntimeException e) {
return new JsonData(0, GameTeamColors.NONE.type);
}
}
@@ -116,7 +127,7 @@ public class WiredTriggerScoreAchieved extends InteractionWiredTrigger {
@Override
public boolean saveData(WiredSettings settings) {
if(settings.getIntParams().length < 1) return false;
this.score = settings.getIntParams()[0];
this.score = clampScore(settings.getIntParams()[0]);
this.teamType = (settings.getIntParams().length > 1)
? normalizeTeamType(settings.getIntParams()[1])
: GameTeamColors.NONE.type;
@@ -128,7 +139,15 @@ public class WiredTriggerScoreAchieved extends InteractionWiredTrigger {
return true;
}
private int normalizeTeamType(int value) {
static int clampScore(int value) {
if (value < 0) {
return 0;
}
return Math.min(value, MAX_SCORE);
}
static int normalizeTeamType(int value) {
if (value >= GameTeamColors.RED.type && value <= GameTeamColors.YELLOW.type) {
return value;
}
@@ -11,6 +11,10 @@ public enum PermissionSetting {
ROOM_OWNER;
public static PermissionSetting fromString(String value) {
if (value == null) {
return DISALLOWED;
}
switch (value) {
case "1":
return ALLOWED;
@@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory;
import java.sql.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -65,35 +66,45 @@ public class PermissionsManager {
}
private void loadPermissionsLegacy(Connection connection) throws SQLException {
Set<Integer> loadedRankIds = new HashSet<>();
try (Statement statement = connection.createStatement(); ResultSet set = statement.executeQuery("SELECT * FROM permissions ORDER BY id ASC")) {
while (set.next()) {
int rankId = set.getInt("id");
loadedRankIds.add(rankId);
Rank rank = null;
if (!this.ranks.containsKey(set.getInt("id"))) {
if (!this.ranks.containsKey(rankId)) {
rank = new Rank(set);
this.ranks.put(set.getInt("id"), rank);
this.ranks.put(rankId, rank);
} else {
rank = this.ranks.get(set.getInt("id"));
rank = this.ranks.get(rankId);
rank.load(set);
}
this.addBadgeMapping(rank);
}
}
this.pruneMissingRanks(loadedRankIds);
}
private boolean loadPermissionsNormalized(Connection connection) throws SQLException {
boolean hasRanks = false;
List<Rank> loadedRanks = new ArrayList<>();
Set<Integer> loadedRankIds = new HashSet<>();
try (Statement statement = connection.createStatement(); ResultSet set = statement.executeQuery("SELECT * FROM permission_ranks ORDER BY id ASC")) {
while (set.next()) {
hasRanks = true;
int rankId = set.getInt("id");
loadedRankIds.add(rankId);
Rank rank = this.ranks.get(set.getInt("id"));
Rank rank = this.ranks.get(rankId);
if (rank == null) {
rank = new Rank(set.getInt("id"));
this.ranks.put(set.getInt("id"), rank);
rank = new Rank(rankId);
this.ranks.put(rankId, rank);
}
rank.loadNormalizedMetadata(set);
@@ -141,9 +152,18 @@ public class PermissionsManager {
}
}
this.pruneMissingRanks(loadedRankIds);
return hasDefinitions;
}
private void pruneMissingRanks(Set<Integer> loadedRankIds) {
for (int rankId : this.ranks.keys()) {
if (!loadedRankIds.contains(rankId)) {
this.ranks.remove(rankId);
}
}
}
private void ensureNormalizedRankColumns(Connection connection, List<Rank> loadedRanks) throws SQLException {
Set<String> availableColumns = new HashSet<>();
@@ -254,6 +274,10 @@ public class PermissionsManager {
public boolean hasPermission(Habbo habbo, String permission, boolean withRoomRights) {
if (habbo == null || habbo.getHabboInfo() == null || permission == null || permission.isBlank()) {
return false;
}
if (!this.hasPermission(habbo.getHabboInfo().getRank(), permission, withRoomRights)) {
for (HabboPlugin plugin : Emulator.getPluginManager().getPlugins()) {
if (plugin.hasPermission(habbo, permission)) {
@@ -269,15 +293,16 @@ public class PermissionsManager {
public boolean hasPermission(Rank rank, String permission, boolean withRoomRights) {
return rank.hasPermission(permission, withRoomRights);
return rank != null && permission != null && !permission.isBlank() && rank.hasPermission(permission, withRoomRights);
}
public Set<String> getStaffBadges() {
return this.badges.keySet();
return Collections.unmodifiableSet(new HashSet<>(this.badges.keySet()));
}
public List<Rank> getRanksByBadgeCode(String code) {
return this.badges.get(code);
List<Rank> ranks = this.badges.get(code);
return ranks == null ? Collections.emptyList() : Collections.unmodifiableList(new ArrayList<>(ranks));
}
public List<Rank> getAllRanks() {
@@ -114,6 +114,10 @@ public class Rank {
}
public boolean hasPermission(String key, boolean isRoomOwner) {
if (key == null || key.isBlank()) {
return false;
}
if (this.permissions.containsKey(key)) {
Permission permission = this.permissions.get(key);
@@ -23,6 +23,7 @@ public class RoomTrade {
//Configuration. Loaded from database & updated accordingly.
public static boolean TRADING_ENABLED = true;
public static boolean TRADING_REQUIRES_PERK = true;
public static final int MAX_OFFERED_ITEMS = 100;
private final List<RoomTradeUser> users;
private final Room room;
@@ -58,7 +59,7 @@ public class RoomTrade {
public synchronized void offerItem(Habbo habbo, HabboItem item) {
RoomTradeUser user = this.getRoomTradeUserForHabbo(habbo);
if (user == null || item == null || user.getItems().contains(item))
if (user == null || item == null || user.getItems().contains(item) || user.getItems().size() >= MAX_OFFERED_ITEMS)
return;
habbo.getInventory().getItemsComponent().removeHabboItem(item);
@@ -75,6 +76,9 @@ public class RoomTrade {
return;
for (HabboItem item : items) {
if (user.getItems().size() >= MAX_OFFERED_ITEMS)
break;
if (!user.getItems().contains(item)) {
habbo.getInventory().getItemsComponent().removeHabboItem(item);
user.getItems().add(item);
@@ -14,7 +14,7 @@ public class WiredMatchFurniSetting {
public WiredMatchFurniSetting(int itemId, String state, int rotation, int x, int y, double z) {
this.item_id = itemId;
this.state = state.replace("\t\t\t", " ");
this.state = state == null ? "" : state.replace("\t\t\t", " ");
this.rotation = rotation;
this.x = x;
this.y = y;
@@ -12,10 +12,15 @@ public class CatalogSearchedItemEvent extends MessageHandler {
public void handle() throws Exception {
int offerId = this.packet.readInt();
int pageId = Emulator.getGameEnvironment().getCatalogManager().offerDefs.get(offerId);
int catalogItemId = Emulator.getGameEnvironment().getCatalogManager().offerDefs.get(offerId);
if (pageId != 0) {
CatalogPage page = Emulator.getGameEnvironment().getCatalogManager().getCatalogPage(Emulator.getGameEnvironment().getCatalogManager().getCatalogItem(pageId).getPageId());
if (catalogItemId != 0) {
CatalogItem requestedItem = Emulator.getGameEnvironment().getCatalogManager().getCatalogItem(catalogItemId);
if (requestedItem == null) {
return;
}
CatalogPage page = Emulator.getGameEnvironment().getCatalogManager().getCatalogPage(requestedItem.getPageId());
if (page != null) {
TIntObjectIterator<CatalogItem> iterator = page.getCatalogItems().iterator();
@@ -25,7 +30,7 @@ public class CatalogSearchedItemEvent extends MessageHandler {
CatalogItem item = iterator.value();
if (item.getOfferId() == offerId) {
if (item.getSearchOfferId() == offerId) {
this.client.sendResponse(new CatalogSearchResultComposer(item));
return;
}
@@ -13,6 +13,10 @@ public class BuyItemEvent extends MessageHandler {
public void handle() throws Exception {
int offerId = this.packet.readInt();
if (!MarketplaceInputGuard.isPositiveId(offerId)) {
return;
}
MarketPlace.buyItem(offerId, this.client);
}
}
@@ -0,0 +1,47 @@
package com.eu.habbo.messages.incoming.catalog.marketplace;
import com.eu.habbo.habbohotel.catalog.marketplace.MarketPlace;
final class MarketplaceInputGuard {
static final int MAX_SEARCH_LENGTH = 30;
static final int DEFAULT_SORT = 1;
static final int MIN_SORT = 1;
static final int MAX_SORT = 6;
private MarketplaceInputGuard() {
}
static boolean isPositiveId(int id) {
return id > 0;
}
static String normalizeSearch(String query) {
if (query == null) {
return "";
}
String normalized = query.trim();
return normalized.length() > MAX_SEARCH_LENGTH ? normalized.substring(0, MAX_SEARCH_LENGTH) : normalized;
}
static int normalizeSort(int sort) {
return sort >= MIN_SORT && sort <= MAX_SORT ? sort : DEFAULT_SORT;
}
static int normalizeMinPrice(int minPrice) {
if (minPrice == -1) {
return -1;
}
return Math.max(0, Math.min(minPrice, MarketPlace.MAXIMUM_LISTING_PRICE));
}
static int normalizeMaxPrice(int maxPrice, int minPrice) {
if (maxPrice == -1) {
return -1;
}
int normalized = Math.max(0, Math.min(maxPrice, MarketPlace.MAXIMUM_LISTING_PRICE));
return minPrice > 0 && normalized > 0 && normalized < minPrice ? minPrice : normalized;
}
}
@@ -9,6 +9,10 @@ public class RequestItemInfoEvent extends MessageHandler {
this.packet.readInt();
int id = this.packet.readInt();
if (!MarketplaceInputGuard.isPositiveId(id)) {
return;
}
this.client.sendResponse(new MarketplaceItemInfoComposer(id));
}
}
@@ -20,14 +20,10 @@ public class RequestOffersEvent extends MessageHandler {
@Override
public void handle() throws Exception {
int min = this.packet.readInt();
int max = this.packet.readInt();
String query = this.packet.readString();
int type = this.packet.readInt();
if (query.length() > 30) {
query = query.substring(0, 30);
}
int min = MarketplaceInputGuard.normalizeMinPrice(this.packet.readInt());
int max = MarketplaceInputGuard.normalizeMaxPrice(this.packet.readInt(), min);
String query = MarketplaceInputGuard.normalizeSearch(this.packet.readString());
int type = MarketplaceInputGuard.normalizeSort(this.packet.readInt());
boolean tryCache = min == -1 && max == -1 && query.isEmpty();
@@ -29,6 +29,7 @@ public class SellItemEvent extends MessageHandler {
final int furniType = this.packet.readInt(); // 1 = FLOOR_TYPE, 2 = WALL_TYPE
final int itemId = this.packet.readInt();
if (!MarketplaceInputGuard.isPositiveId(itemId)) return;
if (furniType != 1 && furniType != 2) return;
HabboItem item = this.client.getHabbo().getInventory().getItemsComponent().getHabboItem(itemId);

Some files were not shown because too many files have changed in this diff Show More