diff --git a/sqlupdates/2_0_0-RC-2_TO_2_0_0-RC-3.sql b/sqlupdates/2_0_0-RC-2_TO_2_0_0-RC-3.sql index 223a8f75..c49c2386 100644 --- a/sqlupdates/2_0_0-RC-2_TO_2_0_0-RC-3.sql +++ b/sqlupdates/2_0_0-RC-2_TO_2_0_0-RC-3.sql @@ -17,4 +17,8 @@ INSERT INTO `emulator_texts`(`key`, `value`) VALUES ('invisible.prevent.chat.err INSERT INTO `emulator_texts`(`key`, `value`) VALUES ('commands.succes.cmd_invisible.updated.back', 'You are now visible again.'); +INSERT INTO `emulator_texts`(`key`, `value`) VALUES ('commands.error.cmd_mimic.forbidden_clothing', 'The other user has clothing that you do not own yet.'); +ALTER TABLE `permissions` +ADD COLUMN `acc_mimic_unredeemed` enum('0','1') NOT NULL DEFAULT '0'; + #END DATABASE UPDATE: 2.0.0 RC-2 -> 2.0.0 RC-3 diff --git a/src/main/java/com/eu/habbo/habbohotel/commands/MimicCommand.java b/src/main/java/com/eu/habbo/habbohotel/commands/MimicCommand.java index bcf6a56f..dbfa6598 100644 --- a/src/main/java/com/eu/habbo/habbohotel/commands/MimicCommand.java +++ b/src/main/java/com/eu/habbo/habbohotel/commands/MimicCommand.java @@ -7,6 +7,7 @@ import com.eu.habbo.habbohotel.users.Habbo; import com.eu.habbo.habbohotel.users.HabboGender; import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer; import com.eu.habbo.messages.outgoing.users.UserDataComposer; +import com.eu.habbo.util.figure.FigureUtil; public class MimicCommand extends Command { @@ -18,28 +19,24 @@ public class MimicCommand extends Command @Override public boolean handle(GameClient gameClient, String[] params) throws Exception { - if(params.length == 2) - { + if (params.length == 2) { Habbo habbo = gameClient.getHabbo().getHabboInfo().getCurrentRoom().getHabbo(params[1]); - if (habbo == null) - { + if (habbo == null) { gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_mimic.not_found").replace("%user%", ""), RoomChatMessageBubbles.ALERT); return true; } - if(habbo == gameClient.getHabbo()) - { + if (habbo == gameClient.getHabbo()) { gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_mimic.not_self"), RoomChatMessageBubbles.ALERT); return true; - } - else if(habbo.hasPermission("acc_not_mimiced") && !gameClient.getHabbo().hasPermission("acc_not_mimiced")) - { + } else if (habbo.hasPermission("acc_not_mimiced") && !gameClient.getHabbo().hasPermission("acc_not_mimiced")) { gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_mimic.blocked").replace("%user%", params[1]).replace("%gender_name%", (habbo.getHabboInfo().getGender().equals(HabboGender.M) ? Emulator.getTexts().getValue("gender.him") : Emulator.getTexts().getValue("gender.her"))), RoomChatMessageBubbles.ALERT); return true; - } - else - { + } else if (!habbo.hasPermission("acc_mimic_unredeemed") && FigureUtil.hasBlacklistedClothing(habbo.getHabboInfo().getLook(), gameClient.getHabbo().getForbiddenClothing())) { + gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_mimic.forbidden_clothing"), RoomChatMessageBubbles.ALERT); + return true; + } else { gameClient.getHabbo().getHabboInfo().setLook(habbo.getHabboInfo().getLook()); gameClient.getHabbo().getHabboInfo().setGender(habbo.getHabboInfo().getGender()); gameClient.sendResponse(new UserDataComposer(gameClient.getHabbo())); diff --git a/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionMannequin.java b/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionMannequin.java index 53c50531..29d4d6b4 100644 --- a/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionMannequin.java +++ b/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionMannequin.java @@ -9,6 +9,7 @@ import com.eu.habbo.habbohotel.users.HabboItem; import com.eu.habbo.messages.ServerMessage; import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer; import com.eu.habbo.messages.outgoing.users.UserDataComposer; +import com.eu.habbo.util.figure.FigureUtil; import java.sql.ResultSet; import java.sql.SQLException; @@ -93,7 +94,7 @@ public class InteractionMannequin extends HabboItem } } - client.getHabbo().getHabboInfo().setLook(look.substring(0, look.length() - 1)); + client.getHabbo().getHabboInfo().setLook(look.substring(0, look.length() - 1), true); room.sendComposer(new RoomUserDataComposer(client.getHabbo()).compose()); client.sendResponse(new UserDataComposer(client.getHabbo())); } diff --git a/src/main/java/com/eu/habbo/habbohotel/items/interactions/games/football/InteractionFootballGate.java b/src/main/java/com/eu/habbo/habbohotel/items/interactions/games/football/InteractionFootballGate.java index b0e6950c..eb968519 100644 --- a/src/main/java/com/eu/habbo/habbohotel/items/interactions/games/football/InteractionFootballGate.java +++ b/src/main/java/com/eu/habbo/habbohotel/items/interactions/games/football/InteractionFootballGate.java @@ -14,7 +14,7 @@ import com.eu.habbo.plugin.EventHandler; import com.eu.habbo.plugin.events.users.UserDisconnectEvent; import com.eu.habbo.plugin.events.users.UserExitRoomEvent; import com.eu.habbo.plugin.events.users.UserSavedLookEvent; -import com.eu.habbo.util.FigureUtil; +import com.eu.habbo.util.figure.FigureUtil; import java.sql.ResultSet; import java.sql.SQLException; @@ -102,7 +102,7 @@ public class InteractionFootballGate extends HabboItem Emulator.getPluginManager().fireEvent(lookEvent); if(!lookEvent.isCancelled()) { - habbo.getHabboInfo().setLook(lookEvent.newLook); + habbo.getHabboInfo().setLook(lookEvent.newLook, true); Emulator.getThreading().run(habbo.getHabboInfo()); habbo.getClient().sendResponse(new UpdateUserLookComposer(habbo)); room.sendComposer(new RoomUserDataComposer(habbo).compose()); @@ -119,7 +119,7 @@ public class InteractionFootballGate extends HabboItem if(!lookEvent.isCancelled()) { habbo.getHabboStats().cache.put(CACHE_KEY, habbo.getHabboInfo().getLook()); - habbo.getHabboInfo().setLook(lookEvent.newLook); + habbo.getHabboInfo().setLook(lookEvent.newLook, true); Emulator.getThreading().run(habbo.getHabboInfo()); habbo.getClient().sendResponse(new UpdateUserLookComposer(habbo)); room.sendComposer(new RoomUserDataComposer(habbo).compose()); diff --git a/src/main/java/com/eu/habbo/habbohotel/users/Habbo.java b/src/main/java/com/eu/habbo/habbohotel/users/Habbo.java index 9434ad33..bd7799b4 100644 --- a/src/main/java/com/eu/habbo/habbohotel/users/Habbo.java +++ b/src/main/java/com/eu/habbo/habbohotel/users/Habbo.java @@ -17,14 +17,15 @@ import com.eu.habbo.messages.outgoing.users.*; import com.eu.habbo.plugin.events.users.UserCreditsEvent; import com.eu.habbo.plugin.events.users.UserDisconnectEvent; import com.eu.habbo.plugin.events.users.UserPointsEvent; +import gnu.trove.TIntCollection; import gnu.trove.map.hash.THashMap; import gnu.trove.set.hash.THashSet; import java.net.InetSocketAddress; import java.sql.ResultSet; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class Habbo implements Runnable { @@ -512,4 +513,14 @@ public class Habbo implements Runnable this.client.getHabbo().getHabboInfo().getCurrentRoom().unIdle(this.client.getHabbo()); } } + + public Set getForbiddenClothing() { + TIntCollection clothingIDs = this.getInventory().getWardrobeComponent().getClothing(); + + return Emulator.getGameEnvironment().getCatalogManager().clothing.values().stream() + .filter(c -> !clothingIDs.contains(c.id)) + .map(c -> c.setId) + .flatMap(c -> Arrays.stream(c).boxed()) + .collect(Collectors.toSet()); + } } diff --git a/src/main/java/com/eu/habbo/habbohotel/users/HabboInfo.java b/src/main/java/com/eu/habbo/habbohotel/users/HabboInfo.java index 15b6f22b..d4bc2357 100644 --- a/src/main/java/com/eu/habbo/habbohotel/users/HabboInfo.java +++ b/src/main/java/com/eu/habbo/habbohotel/users/HabboInfo.java @@ -13,6 +13,7 @@ import com.eu.habbo.habbohotel.rooms.RoomTile; import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.messages.outgoing.rooms.users.RoomUserStatusComposer; import com.eu.habbo.threading.runnables.RoomUnitRidePet; +import com.eu.habbo.util.figure.FigureUtil; import gnu.trove.map.hash.TIntIntHashMap; import gnu.trove.procedure.TIntIntProcedure; @@ -215,7 +216,19 @@ public class HabboInfo implements Runnable return this.look; } - public void setLook(String look) { this.look = look; } + public void setLook(String look) { + this.setLook(look, false); + } + + public void setLook(String look, boolean stripForbidden) { + if (stripForbidden) { + Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(this.id); + + if (habbo != null) look = FigureUtil.stripBlacklistedClothing(look, habbo.getForbiddenClothing()); + } + + this.look = look; + } public HabboGender getGender() { diff --git a/src/main/java/com/eu/habbo/messages/incoming/users/UserSaveLookEvent.java b/src/main/java/com/eu/habbo/messages/incoming/users/UserSaveLookEvent.java index 86cf3b6b..53fffdb3 100644 --- a/src/main/java/com/eu/habbo/messages/incoming/users/UserSaveLookEvent.java +++ b/src/main/java/com/eu/habbo/messages/incoming/users/UserSaveLookEvent.java @@ -8,6 +8,7 @@ import com.eu.habbo.messages.incoming.MessageHandler; import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer; import com.eu.habbo.messages.outgoing.users.UpdateUserLookComposer; import com.eu.habbo.plugin.events.users.UserSavedLookEvent; +import com.eu.habbo.util.figure.FigureUtil; public class UserSaveLookEvent extends MessageHandler { @@ -30,6 +31,12 @@ public class UserSaveLookEvent extends MessageHandler } String look = this.packet.readString(); + + if (FigureUtil.hasBlacklistedClothing(look, this.client.getHabbo().getForbiddenClothing())) { + ScripterManager.scripterDetected(this.client, "The user tried to wear clothing that they have not bought yet."); + return; + } + UserSavedLookEvent lookEvent = new UserSavedLookEvent(this.client.getHabbo(), gender, look); Emulator.getPluginManager().fireEvent(lookEvent); if(lookEvent.isCancelled()) diff --git a/src/main/java/com/eu/habbo/messages/rcon/UpdateUser.java b/src/main/java/com/eu/habbo/messages/rcon/UpdateUser.java index 56e08f46..d661af1b 100644 --- a/src/main/java/com/eu/habbo/messages/rcon/UpdateUser.java +++ b/src/main/java/com/eu/habbo/messages/rcon/UpdateUser.java @@ -5,6 +5,7 @@ import com.eu.habbo.habbohotel.users.Habbo; import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer; import com.eu.habbo.messages.outgoing.users.MeMenuSettingsComposer; import com.eu.habbo.messages.outgoing.users.UpdateUserLookComposer; +import com.eu.habbo.util.figure.FigureUtil; import com.google.gson.Gson; import java.sql.Connection; @@ -57,7 +58,7 @@ public class UpdateUser extends RCONMessage if (!json.look.isEmpty()) { - habbo.getHabboInfo().setLook(json.look); + habbo.getHabboInfo().setLook(json.look, json.strip_unredeemed_clothing); if(habbo.getClient() != null) { habbo.getClient().sendResponse(new UpdateUserLookComposer(habbo).compose()); } @@ -160,6 +161,8 @@ public class UpdateUser extends RCONMessage public String look = ""; + + public boolean strip_unredeemed_clothing = false; //More could be added in the future. } } \ No newline at end of file diff --git a/src/main/java/com/eu/habbo/util/FigureUtil.java b/src/main/java/com/eu/habbo/util/FigureUtil.java deleted file mode 100644 index 6a5a7f4e..00000000 --- a/src/main/java/com/eu/habbo/util/FigureUtil.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.eu.habbo.util; - -import gnu.trove.map.hash.THashMap; -import org.apache.commons.lang3.ArrayUtils; - -import java.util.Map; - -public class FigureUtil -{ - public static THashMap getFigureBits(String looks) - { - THashMap bits = new THashMap<>(); - String[] sets = looks.split("\\."); - - for(String set : sets) - { - String[] setBits = set.split("-", 2); - bits.put(setBits[0], setBits.length > 1 ? setBits[1] : ""); - } - - return bits; - } - - - public static String mergeFigures(String figure1, String figure2) - { - return mergeFigures(figure1, figure2, null, null); - } - - public static String mergeFigures(String figure1, String figure2, String[] limitFigure1) - { - return mergeFigures(figure1, figure2, limitFigure1, null); - } - - public static String mergeFigures(String figure1, String figure2, String[] limitFigure1, String[] limitFigure2) - { - THashMap figureBits1 = getFigureBits(figure1); - THashMap figureBits2 = getFigureBits(figure2); - - StringBuilder finalLook = new StringBuilder(); - - for (Map.Entry keys : figureBits1.entrySet()) - { - if(limitFigure1 == null || ArrayUtils.contains(limitFigure1, keys.getKey())) - { - finalLook.append(keys.getKey()).append("-").append(keys.getValue()).append("."); - } - } - - for (Map.Entry keys : figureBits2.entrySet()) - { - if(limitFigure2 == null || ArrayUtils.contains(limitFigure2, keys.getKey())) - { - finalLook.append(keys.getKey()).append("-").append(keys.getValue()).append("."); - } - } - - if(finalLook.toString().endsWith(".")) - { - finalLook = new StringBuilder(finalLook.substring(0, finalLook.length() - 1)); - } - - return finalLook.toString(); - } -} \ No newline at end of file diff --git a/src/main/java/com/eu/habbo/util/figure/FigureUtil.java b/src/main/java/com/eu/habbo/util/figure/FigureUtil.java index 9c17ac91..9c20ac00 100644 --- a/src/main/java/com/eu/habbo/util/figure/FigureUtil.java +++ b/src/main/java/com/eu/habbo/util/figure/FigureUtil.java @@ -4,34 +4,70 @@ import gnu.trove.map.hash.THashMap; import org.apache.commons.lang3.ArrayUtils; import java.util.Map; +import java.util.Set; +import java.util.StringJoiner; -public class FigureUtil +public class FigureUtil { - public static THashMap getFigureBits(String looks) + public static THashMap getFigureBits(String looks) { THashMap bits = new THashMap<>(); String[] sets = looks.split("\\."); - + for(String set : sets) { String[] setBits = set.split("-", 2); bits.put(setBits[0], setBits.length > 1 ? setBits[1] : ""); } - + return bits; } - - + + public static String mergeFigures(String figure1, String figure2) { return mergeFigures(figure1, figure2, null, null); } - + public static String mergeFigures(String figure1, String figure2, String[] limitFigure1) { return mergeFigures(figure1, figure2, limitFigure1, null); } - + + public static boolean hasBlacklistedClothing(String figure, Set blacklist) { + for (String set : figure.split("\\.")) { + String[] pieces = set.split("-"); + + try { + if (pieces.length >= 2 && blacklist.contains(Integer.valueOf(pieces[1]))) { + return true; + } + } catch (NumberFormatException ignored) { + + } + } + + return false; + } + + public static String stripBlacklistedClothing(String figure, Set blacklist) { + StringJoiner joiner = new StringJoiner("."); + + for (String set : figure.split("\\.")) { + String[] pieces = set.split("-"); + + try { + if (pieces.length < 2 || !blacklist.contains(Integer.valueOf(pieces[1]))) { + joiner.add(set); + } + } catch (NumberFormatException ignored) { + joiner.add(set); + } + } + + return joiner.toString(); + } + public static String mergeFigures(String figure1, String figure2, String[] limitFigure1, String[] limitFigure2) { THashMap figureBits1 = getFigureBits(figure1); @@ -39,17 +75,17 @@ public class FigureUtil StringBuilder finalLook = new StringBuilder(); - for (Map.Entry keys : figureBits1.entrySet()) + for (Map.Entry keys : figureBits1.entrySet()) { - if(limitFigure1 == null || ArrayUtils.contains(limitFigure1, keys.getKey())) + if(limitFigure1 == null || ArrayUtils.contains(limitFigure1, keys.getKey())) { finalLook.append(keys.getKey()).append("-").append(keys.getValue()).append("."); } } - for (Map.Entry keys : figureBits2.entrySet()) + for (Map.Entry keys : figureBits2.entrySet()) { - if(limitFigure2 == null || ArrayUtils.contains(limitFigure2, keys.getKey())) + if(limitFigure2 == null || ArrayUtils.contains(limitFigure2, keys.getKey())) { finalLook.append(keys.getKey()).append("-").append(keys.getValue()).append("."); } @@ -59,7 +95,7 @@ public class FigureUtil { finalLook = new StringBuilder(finalLook.substring(0, finalLook.length() - 1)); } - + return finalLook.toString(); } -} +} \ No newline at end of file