From 6ab152c47df76743e3131f97cb37fad57be8ce6f Mon Sep 17 00:00:00 2001 From: Lorenzune Date: Fri, 3 Apr 2026 12:09:16 +0200 Subject: [PATCH] feat: add room control furni and stack walk helper --- .../habbo/habbohotel/items/ItemManager.java | 8 + .../InteractionAreaHideControl.java | 172 ++++++++++++++++ .../InteractionConfInvisControl.java | 16 ++ .../InteractionHanditemBlockControl.java | 16 ++ .../InteractionQueueSpeedControl.java | 186 ++++++++++++++++++ .../InteractionRemoteSwitchControl.java | 21 ++ .../InteractionStackWalkHelper.java | 48 +++++ .../InteractionWiredDisableControl.java | 16 ++ .../com/eu/habbo/habbohotel/rooms/Room.java | 53 +++-- .../habbohotel/rooms/RoomAreaHideSupport.java | 100 ++++++++++ .../rooms/RoomConfInvisSupport.java | 107 ++++++++++ .../habbohotel/rooms/RoomCycleManager.java | 3 +- .../rooms/RoomHanditemBlockSupport.java | 65 ++++++ .../habbohotel/rooms/RoomItemManager.java | 157 ++++++++++++--- .../habbo/habbohotel/rooms/RoomManager.java | 6 + .../rooms/RoomQueueSpeedControlSupport.java | 77 ++++++++ .../habbohotel/rooms/RoomRollerManager.java | 2 +- .../habbohotel/rooms/RoomTileManager.java | 15 +- .../eu/habbo/habbohotel/rooms/RoomUnit.java | 3 +- .../rooms/RoomWiredDisableSupport.java | 47 +++++ .../habbo/habbohotel/wired/WiredHandler.java | 10 + .../habbohotel/wired/core/WiredManager.java | 9 + .../rooms/items/RoomPlaceItemEvent.java | 1 + .../items/SetStackHelperHeightEvent.java | 5 +- .../users/RoomUserGiveHandItemEvent.java | 5 + .../eu/habbo/messages/outgoing/Outgoing.java | 3 + .../rooms/items/AddFloorItemComposer.java | 8 +- .../rooms/items/AreaHideComposer.java | 30 +++ .../rooms/items/ConfInvisStateComposer.java | 34 ++++ .../rooms/items/FloorItemUpdateComposer.java | 9 +- .../items/HanditemBlockStateComposer.java | 25 +++ .../rooms/items/RoomFloorItemsComposer.java | 8 +- .../rooms/users/RoomUnitOnRollerComposer.java | 5 +- .../runnables/HabboGiveHandItemToHabbo.java | 8 + 34 files changed, 1217 insertions(+), 61 deletions(-) create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionAreaHideControl.java create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionConfInvisControl.java create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionHanditemBlockControl.java create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionQueueSpeedControl.java create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionRemoteSwitchControl.java create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionStackWalkHelper.java create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionWiredDisableControl.java create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomAreaHideSupport.java create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomConfInvisSupport.java create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomHanditemBlockSupport.java create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomQueueSpeedControlSupport.java create mode 100644 Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomWiredDisableSupport.java create mode 100644 Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/AreaHideComposer.java create mode 100644 Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/ConfInvisStateComposer.java create mode 100644 Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/HanditemBlockStateComposer.java diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java index 411a530b..2951ca56 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/ItemManager.java @@ -169,6 +169,7 @@ public class ItemManager { this.interactionsList.add(new ItemInteraction("monsterplant_seed", InteractionMonsterPlantSeed.class)); this.interactionsList.add(new ItemInteraction("gift", InteractionGift.class)); this.interactionsList.add(new ItemInteraction("stack_helper", InteractionStackHelper.class)); + this.interactionsList.add(new ItemInteraction("stack_walk_helper", InteractionStackWalkHelper.class)); this.interactionsList.add(new ItemInteraction("puzzle_box", InteractionPuzzleBox.class)); this.interactionsList.add(new ItemInteraction("hopper", InteractionHopper.class)); this.interactionsList.add(new ItemInteraction("costume_hopper", InteractionCostumeHopper.class)); @@ -198,6 +199,13 @@ public class ItemManager { this.interactionsList.add(new ItemInteraction("youtube", InteractionYoutubeTV.class)); this.interactionsList.add(new ItemInteraction("jukebox", InteractionJukeBox.class)); this.interactionsList.add(new ItemInteraction("switch", InteractionSwitch.class)); + this.interactionsList.add(new ItemInteraction("conf_invis_control", InteractionConfInvisControl.class)); + this.interactionsList.add(new ItemInteraction("wf_conf_invis_control", InteractionConfInvisControl.class)); + this.interactionsList.add(new ItemInteraction("wf_conf_area_hide", InteractionAreaHideControl.class)); + this.interactionsList.add(new ItemInteraction("conf_area_hide", InteractionAreaHideControl.class)); + this.interactionsList.add(new ItemInteraction("wf_conf_handitem_block", InteractionHanditemBlockControl.class)); + this.interactionsList.add(new ItemInteraction("wf_conf_queue_speed", InteractionQueueSpeedControl.class)); + this.interactionsList.add(new ItemInteraction("wf_conf_wired_disable", InteractionWiredDisableControl.class)); this.interactionsList.add(new ItemInteraction("switch_remote_control", InteractionSwitchRemoteControl.class)); this.interactionsList.add(new ItemInteraction("fx_box", InteractionFXBox.class)); this.interactionsList.add(new ItemInteraction("blackhole", InteractionBlackHole.class)); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionAreaHideControl.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionAreaHideControl.java new file mode 100644 index 00000000..5c7e975b --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionAreaHideControl.java @@ -0,0 +1,172 @@ +package com.eu.habbo.habbohotel.items.interactions; + +import com.eu.habbo.Emulator; +import com.eu.habbo.habbohotel.gameclients.GameClient; +import com.eu.habbo.habbohotel.items.Item; +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomAreaHideSupport; +import com.eu.habbo.habbohotel.rooms.RoomLayout; +import com.eu.habbo.habbohotel.users.Habbo; +import com.eu.habbo.habbohotel.users.HabboItem; +import com.eu.habbo.habbohotel.wired.WiredEffectType; +import com.eu.habbo.messages.ServerMessage; +import gnu.trove.map.hash.THashMap; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class InteractionAreaHideControl extends InteractionCustomValues { + public static final THashMap defaultValues = new THashMap() { + { + this.put("state", "0"); + } + { + this.put("rootX", "0"); + } + { + this.put("rootY", "0"); + } + { + this.put("width", "0"); + } + { + this.put("length", "0"); + } + { + this.put("invisibility", "0"); + } + { + this.put("wallItems", "0"); + } + { + this.put("invert", "0"); + } + }; + + public InteractionAreaHideControl(ResultSet set, Item baseItem) throws SQLException { + super(set, baseItem, defaultValues); + this.normalizeValues(); + } + + public InteractionAreaHideControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { + super(id, userId, item, extradata, limitedStack, limitedSells, defaultValues); + this.normalizeValues(); + } + + @Override + public void serializeExtradata(ServerMessage serverMessage) { + this.normalizeValues(); + + serverMessage.appendInt(5 + (this.isLimited() ? 256 : 0)); + serverMessage.appendInt(8); + serverMessage.appendInt(RoomAreaHideSupport.getState(this)); + serverMessage.appendInt(RoomAreaHideSupport.getRootX(this)); + serverMessage.appendInt(RoomAreaHideSupport.getRootY(this)); + serverMessage.appendInt(RoomAreaHideSupport.getWidth(this)); + serverMessage.appendInt(RoomAreaHideSupport.getLength(this)); + serverMessage.appendInt(RoomAreaHideSupport.isInvisibilityEnabled(this) ? 1 : 0); + serverMessage.appendInt(RoomAreaHideSupport.includesWallItems(this) ? 1 : 0); + serverMessage.appendInt(RoomAreaHideSupport.isInverted(this) ? 1 : 0); + + if (this.isLimited()) { + serverMessage.appendInt(this.getLimitedSells()); + serverMessage.appendInt(this.getLimitedStack()); + } + } + + @Override + public boolean isUsable() { + return true; + } + + @Override + public boolean allowWiredResetState() { + return true; + } + + @Override + public void onClick(GameClient client, Room room, Object[] objects) throws Exception { + if (room == null) { + return; + } + + boolean wiredToggle = objects != null + && objects.length >= 2 + && objects[1] instanceof WiredEffectType; + + if (!wiredToggle) { + if (client == null || !this.canToggle(client.getHabbo(), room)) { + return; + } + } + + this.values.put("state", (RoomAreaHideSupport.getState(this) == 1) ? "0" : "1"); + this.normalizeValues(); + this.needsUpdate(true); + Emulator.getThreading().run(this); + room.updateItem(this); + } + + @Override + public void onCustomValuesSaved(Room room, GameClient client, THashMap oldValues) { + this.normalizeValues(); + } + + public boolean canToggle(Habbo habbo, Room room) { + if (habbo == null || room == null) { + return false; + } + + if (room.hasRights(habbo)) { + return true; + } + + if (!habbo.getHabboStats().isRentingSpace()) { + return false; + } + + HabboItem rentedItem = room.getHabboItem(habbo.getHabboStats().rentedItemId); + + return room.getLayout() != null + && rentedItem != null + && RoomLayout.squareInSquare( + RoomLayout.getRectangle( + rentedItem.getX(), + rentedItem.getY(), + rentedItem.getBaseItem().getWidth(), + rentedItem.getBaseItem().getLength(), + rentedItem.getRotation() + ), + RoomLayout.getRectangle( + this.getX(), + this.getY(), + this.getBaseItem().getWidth(), + this.getBaseItem().getLength(), + this.getRotation() + ) + ); + } + + private void normalizeValues() { + this.values.put("state", booleanFlag(this.values.get("state"))); + this.values.put("rootX", Integer.toString(nonNegative(this.values.get("rootX")))); + this.values.put("rootY", Integer.toString(nonNegative(this.values.get("rootY")))); + this.values.put("width", Integer.toString(nonNegative(this.values.get("width")))); + this.values.put("length", Integer.toString(nonNegative(this.values.get("length")))); + this.values.put("invisibility", booleanFlag(this.values.get("invisibility"))); + this.values.put("wallItems", booleanFlag(this.values.get("wallItems"))); + this.values.put("invert", booleanFlag(this.values.get("invert"))); + } + + private static int nonNegative(String value) { + try { + return Math.max(0, Integer.parseInt(value)); + } catch (Exception ignored) { + return 0; + } + } + + private static String booleanFlag(String value) { + return ("1".equals(value) || "true".equalsIgnoreCase(value)) ? "1" : "0"; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionConfInvisControl.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionConfInvisControl.java new file mode 100644 index 00000000..fe132642 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionConfInvisControl.java @@ -0,0 +1,16 @@ +package com.eu.habbo.habbohotel.items.interactions; + +import com.eu.habbo.habbohotel.items.Item; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class InteractionConfInvisControl extends InteractionRemoteSwitchControl { + public InteractionConfInvisControl(ResultSet set, Item baseItem) throws SQLException { + super(set, baseItem); + } + + public InteractionConfInvisControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { + super(id, userId, item, extradata, limitedStack, limitedSells); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionHanditemBlockControl.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionHanditemBlockControl.java new file mode 100644 index 00000000..59362e23 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionHanditemBlockControl.java @@ -0,0 +1,16 @@ +package com.eu.habbo.habbohotel.items.interactions; + +import com.eu.habbo.habbohotel.items.Item; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class InteractionHanditemBlockControl extends InteractionRemoteSwitchControl { + public InteractionHanditemBlockControl(ResultSet set, Item baseItem) throws SQLException { + super(set, baseItem); + } + + public InteractionHanditemBlockControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { + super(id, userId, item, extradata, limitedStack, limitedSells); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionQueueSpeedControl.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionQueueSpeedControl.java new file mode 100644 index 00000000..6707af8d --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionQueueSpeedControl.java @@ -0,0 +1,186 @@ +package com.eu.habbo.habbohotel.items.interactions; + +import com.eu.habbo.Emulator; +import com.eu.habbo.habbohotel.gameclients.GameClient; +import com.eu.habbo.habbohotel.items.Item; +import com.eu.habbo.habbohotel.rooms.Room; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class InteractionQueueSpeedControl extends InteractionRemoteSwitchControl { + private static final int[] MODE_STATES = new int[]{0, 3, 6, 9}; + private static final int MODE_FRAME_COUNT = 3; + private static final int BASE_FRAME_DURATION_MS = 500; + + private transient volatile int animationRevision = 0; + private transient volatile int animationRoomId = 0; + private transient volatile int animationModeState = Integer.MIN_VALUE; + + public InteractionQueueSpeedControl(ResultSet set, Item baseItem) throws SQLException { + super(set, baseItem); + } + + public InteractionQueueSpeedControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { + super(id, userId, item, extradata, limitedStack, limitedSells); + } + + public static int toModeState(String extradata) { + int state = 0; + + try { + state = Integer.parseInt(extradata); + } catch (NumberFormatException ignored) { + } + + if (state >= 9) { + return 9; + } + + if (state >= 6) { + return 6; + } + + if (state >= 3) { + return 3; + } + + return 0; + } + + public static int toRollerSpeed(String extradata) { + int modeState = toModeState(extradata); + + if (modeState >= 9) { + return 3; + } + + if (modeState >= 6) { + return 2; + } + + if (modeState >= 3) { + return 1; + } + + return 0; + } + + public static int toRollerIntervalMs(String extradata) { + return BASE_FRAME_DURATION_MS * (toRollerSpeed(extradata) + 1); + } + + @Override + public void onClick(GameClient client, Room room, Object[] objects) throws Exception { + if (room == null) { + return; + } + + boolean wiredToggle = objects != null + && objects.length >= 2 + && objects[1] instanceof com.eu.habbo.habbohotel.wired.WiredEffectType; + + if (!wiredToggle) { + if (client == null) { + return; + } + + if (!this.canToggle(client.getHabbo(), room)) { + super.onClick(client, room, new Object[]{"QUEUE_SPEED_USE"}); + return; + } + } + + int nextModeState = getNextModeState(this.getExtradata()); + applyModeState(room, nextModeState, true); + + if (client != null) { + super.onClick(client, room, new Object[]{"TOGGLE_OVERRIDE"}); + } + } + + @Override + public void onPlace(Room room) { + super.onPlace(room); + this.ensureAnimationLoop(room); + } + + @Override + public void onPickUp(Room room) { + this.animationRevision++; + this.animationRoomId = 0; + this.animationModeState = Integer.MIN_VALUE; + super.onPickUp(room); + } + + public void ensureAnimationLoop(Room room) { + if (room == null || !room.isLoaded() || this.getRoomId() != room.getId()) { + return; + } + + int modeState = toModeState(this.getExtradata()); + + if (this.animationRoomId == room.getId() && this.animationModeState == modeState) { + return; + } + + applyModeState(room, modeState, false); + } + + private void applyModeState(Room room, int modeState, boolean persistSelection) { + if (room == null) { + return; + } + + this.animationRevision++; + this.animationRoomId = room.getId(); + this.animationModeState = modeState; + + this.setExtradata(Integer.toString(modeState)); + if (persistSelection) { + this.needsUpdate(true); + } + room.updateItemState(this); + + int revision = this.animationRevision; + int nextFrame = modeState + 1; + long delay = toRollerIntervalMs(Integer.toString(modeState)); + + Emulator.getThreading().run(() -> this.animateNextFrame(room, modeState, nextFrame, revision), delay); + } + + private void animateNextFrame(Room room, int modeState, int nextFrame, int revision) { + if (room == null || !room.isLoaded() || this.getRoomId() != room.getId()) { + return; + } + + if (revision != this.animationRevision || modeState != this.animationModeState) { + return; + } + + int maxFrame = modeState + (MODE_FRAME_COUNT - 1); + int frame = (nextFrame > maxFrame) ? modeState : nextFrame; + + this.setExtradata(Integer.toString(frame)); + room.updateItemState(this); + + int followingFrame = (frame >= maxFrame) ? modeState : (frame + 1); + long delay = toRollerIntervalMs(Integer.toString(modeState)); + + Emulator.getThreading().run(() -> this.animateNextFrame(room, modeState, followingFrame, revision), delay); + } + + private static int getNextModeState(String extradata) { + int currentModeState = toModeState(extradata); + + for (int index = 0; index < MODE_STATES.length; index++) { + if (MODE_STATES[index] != currentModeState) { + continue; + } + + return MODE_STATES[(index + 1) % MODE_STATES.length]; + } + + return MODE_STATES[0]; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionRemoteSwitchControl.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionRemoteSwitchControl.java new file mode 100644 index 00000000..aeb7f8f0 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionRemoteSwitchControl.java @@ -0,0 +1,21 @@ +package com.eu.habbo.habbohotel.items.interactions; + +import com.eu.habbo.habbohotel.items.Item; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class InteractionRemoteSwitchControl extends InteractionDefault { + public InteractionRemoteSwitchControl(ResultSet set, Item baseItem) throws SQLException { + super(set, baseItem); + } + + public InteractionRemoteSwitchControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { + super(id, userId, item, extradata, limitedStack, limitedSells); + } + + @Override + public boolean isUsable() { + return true; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionStackWalkHelper.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionStackWalkHelper.java new file mode 100644 index 00000000..d6102f98 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionStackWalkHelper.java @@ -0,0 +1,48 @@ +package com.eu.habbo.habbohotel.items.interactions; + +import com.eu.habbo.habbohotel.items.Item; +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomUnit; +import com.eu.habbo.habbohotel.users.HabboItem; +import com.eu.habbo.messages.ServerMessage; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class InteractionStackWalkHelper extends HabboItem { + public InteractionStackWalkHelper(ResultSet set, Item baseItem) throws SQLException { + super(set, baseItem); + } + + public InteractionStackWalkHelper(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { + super(id, userId, item, extradata, limitedStack, limitedSells); + } + + @Override + public boolean canWalkOn(RoomUnit roomUnit, Room room, Object[] objects) { + return false; + } + + @Override + public boolean isWalkable() { + return false; + } + + @Override + public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) throws Exception { + + } + + @Override + public void serializeExtradata(ServerMessage serverMessage) { + serverMessage.appendInt((this.isLimited() ? 256 : 0)); + serverMessage.appendString(this.getExtradata()); + + super.serializeExtradata(serverMessage); + } + + @Override + public boolean isUsable() { + return true; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionWiredDisableControl.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionWiredDisableControl.java new file mode 100644 index 00000000..2c69ff86 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/InteractionWiredDisableControl.java @@ -0,0 +1,16 @@ +package com.eu.habbo.habbohotel.items.interactions; + +import com.eu.habbo.habbohotel.items.Item; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class InteractionWiredDisableControl extends InteractionRemoteSwitchControl { + public InteractionWiredDisableControl(ResultSet set, Item baseItem) throws SQLException { + super(set, baseItem); + } + + public InteractionWiredDisableControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { + super(id, userId, item, extradata, limitedStack, limitedSells); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java index d0231b6f..87096178 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java @@ -2458,29 +2458,38 @@ public class Room implements Comparable, ISerialize, Runnable { } public void updateItem(HabboItem item) { - if (this.isLoaded()) { - if (item != null && item.getRoomId() == this.id) { - if (item.getBaseItem() != null) { - if (item.getBaseItem().getType() == FurnitureType.FLOOR) { - this.sendComposer(new FloorItemUpdateComposer(item).compose()); - this.updateTiles(this.getLayout() - .getTilesAt(this.layout.getTile(item.getX(), item.getY()), - item.getBaseItem().getWidth(), item.getBaseItem().getLength(), - item.getRotation())); - } else if (item.getBaseItem().getType() == FurnitureType.WALL) { - this.sendComposer(new WallItemUpdateComposer(item).compose()); + if (this.isLoaded()) { + if (item != null && item.getRoomId() == this.id) { + if (item.getBaseItem() != null) { + if (item.getBaseItem().getType() == FurnitureType.FLOOR) { + this.sendComposer(new FloorItemUpdateComposer(item).compose()); + this.updateTiles(this.getLayout() + .getTilesAt(this.layout.getTile(item.getX(), item.getY()), + item.getBaseItem().getWidth(), item.getBaseItem().getLength(), + item.getRotation())); + + if (RoomAreaHideSupport.isControllerItem(item)) { + RoomAreaHideSupport.sendState(this, item); + } + } else if (item.getBaseItem().getType() == FurnitureType.WALL) { + this.sendComposer(new WallItemUpdateComposer(item).compose()); + } } } - } } } public void updateItemState(HabboItem item) { - if (!item.isLimited()) { - this.sendComposer(new ItemStateComposer(item).compose()); - } else { - this.sendComposer(new FloorItemUpdateComposer(item).compose()); - } + if (item != null && RoomAreaHideSupport.isControllerItem(item)) { + this.updateItem(item); + return; + } + + if (!item.isLimited()) { + this.sendComposer(new ItemStateComposer(item).compose()); + } else { + this.sendComposer(new FloorItemUpdateComposer(item).compose()); + } if (item.getBaseItem().getType() == FurnitureType.FLOOR) { if (this.layout == null) { @@ -2495,6 +2504,16 @@ public class Room implements Comparable, ISerialize, Runnable { ((InteractionMultiHeight) item).updateUnitsOnItem(this); } } + + if (item.getBaseItem().getType() == FurnitureType.FLOOR + && (RoomConfInvisSupport.isControllerItem(item) || RoomConfInvisSupport.isTarget(item))) { + RoomConfInvisSupport.sendState(this); + } + + if (item.getBaseItem().getType() == FurnitureType.FLOOR + && RoomHanditemBlockSupport.isControllerItem(item)) { + RoomHanditemBlockSupport.sendState(this); + } } public int getUserFurniCount(int userId) { diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomAreaHideSupport.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomAreaHideSupport.java new file mode 100644 index 00000000..426cbf4c --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomAreaHideSupport.java @@ -0,0 +1,100 @@ +package com.eu.habbo.habbohotel.rooms; + +import com.eu.habbo.habbohotel.gameclients.GameClient; +import com.eu.habbo.habbohotel.items.FurnitureType; +import com.eu.habbo.habbohotel.items.interactions.InteractionAreaHideControl; +import com.eu.habbo.habbohotel.users.HabboItem; +import com.eu.habbo.messages.outgoing.rooms.items.AreaHideComposer; + +public final class RoomAreaHideSupport { + private RoomAreaHideSupport() { + } + + public static boolean isControllerItem(HabboItem item) { + return item instanceof InteractionAreaHideControl + || hasInteractionName(item, "wf_conf_area_hide") + || hasInteractionName(item, "conf_area_hide"); + } + + public static boolean isControllerActive(HabboItem item) { + return isControllerItem(item) && getState(item) == 1; + } + + public static int getState(HabboItem item) { + return Math.min(1, readIntValue(item, "state", 0)); + } + + public static int getRootX(HabboItem item) { + return readIntValue(item, "rootX", 0); + } + + public static int getRootY(HabboItem item) { + return readIntValue(item, "rootY", 0); + } + + public static int getWidth(HabboItem item) { + return readIntValue(item, "width", 0); + } + + public static int getLength(HabboItem item) { + return readIntValue(item, "length", 0); + } + + public static boolean isInvisibilityEnabled(HabboItem item) { + return readIntValue(item, "invisibility", 0) == 1; + } + + public static boolean includesWallItems(HabboItem item) { + return readIntValue(item, "wallItems", 0) == 1; + } + + public static boolean isInverted(HabboItem item) { + return readIntValue(item, "invert", 0) == 1; + } + + public static void sendState(Room room, HabboItem item) { + if (room == null || item == null || !isControllerItem(item)) { + return; + } + + room.sendComposer(new AreaHideComposer(item).compose()); + } + + public static void sendState(Room room, GameClient client) { + if (room == null || client == null) { + return; + } + + for (HabboItem item : room.getFloorItems()) { + if (!isControllerActive(item)) { + continue; + } + + client.sendResponse(new AreaHideComposer(item).compose()); + } + } + + private static int readIntValue(HabboItem item, String key, int fallback) { + if (!(item instanceof InteractionAreaHideControl) || key == null) { + return fallback; + } + + InteractionAreaHideControl areaHide = (InteractionAreaHideControl) item; + String value = areaHide.values.get(key); + + try { + return Math.max(0, Integer.parseInt(value)); + } catch (Exception ignored) { + return fallback; + } + } + + private static boolean hasInteractionName(HabboItem item, String interactionName) { + return item != null + && item.getBaseItem() != null + && item.getBaseItem().getType() == FurnitureType.FLOOR + && item.getBaseItem().getInteractionType() != null + && item.getBaseItem().getInteractionType().getName() != null + && item.getBaseItem().getInteractionType().getName().equalsIgnoreCase(interactionName); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomConfInvisSupport.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomConfInvisSupport.java new file mode 100644 index 00000000..53b5be41 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomConfInvisSupport.java @@ -0,0 +1,107 @@ +package com.eu.habbo.habbohotel.rooms; + +import com.eu.habbo.habbohotel.gameclients.GameClient; +import com.eu.habbo.habbohotel.items.FurnitureType; +import com.eu.habbo.habbohotel.items.interactions.InteractionConfInvisControl; +import com.eu.habbo.habbohotel.users.HabboItem; +import com.eu.habbo.messages.outgoing.rooms.items.ConfInvisStateComposer; +import gnu.trove.list.array.TIntArrayList; + +import java.util.regex.Pattern; + +public final class RoomConfInvisSupport { + private RoomConfInvisSupport() { + } + + public static boolean isControllerItem(HabboItem item) { + return item instanceof InteractionConfInvisControl + || hasInteractionName(item, "wf_conf_invis_control"); + } + + public static boolean isControllerActive(HabboItem item) { + return isControllerItem(item) && "1".equals(item.getExtradata()); + } + + public static boolean isTarget(HabboItem item) { + return item != null + && item.getBaseItem() != null + && item.getBaseItem().getType() == FurnitureType.FLOOR + && hasCustomParamToken(item.getBaseItem().getCustomParams(), "is_invisible"); + } + + public static TIntArrayList collectHiddenFloorItemIds(Room room) { + TIntArrayList hiddenItemIds = new TIntArrayList(); + + if (room == null) { + return hiddenItemIds; + } + + if (!hasActiveController(room)) { + return hiddenItemIds; + } + + for (HabboItem item : room.getFloorItems()) { + if (isTarget(item)) { + hiddenItemIds.add(item.getId()); + } + } + + return hiddenItemIds; + } + + public static boolean hasActiveController(Room room) { + if (room == null) { + return false; + } + + for (HabboItem item : room.getFloorItems()) { + if (isControllerActive(item)) { + return true; + } + } + + return false; + } + + public static void sendState(Room room) { + if (room == null) { + return; + } + + room.sendComposer(new ConfInvisStateComposer(room).compose()); + } + + public static void sendState(Room room, GameClient client) { + if (room == null || client == null) { + return; + } + + client.sendResponse(new ConfInvisStateComposer(room).compose()); + } + + private static boolean hasCustomParamToken(String value, String token) { + if (value == null || token == null) { + return false; + } + + String normalized = value.trim().toLowerCase(); + + if (normalized.isEmpty()) { + return false; + } + + Pattern pattern = Pattern.compile("(^|[^a-z0-9_])" + Pattern.quote(token.toLowerCase()) + "($|[^a-z0-9_])"); + + return pattern.matcher(normalized).find(); + } + + private static boolean hasInteractionName(HabboItem item, String interactionName) { + if (item == null || item.getBaseItem() == null || item.getBaseItem().getInteractionType() == null || interactionName == null) { + return false; + } + + String currentInteractionName = item.getBaseItem().getInteractionType().getName(); + + return currentInteractionName != null && currentInteractionName.equalsIgnoreCase(interactionName); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomCycleManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomCycleManager.java index 8f5bbc51..c3898db1 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomCycleManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomCycleManager.java @@ -377,7 +377,8 @@ public class RoomCycleManager { * Processes roller cycle. */ private void processRollers(THashSet updatedUnit) { - int rollerSpeed = this.room.getRollerSpeed(); + Integer controlledRollerSpeed = RoomQueueSpeedControlSupport.getEffectiveRollerSpeed(this.room); + int rollerSpeed = (controlledRollerSpeed != null) ? controlledRollerSpeed : this.room.getRollerSpeed(); if (rollerSpeed != -1 && this.rollerCycle >= rollerSpeed) { this.rollerCycle = 0; this.room.getRollerManager().processRollerCycle(updatedUnit, this.cycleTimestamp); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomHanditemBlockSupport.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomHanditemBlockSupport.java new file mode 100644 index 00000000..b35025e5 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomHanditemBlockSupport.java @@ -0,0 +1,65 @@ +package com.eu.habbo.habbohotel.rooms; + +import com.eu.habbo.habbohotel.items.interactions.InteractionHanditemBlockControl; +import com.eu.habbo.habbohotel.users.HabboItem; +import com.eu.habbo.habbohotel.gameclients.GameClient; +import com.eu.habbo.messages.outgoing.rooms.items.HanditemBlockStateComposer; + +public final class RoomHanditemBlockSupport { + private static final String CONTROLLER_INTERACTION = "wf_conf_handitem_block"; + + private RoomHanditemBlockSupport() { + } + + public static boolean isHanditemBlocked(Room room) { + if (room == null) { + return false; + } + + for (HabboItem item : room.getFloorItems()) { + if (isActiveController(item)) { + return true; + } + } + + return false; + } + + public static boolean isActiveController(HabboItem item) { + return isControllerItem(item) && "1".equals(item.getExtradata()); + } + + public static boolean isControllerItem(HabboItem item) { + if (item == null || item.getBaseItem() == null) { + return false; + } + + if (item instanceof InteractionHanditemBlockControl) { + return true; + } + + if (item.getBaseItem().getInteractionType() == null) { + return false; + } + + String interactionName = item.getBaseItem().getInteractionType().getName(); + + return interactionName != null && interactionName.equalsIgnoreCase(CONTROLLER_INTERACTION); + } + + public static void sendState(Room room) { + if (room == null) { + return; + } + + room.sendComposer(new HanditemBlockStateComposer(room).compose()); + } + + public static void sendState(Room room, GameClient client) { + if (room == null || client == null) { + return; + } + + client.sendResponse(new HanditemBlockStateComposer(room).compose()); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomItemManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomItemManager.java index a95a5cd7..9b36d828 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomItemManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomItemManager.java @@ -1009,6 +1009,18 @@ public class RoomItemManager { if (item.getBaseItem().getType() == FurnitureType.FLOOR) { this.room.sendComposer(new RemoveFloorItemComposer(item).compose()); + if (RoomConfInvisSupport.isControllerItem(item) || RoomConfInvisSupport.isTarget(item)) { + RoomConfInvisSupport.sendState(this.room); + } + + if (RoomAreaHideSupport.isControllerItem(item)) { + RoomAreaHideSupport.sendState(this.room, item); + } + + if (RoomHanditemBlockSupport.isControllerItem(item)) { + RoomHanditemBlockSupport.sendState(this.room); + } + THashSet updatedTiles = this.room.getLayout().getTilesAt( this.room.getLayout().getTile(item.getX(), item.getY()), item.getBaseItem().getWidth(), @@ -1296,13 +1308,75 @@ public class RoomItemManager { /** * Checks if furniture fits at a location with unit check option. */ + private boolean isStackPlacementBypassItem(HabboItem item) { + return item instanceof InteractionStackHelper + || item instanceof InteractionTileWalkMagic + || item instanceof InteractionStackWalkHelper; + } + + private boolean shouldPinStackHelperToFloor(HabboItem item) { + return item instanceof InteractionStackHelper || item instanceof InteractionTileWalkMagic; + } + + private boolean isStackHeightHelper(HabboItem item) { + return item instanceof InteractionStackHelper + || item instanceof InteractionTileWalkMagic + || item instanceof InteractionStackWalkHelper; + } + + private HabboItem findStackHeightHelperAt(RoomTile tile, HabboItem exclude) { + if (tile == null) { + return null; + } + + for (HabboItem helper : this.getItemsAt(tile)) { + if (helper != exclude && this.isStackHeightHelper(helper)) { + return helper; + } + } + + return null; + } + + private double getMinimumTileHeight(THashSet occupiedTiles) { + double minimumHeight = 0.0D; + + for (RoomTile occupiedTile : occupiedTiles) { + minimumHeight = Math.max(minimumHeight, this.room.getLayout().getHeightAtSquare(occupiedTile.x, occupiedTile.y)); + } + + return minimumHeight; + } + + private double getConfiguredStackWalkHelperHeight(HabboItem item, THashSet occupiedTiles) { + double height = 0.0D; + + try { + if (item.getExtradata() != null && !item.getExtradata().isEmpty()) { + height = Double.parseDouble(item.getExtradata()) / 100.0D; + } + } catch (NumberFormatException ignored) { + } + + return Math.max(height, this.getMinimumTileHeight(occupiedTiles)); + } + + private double resolveStackWalkHelperHeight(HabboItem item, RoomTile tile, THashSet occupiedTiles) { + HabboItem helper = this.findStackHeightHelperAt(tile, item); + if (helper != null) { + return Math.max(helper.getZ(), this.getMinimumTileHeight(occupiedTiles)); + } + + return this.getConfiguredStackWalkHelperHeight(item, occupiedTiles); + } + public FurnitureMovementError furnitureFitsAt(RoomTile tile, HabboItem item, int rotation, boolean checkForUnits) { RoomLayout layout = this.room.getLayout(); if (!layout.fitsOnMap(tile, item.getBaseItem().getWidth(), item.getBaseItem().getLength(), rotation)) { return FurnitureMovementError.INVALID_MOVE; } - if (item instanceof InteractionStackHelper || item instanceof InteractionTileWalkMagic) { + if (this.isStackPlacementBypassItem(item)) { return FurnitureMovementError.NONE; } @@ -1354,7 +1428,7 @@ public class RoomItemManager { return FurnitureMovementError.INVALID_MOVE; } - if (item instanceof InteractionStackHelper || item instanceof InteractionTileWalkMagic) { + if (this.isStackPlacementBypassItem(item)) { return FurnitureMovementError.NONE; } @@ -1463,6 +1537,18 @@ public class RoomItemManager { this.room.sendComposer( new AddFloorItemComposer(item, this.getFurniOwnerName(item.getUserId())).compose()); + if (RoomConfInvisSupport.isControllerItem(item) || RoomConfInvisSupport.isTarget(item)) { + RoomConfInvisSupport.sendState(this.room); + } + + if (RoomAreaHideSupport.isControllerItem(item)) { + RoomAreaHideSupport.sendState(this.room, item); + } + + if (RoomHanditemBlockSupport.isControllerItem(item)) { + RoomHanditemBlockSupport.sendState(this.room); + } + for (RoomTile t : occupiedTiles) { this.room.updateHabbosAt(t.x, t.y); this.room.updateBotsAt(t.x, t.y); @@ -1530,9 +1616,7 @@ public class RoomItemManager { rotation %= 8; - boolean magicTile = - item instanceof InteractionStackHelper || - item instanceof InteractionTileWalkMagic; + boolean magicTile = this.isStackPlacementBypassItem(item); THashSet occupiedTiles = layout.getTilesAt( tile, @@ -1595,9 +1679,11 @@ public class RoomItemManager { item.setY(tile.y); item.setZ(z); - if (magicTile) { + if (this.shouldPinStackHelperToFloor(item)) { item.setZ(tile.z); item.setExtradata("" + (item.getZ() * 100)); + } else if (item instanceof InteractionStackWalkHelper) { + item.setZ(this.resolveStackWalkHelperHeight(item, tile, occupiedTiles)); } if (item.getZ() > Room.MAXIMUM_FURNI_HEIGHT) { @@ -1689,9 +1775,7 @@ public class RoomItemManager { rotation %= 8; - boolean magicTile = - item instanceof InteractionStackHelper || - item instanceof InteractionTileWalkMagic; + boolean magicTile = this.isStackPlacementBypassItem(item); THashSet occupiedTiles = layout.getTilesAt( tile, @@ -1751,9 +1835,11 @@ public class RoomItemManager { item.setY(tile.y); item.setZ(z); - if (magicTile) { + if (this.shouldPinStackHelperToFloor(item)) { item.setZ(tile.z); item.setExtradata("" + (item.getZ() * 100)); + } else if (item instanceof InteractionStackWalkHelper) { + item.setZ(this.resolveStackWalkHelperHeight(item, tile, occupiedTiles)); } if (item.getZ() > Room.MAXIMUM_FURNI_HEIGHT) { @@ -1845,10 +1931,9 @@ public class RoomItemManager { pluginHelper = event.hasPluginHelper(); } - boolean magicTile = item instanceof InteractionStackHelper || item instanceof InteractionTileWalkMagic; + boolean magicTile = this.isStackPlacementBypassItem(item); - java.util.Optional stackHelper = this.getItemsAt(tile).stream() - .filter(i -> i instanceof InteractionStackHelper).findAny(); + HabboItem stackHelper = this.findStackHeightHelperAt(tile, item); // Check if can be placed at new position THashSet occupiedTiles = layout.getTilesAt(tile, item.getBaseItem().getWidth(), @@ -1858,7 +1943,7 @@ public class RoomItemManager { HabboItem topItem = this.getTopItemAt(occupiedTiles, null); - if (!stackHelper.isPresent() && !pluginHelper) { + if (stackHelper == null && !pluginHelper) { if (oldLocation != tile) { for (RoomTile t : occupiedTiles) { HabboItem tileTopItem = this.getTopItemAt(t.x, t.y); @@ -1915,7 +2000,7 @@ public class RoomItemManager { } } - if ((!stackHelper.isPresent() && topItem != null && topItem != item && !topItem.getBaseItem() + if ((stackHelper == null && topItem != null && topItem != item && !topItem.getBaseItem() .allowStack()) || (topItem != null && topItem != item && topItem.getZ() + Item.getCurrentHeight(topItem) + Item.getCurrentHeight(item) > Room.MAXIMUM_FURNI_HEIGHT)) { @@ -1927,9 +2012,10 @@ public class RoomItemManager { // Place at new position double height; - if (stackHelper.isPresent()) { - height = stackHelper.get().getExtradata().isEmpty() ? Double.parseDouble("0.0") - : (Double.parseDouble(stackHelper.get().getExtradata()) / 100); + if (stackHelper != null) { + height = stackHelper.getZ(); + } else if (item instanceof InteractionStackWalkHelper) { + height = this.resolveStackWalkHelperHeight(item, tile, occupiedTiles); } else if (item == topItem) { height = item.getZ(); } else if (magicTile) { @@ -1980,7 +2066,7 @@ public class RoomItemManager { item.setX(tile.x); item.setY(tile.y); item.setZ(height); - if (magicTile) { + if (this.shouldPinStackHelperToFloor(item)) { item.setZ(tile.z); item.setExtradata("" + item.getZ() * 100); } @@ -2054,10 +2140,9 @@ public class RoomItemManager { pluginHelper = event.hasPluginHelper(); } - boolean magicTile = item instanceof InteractionStackHelper || item instanceof InteractionTileWalkMagic; + boolean magicTile = this.isStackPlacementBypassItem(item); - java.util.Optional stackHelper = this.getItemsAt(tile).stream() - .filter(i -> i instanceof InteractionStackHelper).findAny(); + HabboItem stackHelper = this.findStackHeightHelperAt(tile, item); THashSet occupiedTiles = layout.getTilesAt(tile, item.getBaseItem().getWidth(), item.getBaseItem().getLength(), rotation); @@ -2066,7 +2151,7 @@ public class RoomItemManager { HabboItem topItem = this.getTopPhysicsItemAt(occupiedTiles, null, physics); - if (!stackHelper.isPresent() && !pluginHelper) { + if (stackHelper == null && !pluginHelper) { if (oldLocation != tile) { for (RoomTile t : occupiedTiles) { HabboItem tileTopItem = this.getTopPhysicsItemAt(t.x, t.y, item, physics); @@ -2118,7 +2203,7 @@ public class RoomItemManager { } } - if ((!stackHelper.isPresent() && topItem != null && topItem != item && !topItem.getBaseItem() + if ((stackHelper == null && topItem != null && topItem != item && !topItem.getBaseItem() .allowStack()) || (topItem != null && topItem != item && topItem.getZ() + Item.getCurrentHeight(topItem) + Item.getCurrentHeight(item) > Room.MAXIMUM_FURNI_HEIGHT)) { @@ -2129,9 +2214,10 @@ public class RoomItemManager { double height; - if (stackHelper.isPresent()) { - height = stackHelper.get().getExtradata().isEmpty() ? Double.parseDouble("0.0") - : (Double.parseDouble(stackHelper.get().getExtradata()) / 100); + if (stackHelper != null) { + height = stackHelper.getZ(); + } else if (item instanceof InteractionStackWalkHelper) { + height = this.resolveStackWalkHelperHeight(item, tile, occupiedTiles); } else if (item == topItem) { height = item.getZ(); } else if (magicTile) { @@ -2182,7 +2268,7 @@ public class RoomItemManager { item.setX(tile.x); item.setY(tile.y); item.setZ(height); - if (magicTile) { + if (this.shouldPinStackHelperToFloor(item)) { item.setZ(tile.z); item.setExtradata("" + item.getZ() * 100); } @@ -2237,7 +2323,7 @@ public class RoomItemManager { * Slides furniture to a new position. */ public FurnitureMovementError slideFurniTo(HabboItem item, RoomTile tile, int rotation) { - boolean magicTile = item instanceof InteractionStackHelper; + boolean magicTile = this.isStackPlacementBypassItem(item); RoomLayout layout = this.room.getLayout(); @@ -2257,9 +2343,11 @@ public class RoomItemManager { item.setRotation(rotation); // Place at new position - if (magicTile) { + if (this.shouldPinStackHelperToFloor(item)) { item.setZ(tile.z); item.setExtradata("" + item.getZ() * 100); + } else if (item instanceof InteractionStackWalkHelper) { + item.setZ(this.resolveStackWalkHelperHeight(item, tile, occupiedTiles)); } if (item.getZ() > Room.MAXIMUM_FURNI_HEIGHT) { item.setZ(Room.MAXIMUM_FURNI_HEIGHT); @@ -2410,12 +2498,17 @@ public class RoomItemManager { return height; } + double helperHeight = Double.NEGATIVE_INFINITY; for (HabboItem item : this.getPhysicsItemsAt(tile, exclude, physics)) { - if (item instanceof InteractionStackHelper || item instanceof InteractionTileWalkMagic) { - return item.getZ(); + if (item instanceof InteractionStackHelper || item instanceof InteractionTileWalkMagic || item instanceof InteractionStackWalkHelper) { + helperHeight = Math.max(helperHeight, item.getZ()); } } + if (helperHeight != Double.NEGATIVE_INFINITY) { + return helperHeight; + } + HabboItem topItem = this.getTopPhysicsItemAt(x, y, exclude, physics); if (topItem != null) { return topItem.getZ() + (topItem.getBaseItem().allowSit() ? 0 : Item.getCurrentHeight(topItem)); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java index 08d9ccca..fd25c1e7 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java @@ -34,6 +34,8 @@ import com.eu.habbo.messages.outgoing.polls.PollStartComposer; import com.eu.habbo.messages.outgoing.polls.infobus.SimplePollAnswersComposer; import com.eu.habbo.messages.outgoing.polls.infobus.SimplePollStartComposer; import com.eu.habbo.messages.outgoing.rooms.*; +import com.eu.habbo.messages.outgoing.rooms.items.ConfInvisStateComposer; +import com.eu.habbo.messages.outgoing.rooms.items.HanditemBlockStateComposer; import com.eu.habbo.messages.outgoing.rooms.items.RoomFloorItemsComposer; import com.eu.habbo.messages.outgoing.rooms.items.RoomWallItemsComposer; import com.eu.habbo.messages.outgoing.rooms.pets.RoomPetComposer; @@ -886,6 +888,10 @@ public class RoomManager { floorItems.clear(); } + habbo.getClient().sendResponse(new ConfInvisStateComposer(room).compose()); + RoomAreaHideSupport.sendState(room, habbo.getClient()); + habbo.getClient().sendResponse(new HanditemBlockStateComposer(room).compose()); + if (!room.getCurrentPets().isEmpty()) { habbo.getClient().sendResponse(new RoomPetComposer(room.getCurrentPets())); for (Pet pet : room.getCurrentPets().valueCollection()) { diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomQueueSpeedControlSupport.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomQueueSpeedControlSupport.java new file mode 100644 index 00000000..18019c9f --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomQueueSpeedControlSupport.java @@ -0,0 +1,77 @@ +package com.eu.habbo.habbohotel.rooms; + +import com.eu.habbo.habbohotel.items.interactions.InteractionQueueSpeedControl; +import com.eu.habbo.habbohotel.items.interactions.InteractionRoller; +import com.eu.habbo.habbohotel.users.HabboItem; + +public final class RoomQueueSpeedControlSupport { + private static final String CONTROLLER_INTERACTION = "wf_conf_queue_speed"; + + private RoomQueueSpeedControlSupport() { + } + + public static Integer getEffectiveRollerSpeed(Room room) { + HabboItem controller = getControllerItem(room); + return controller != null ? InteractionQueueSpeedControl.toRollerSpeed(controller.getExtradata()) : null; + } + + public static int getEffectiveRollerIntervalMs(Room room) { + Integer effectiveRollerSpeed = getEffectiveRollerSpeed(room); + + if (effectiveRollerSpeed != null) { + return toRollerIntervalMs(effectiveRollerSpeed); + } + + if (room == null) { + return InteractionRoller.DELAY; + } + + return toRollerIntervalMs(room.getRollerSpeed()); + } + + private static int toRollerIntervalMs(int rollerSpeed) { + if (rollerSpeed < 0) { + return InteractionRoller.DELAY; + } + + return (rollerSpeed + 1) * 500; + } + + private static boolean isControllerItem(HabboItem item) { + if (item == null || item.getBaseItem() == null) { + return false; + } + + if (item instanceof InteractionQueueSpeedControl) { + return true; + } + + if (item.getBaseItem().getInteractionType() == null) { + return false; + } + + String interactionName = item.getBaseItem().getInteractionType().getName(); + + return interactionName != null && interactionName.equalsIgnoreCase(CONTROLLER_INTERACTION); + } + + private static HabboItem getControllerItem(Room room) { + if (room == null) { + return null; + } + + for (HabboItem item : room.getFloorItems()) { + if (!isControllerItem(item)) { + continue; + } + + if (item instanceof InteractionQueueSpeedControl) { + ((InteractionQueueSpeedControl) item).ensureAnimationLoop(room); + } + + return item; + } + + return null; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomRollerManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomRollerManager.java index 9d564ece..318e6f78 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomRollerManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomRollerManager.java @@ -354,7 +354,7 @@ public class RoomRollerManager { LOGGER.error("Caught exception", e); } } - }, this.room.getRollerSpeed() == 0 ? 250 : InteractionRoller.DELAY); + }, RoomQueueSpeedControlSupport.getEffectiveRollerIntervalMs(this.room)); } } diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomTileManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomTileManager.java index c87be418..e585b675 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomTileManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomTileManager.java @@ -4,6 +4,7 @@ import com.eu.habbo.Emulator; import com.eu.habbo.habbohotel.bots.Bot; import com.eu.habbo.habbohotel.items.Item; import com.eu.habbo.habbohotel.items.interactions.InteractionStackHelper; +import com.eu.habbo.habbohotel.items.interactions.InteractionStackWalkHelper; import com.eu.habbo.habbohotel.items.interactions.InteractionTileWalkMagic; import com.eu.habbo.habbohotel.users.HabboItem; import com.eu.habbo.plugin.events.furniture.FurnitureStackHeightEvent; @@ -149,7 +150,7 @@ public class RoomTileManager { result = overriddenState; } - if (this.room.getItemManager().getItemsAt(tile).stream().anyMatch(i -> i instanceof InteractionTileWalkMagic)) { + if (this.room.getItemManager().getItemsAt(tile).stream().anyMatch(i -> i instanceof InteractionTileWalkMagic || i instanceof InteractionStackWalkHelper)) { result = RoomTileState.OPEN; } @@ -211,14 +212,20 @@ public class RoomTileManager { boolean canStack = true; THashSet stackHelpers = this.room.getItemManager().getItemsAt(InteractionStackHelper.class, x, y); + stackHelpers.addAll(this.room.getItemManager().getItemsAt(InteractionStackWalkHelper.class, x, y)); stackHelpers.addAll(this.room.getItemManager().getItemsAt(InteractionTileWalkMagic.class, x, y)); if (stackHelpers.size() > 0) { + double helperHeight = Double.NEGATIVE_INFINITY; for (HabboItem item : stackHelpers) { if (item == exclude) { continue; } - return calculateHeightmap ? item.getZ() * 256.0D : item.getZ(); + helperHeight = Math.max(helperHeight, item.getZ()); + } + + if (helperHeight != Double.NEGATIVE_INFINITY) { + return calculateHeightmap ? helperHeight * 256.0D : helperHeight; } } @@ -425,6 +432,10 @@ public class RoomTileManager { HabboItem topItem = null; boolean canWalk = true; THashSet items = this.room.getItemManager().getItemsAt(roomTile); + if (items != null && items.stream().anyMatch(item -> item instanceof InteractionTileWalkMagic || item instanceof InteractionStackWalkHelper)) { + return true; + } + if (items != null) { for (HabboItem item : items) { if (topItem == null) { diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomUnit.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomUnit.java index bda55501..983ef85b 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomUnit.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomUnit.java @@ -4,6 +4,7 @@ import com.eu.habbo.Emulator; import com.eu.habbo.habbohotel.bots.Bot; import com.eu.habbo.habbohotel.items.Item; import com.eu.habbo.habbohotel.items.interactions.InteractionTileWalkMagic; +import com.eu.habbo.habbohotel.items.interactions.InteractionStackWalkHelper; import com.eu.habbo.habbohotel.items.interactions.InteractionWater; import com.eu.habbo.habbohotel.items.interactions.InteractionWaterItem; import com.eu.habbo.habbohotel.items.interactions.interfaces.ConditionalGate; @@ -325,7 +326,7 @@ public class RoomUnit { } Optional stackHelper = room.getItemsAt(next).stream() - .filter(i -> i instanceof InteractionTileWalkMagic).findAny(); + .filter(i -> i instanceof InteractionTileWalkMagic || i instanceof InteractionStackWalkHelper).findAny(); if (stackHelper.isPresent()) { zHeight = stackHelper.get().getZ(); } diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomWiredDisableSupport.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomWiredDisableSupport.java new file mode 100644 index 00000000..9aa33f59 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomWiredDisableSupport.java @@ -0,0 +1,47 @@ +package com.eu.habbo.habbohotel.rooms; + +import com.eu.habbo.habbohotel.items.interactions.InteractionWiredDisableControl; +import com.eu.habbo.habbohotel.users.HabboItem; + +public final class RoomWiredDisableSupport { + private static final String CONTROLLER_INTERACTION = "wf_conf_wired_disable"; + + private RoomWiredDisableSupport() { + } + + public static boolean isWiredDisabled(Room room) { + if (room == null) { + return false; + } + + for (HabboItem item : room.getFloorItems()) { + if (isActiveController(item)) { + return true; + } + } + + return false; + } + + public static boolean isActiveController(HabboItem item) { + return isControllerItem(item) && "1".equals(item.getExtradata()); + } + + public static boolean isControllerItem(HabboItem item) { + if (item == null || item.getBaseItem() == null) { + return false; + } + + if (item instanceof InteractionWiredDisableControl) { + return true; + } + + if (item.getBaseItem().getInteractionType() == null) { + return false; + } + + String interactionName = item.getBaseItem().getInteractionType().getName(); + + return interactionName != null && interactionName.equalsIgnoreCase(CONTROLLER_INTERACTION); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredHandler.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredHandler.java index 5e81da8d..a0451992 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredHandler.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredHandler.java @@ -16,6 +16,7 @@ import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraOrEval; import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraRandom; import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraUnseen; import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomWiredDisableSupport; import com.eu.habbo.habbohotel.rooms.RoomTile; import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.habbohotel.users.Habbo; @@ -71,6 +72,9 @@ public class WiredHandler { if (room == null) return false; + if (RoomWiredDisableSupport.isWiredDisabled(room)) + return false; + if (!room.isLoaded()) return false; @@ -118,6 +122,9 @@ public class WiredHandler { if (room == null) return false; + if (RoomWiredDisableSupport.isWiredDisabled(room)) + return false; + if (!room.isLoaded()) return false; @@ -160,6 +167,9 @@ public class WiredHandler { long millis = System.currentTimeMillis(); LegacyExecutionPlan executionPlan = new LegacyExecutionPlan(); + if (RoomWiredDisableSupport.isWiredDisabled(room)) + return false; + if(handle(trigger, roomUnit, room, stuff, executionPlan)) { triggerEffects(executionPlan.effects, roomUnit, room, stuff, millis, executionPlan.executeInOrder); return true; diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/core/WiredManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/core/WiredManager.java index 82456ac9..9d264065 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/core/WiredManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/core/WiredManager.java @@ -10,6 +10,7 @@ import com.eu.habbo.habbohotel.items.interactions.wired.effects.WiredEffectTrigg import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraExecutionLimit; import com.eu.habbo.habbohotel.items.interactions.wired.triggers.WiredTriggerHabboClicksUser; import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomWiredDisableSupport; import com.eu.habbo.habbohotel.rooms.RoomTile; import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.habbohotel.users.Habbo; @@ -231,6 +232,10 @@ public final class WiredManager { if (!isEnabled() || engine == null) { return false; } + + if (event == null || RoomWiredDisableSupport.isWiredDisabled(event.getRoom())) { + return false; + } return engine.handleEvent(event); } @@ -348,6 +353,10 @@ public final class WiredManager { return false; } + if (RoomWiredDisableSupport.isWiredDisabled(room)) { + return false; + } + WiredEvent event = WiredEvents.userSays(room, user, message, chatType, chatStyle); return engine.shouldSuppressUserSaysOutput(event); } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/items/RoomPlaceItemEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/items/RoomPlaceItemEvent.java index 0f293184..88d62d20 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/items/RoomPlaceItemEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/items/RoomPlaceItemEvent.java @@ -77,6 +77,7 @@ public class RoomPlaceItemEvent extends MessageHandler { if ((rentSpace != null || buildArea != null) && !room.hasRights(this.client.getHabbo())) { if (item instanceof InteractionRoller || item instanceof InteractionStackHelper || + item instanceof InteractionStackWalkHelper || item instanceof InteractionWired || item instanceof InteractionBackgroundToner || item instanceof InteractionRoomAds || diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/items/SetStackHelperHeightEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/items/SetStackHelperHeightEvent.java index edc29cc2..c3b1d337 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/items/SetStackHelperHeightEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/items/SetStackHelperHeightEvent.java @@ -1,6 +1,7 @@ package com.eu.habbo.messages.incoming.rooms.items; import com.eu.habbo.habbohotel.items.interactions.InteractionStackHelper; +import com.eu.habbo.habbohotel.items.interactions.InteractionStackWalkHelper; import com.eu.habbo.habbohotel.items.interactions.InteractionTileWalkMagic; import com.eu.habbo.habbohotel.rooms.Room; import com.eu.habbo.habbohotel.rooms.RoomTile; @@ -21,7 +22,7 @@ public class SetStackHelperHeightEvent extends MessageHandler { if (this.client.getHabbo().getHabboInfo().getId() == this.client.getHabbo().getHabboInfo().getCurrentRoom().getOwnerId() || this.client.getHabbo().getHabboInfo().getCurrentRoom().hasRights(this.client.getHabbo())) { HabboItem item = this.client.getHabbo().getHabboInfo().getCurrentRoom().getHabboItem(itemId); - if (item instanceof InteractionStackHelper || item instanceof InteractionTileWalkMagic) { + if (item instanceof InteractionStackHelper || item instanceof InteractionTileWalkMagic || item instanceof InteractionStackWalkHelper) { Room room = this.client.getHabbo().getHabboInfo().getCurrentRoom(); RoomTile itemTile = room.getLayout().getTile(item.getX(), item.getY()); double stackerHeight = this.packet.readInt(); @@ -51,7 +52,7 @@ public class SetStackHelperHeightEvent extends MessageHandler { item.setExtradata((int) (height * 100) + ""); item.needsUpdate(true); - if (item instanceof InteractionTileWalkMagic) { + if (item instanceof InteractionTileWalkMagic || item instanceof InteractionStackWalkHelper) { for (RoomTile t : tiles) { this.client.getHabbo().getHabboInfo().getCurrentRoom().updateHabbosAt(t.x, t.y); this.client.getHabbo().getHabboInfo().getCurrentRoom().updateBotsAt(t.x, t.y); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserGiveHandItemEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserGiveHandItemEvent.java index 9342e045..dd6333f7 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserGiveHandItemEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/users/RoomUserGiveHandItemEvent.java @@ -2,6 +2,7 @@ package com.eu.habbo.messages.incoming.rooms.users; import com.eu.habbo.Emulator; import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomHanditemBlockSupport; import com.eu.habbo.habbohotel.users.Habbo; import com.eu.habbo.messages.incoming.MessageHandler; import com.eu.habbo.threading.runnables.HabboGiveHandItemToHabbo; @@ -18,6 +19,10 @@ public class RoomUserGiveHandItemEvent extends MessageHandler { Room room = this.client.getHabbo().getHabboInfo().getCurrentRoom(); if (room != null) { + if (RoomHanditemBlockSupport.isHanditemBlocked(room)) { + return; + } + Habbo target = room.getHabbo(userId); if (target != null) { diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java index 3abf3fbc..36ef55a3 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java @@ -123,6 +123,8 @@ public class Outgoing { public final static int WiredMonitorDataComposer = 5101; // CUSTOM public final static int WiredRoomSettingsDataComposer = 5102; // CUSTOM public final static int WiredUserVariablesDataComposer = 5103; // CUSTOM + public final static int ConfInvisStateComposer = 5104; // CUSTOM + public final static int AreaHideComposer = 6001; // CUSTOM public final static int RoomPaintComposer = 2454; // PRODUCTION-201611291003-338511768 public final static int MarketplaceConfigComposer = 1823; // PRODUCTION-201611291003-338511768 public final static int AddBotComposer = 1352; // PRODUCTION-201611291003-338511768 @@ -328,6 +330,7 @@ public class Outgoing { public final static int VerifyMobilePhoneCodeWindowComposer = 800; // PRODUCTION-201611291003-338511768 public final static int VerifyMobilePhoneDoneComposer = 91; // PRODUCTION-201611291003-338511768 public final static int RoomUserReceivedHandItemComposer = 354; // PRODUCTION-201611291003-338511768 + public final static int HanditemBlockStateComposer = 5105; public final static int MutedWhisperComposer = 826; // PRODUCTION-201611291003-338511768 public final static int UnknownHintComposer = 1787; // PRODUCTION-201611291003-338511768 public final static int BullyReportClosedComposer = 2674; // PRODUCTION-201611291003-338511768 diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/AddFloorItemComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/AddFloorItemComposer.java index dde6076a..94c29a61 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/AddFloorItemComposer.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/AddFloorItemComposer.java @@ -19,7 +19,13 @@ public class AddFloorItemComposer extends MessageComposer { protected ServerMessage composeInternal() { this.response.init(Outgoing.AddFloorItemComposer); this.item.serializeFloorData(this.response); - this.response.appendInt(this.item instanceof InteractionGift ? ((((InteractionGift) this.item).getColorId() * 1000) + ((InteractionGift) this.item).getRibbonId()) : (this.item instanceof InteractionMusicDisc ? ((InteractionMusicDisc) this.item).getSongId() : 1)); + this.response.appendInt( + this.item instanceof InteractionGift + ? ((((InteractionGift) this.item).getColorId() * 1000) + ((InteractionGift) this.item).getRibbonId()) + : (this.item instanceof InteractionMusicDisc + ? ((InteractionMusicDisc) this.item).getSongId() + : (this.item instanceof InteractionStackWalkHelper ? 2147483001 : 1)) + ); this.item.serializeExtradata(this.response); this.response.appendInt(-1); this.response.appendInt(this.item instanceof InteractionTeleport || this.item instanceof InteractionSwitch || this.item instanceof InteractionSwitchRemoteControl || this.item instanceof InteractionVendingMachine || this.item instanceof InteractionInformationTerminal || this.item instanceof InteractionPostIt|| this.item instanceof InteractionPuzzleBox ? 2 : this.item.isUsable() ? 1 : 0); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/AreaHideComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/AreaHideComposer.java new file mode 100644 index 00000000..c7e48e55 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/AreaHideComposer.java @@ -0,0 +1,30 @@ +package com.eu.habbo.messages.outgoing.rooms.items; + +import com.eu.habbo.habbohotel.rooms.RoomAreaHideSupport; +import com.eu.habbo.habbohotel.users.HabboItem; +import com.eu.habbo.messages.ServerMessage; +import com.eu.habbo.messages.outgoing.MessageComposer; +import com.eu.habbo.messages.outgoing.Outgoing; + +public class AreaHideComposer extends MessageComposer { + private final HabboItem item; + + public AreaHideComposer(HabboItem item) { + this.item = item; + } + + @Override + protected ServerMessage composeInternal() { + this.response.init(Outgoing.AreaHideComposer); + this.response.appendInt(this.item.getId()); + this.response.appendBoolean(RoomAreaHideSupport.isControllerActive(this.item)); + this.response.appendInt(RoomAreaHideSupport.getRootX(this.item)); + this.response.appendInt(RoomAreaHideSupport.getRootY(this.item)); + this.response.appendInt(RoomAreaHideSupport.getWidth(this.item)); + this.response.appendInt(RoomAreaHideSupport.getLength(this.item)); + this.response.appendBoolean(RoomAreaHideSupport.isInverted(this.item)); + this.response.appendBoolean(RoomAreaHideSupport.includesWallItems(this.item)); + this.response.appendBoolean(RoomAreaHideSupport.isInvisibilityEnabled(this.item)); + return this.response; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/ConfInvisStateComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/ConfInvisStateComposer.java new file mode 100644 index 00000000..21ef034b --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/ConfInvisStateComposer.java @@ -0,0 +1,34 @@ +package com.eu.habbo.messages.outgoing.rooms.items; + +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomConfInvisSupport; +import com.eu.habbo.messages.ServerMessage; +import com.eu.habbo.messages.outgoing.MessageComposer; +import com.eu.habbo.messages.outgoing.Outgoing; +import gnu.trove.list.array.TIntArrayList; + +public class ConfInvisStateComposer extends MessageComposer { + private final int roomId; + private final boolean active; + private final TIntArrayList hiddenItemIds; + + public ConfInvisStateComposer(Room room) { + this.roomId = (room != null) ? room.getId() : 0; + this.active = RoomConfInvisSupport.hasActiveController(room); + this.hiddenItemIds = RoomConfInvisSupport.collectHiddenFloorItemIds(room); + } + + @Override + protected ServerMessage composeInternal() { + this.response.init(Outgoing.ConfInvisStateComposer); + this.response.appendInt(this.roomId); + this.response.appendBoolean(this.active); + this.response.appendInt(this.hiddenItemIds.size()); + + for (int i = 0; i < this.hiddenItemIds.size(); i++) { + this.response.appendInt(this.hiddenItemIds.get(i)); + } + + return this.response; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/FloorItemUpdateComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/FloorItemUpdateComposer.java index 77b292ea..88b4dd64 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/FloorItemUpdateComposer.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/FloorItemUpdateComposer.java @@ -2,6 +2,7 @@ package com.eu.habbo.messages.outgoing.rooms.items; import com.eu.habbo.habbohotel.items.interactions.InteractionGift; import com.eu.habbo.habbohotel.items.interactions.InteractionMusicDisc; +import com.eu.habbo.habbohotel.items.interactions.InteractionStackWalkHelper; import com.eu.habbo.habbohotel.users.HabboItem; import com.eu.habbo.messages.ServerMessage; import com.eu.habbo.messages.outgoing.MessageComposer; @@ -18,7 +19,13 @@ public class FloorItemUpdateComposer extends MessageComposer { protected ServerMessage composeInternal() { this.response.init(Outgoing.FloorItemUpdateComposer); this.item.serializeFloorData(this.response); - this.response.appendInt(this.item instanceof InteractionGift ? ((((InteractionGift) this.item).getColorId() * 1000) + ((InteractionGift) this.item).getRibbonId()) : (this.item instanceof InteractionMusicDisc ? ((InteractionMusicDisc) this.item).getSongId() : item.isUsable() ? 0 : 0)); + this.response.appendInt( + this.item instanceof InteractionGift + ? ((((InteractionGift) this.item).getColorId() * 1000) + ((InteractionGift) this.item).getRibbonId()) + : (this.item instanceof InteractionMusicDisc + ? ((InteractionMusicDisc) this.item).getSongId() + : (this.item instanceof InteractionStackWalkHelper ? 2147483001 : 0)) + ); this.item.serializeExtradata(this.response); this.response.appendInt(-1); this.response.appendInt(0); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/HanditemBlockStateComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/HanditemBlockStateComposer.java new file mode 100644 index 00000000..80fa7dce --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/HanditemBlockStateComposer.java @@ -0,0 +1,25 @@ +package com.eu.habbo.messages.outgoing.rooms.items; + +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomHanditemBlockSupport; +import com.eu.habbo.messages.ServerMessage; +import com.eu.habbo.messages.outgoing.MessageComposer; +import com.eu.habbo.messages.outgoing.Outgoing; + +public class HanditemBlockStateComposer extends MessageComposer { + private final int roomId; + private final boolean blocked; + + public HanditemBlockStateComposer(Room room) { + this.roomId = (room != null) ? room.getId() : 0; + this.blocked = RoomHanditemBlockSupport.isHanditemBlocked(room); + } + + @Override + protected ServerMessage composeInternal() { + this.response.init(Outgoing.HanditemBlockStateComposer); + this.response.appendInt(this.roomId); + this.response.appendBoolean(this.blocked); + return this.response; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/RoomFloorItemsComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/RoomFloorItemsComposer.java index 162935ab..2045879c 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/RoomFloorItemsComposer.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/items/RoomFloorItemsComposer.java @@ -41,7 +41,13 @@ public class RoomFloorItemsComposer extends MessageComposer { for (HabboItem item : this.items) { item.serializeFloorData(this.response); - this.response.appendInt(item instanceof InteractionGift ? ((((InteractionGift) item).getColorId() * 1000) + ((InteractionGift) item).getRibbonId()) : (item instanceof InteractionMusicDisc ? ((InteractionMusicDisc) item).getSongId() : 1)); + this.response.appendInt( + item instanceof InteractionGift + ? ((((InteractionGift) item).getColorId() * 1000) + ((InteractionGift) item).getRibbonId()) + : (item instanceof InteractionMusicDisc + ? ((InteractionMusicDisc) item).getSongId() + : (item instanceof InteractionStackWalkHelper ? 2147483001 : 1)) + ); item.serializeExtradata(this.response); this.response.appendInt(-1); this.response.appendInt(item instanceof InteractionTeleport || item instanceof InteractionSwitch || item instanceof InteractionSwitchRemoteControl || item instanceof InteractionVendingMachine || item instanceof InteractionInformationTerminal || item instanceof InteractionPostIt || item instanceof InteractionPuzzleBox ? 2 : item.isUsable() ? 1 : 0); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/users/RoomUnitOnRollerComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/users/RoomUnitOnRollerComposer.java index 0628a478..4a356e7a 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/users/RoomUnitOnRollerComposer.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/users/RoomUnitOnRollerComposer.java @@ -6,6 +6,7 @@ import com.eu.habbo.habbohotel.items.interactions.InteractionRoller; import com.eu.habbo.habbohotel.pets.Pet; import com.eu.habbo.habbohotel.pets.RideablePet; import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomQueueSpeedControlSupport; import com.eu.habbo.habbohotel.rooms.RoomTile; import com.eu.habbo.habbohotel.rooms.RoomUnit; import com.eu.habbo.habbohotel.rooms.RoomUnitType; @@ -157,7 +158,7 @@ public class RoomUnitOnRollerComposer extends MessageComposer { } } } - }, this.room.getRollerSpeed() == 0 ? 250 : InteractionRoller.DELAY); + }, RoomQueueSpeedControlSupport.getEffectiveRollerIntervalMs(this.room)); /* RoomTile rollerTile = room.getLayout().getTile(this.roller.getX(), this.roller.getY()); Emulator.getThreading().run(() -> { @@ -177,7 +178,7 @@ public class RoomUnitOnRollerComposer extends MessageComposer { } } } - }, this.room.getRollerSpeed() == 0 ? 250 : InteractionRoller.DELAY); + }, RoomQueueSpeedControlSupport.getEffectiveRollerIntervalMs(this.room)); */ } else { this.roomUnit.setLocation(this.newLocation); diff --git a/Emulator/src/main/java/com/eu/habbo/threading/runnables/HabboGiveHandItemToHabbo.java b/Emulator/src/main/java/com/eu/habbo/threading/runnables/HabboGiveHandItemToHabbo.java index 16a59ec5..a3cf6470 100644 --- a/Emulator/src/main/java/com/eu/habbo/threading/runnables/HabboGiveHandItemToHabbo.java +++ b/Emulator/src/main/java/com/eu/habbo/threading/runnables/HabboGiveHandItemToHabbo.java @@ -1,6 +1,8 @@ package com.eu.habbo.threading.runnables; import com.eu.habbo.habbohotel.users.Habbo; +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.rooms.RoomHanditemBlockSupport; import com.eu.habbo.messages.outgoing.rooms.users.RoomUserHandItemComposer; import com.eu.habbo.messages.outgoing.rooms.users.RoomUserReceivedHandItemComposer; @@ -21,6 +23,12 @@ public class HabboGiveHandItemToHabbo implements Runnable { if (this.from.getHabboInfo().getCurrentRoom() != this.target.getHabboInfo().getCurrentRoom()) return; + Room room = this.from.getHabboInfo().getCurrentRoom(); + + if (RoomHanditemBlockSupport.isHanditemBlocked(room)) { + return; + } + int itemId = this.from.getRoomUnit().getHandItem(); if (itemId > 0) {