Merge pull request #37 from duckietm/dev

Dev
This commit is contained in:
DuckieTM
2026-03-22 21:37:28 +01:00
committed by GitHub
37 changed files with 3015 additions and 171 deletions
+1 -1
View File
@@ -8,5 +8,5 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_23" default="true" project-jdk-name="openjdk-23" project-jdk-type="JavaSDK" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="graalvm-jdk-21" project-jdk-type="JavaSDK" />
</project>
@@ -56,6 +56,8 @@ public final class Emulator {
public static String build = "";
public static long buildTimestamp = -1L;
public static boolean isReady = false;
public static boolean isShuttingDown = false;
public static boolean stopped = false;
@@ -50,8 +50,12 @@ import com.eu.habbo.habbohotel.items.interactions.totems.InteractionTotemPlanet;
import com.eu.habbo.habbohotel.items.interactions.wired.conditions.*;
import com.eu.habbo.habbohotel.items.interactions.wired.effects.*;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredBlob;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraAnimationTime;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterFurni;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterUser;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMoveCarryUsers;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMovePhysics;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMoveNoAnimation;
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;
@@ -341,6 +345,10 @@ public class ItemManager {
this.interactionsList.add(new ItemInteraction("wf_xtra_filter_furni", WiredExtraFilterFurni.class));
this.interactionsList.add(new ItemInteraction("wf_xtra_filter_user", WiredExtraFilterUser.class));
this.interactionsList.add(new ItemInteraction("wf_xtra_filter_users", WiredExtraFilterUser.class));
this.interactionsList.add(new ItemInteraction("wf_xtra_mov_carry_users", WiredExtraMoveCarryUsers.class));
this.interactionsList.add(new ItemInteraction("wf_xtra_mov_no_animation", WiredExtraMoveNoAnimation.class));
this.interactionsList.add(new ItemInteraction("wf_xtra_anim_time", WiredExtraAnimationTime.class));
this.interactionsList.add(new ItemInteraction("wf_xtra_mov_physics", WiredExtraMovePhysics.class));
this.interactionsList.add(new ItemInteraction("wf_highscore", InteractionWiredHighscore.class));
@@ -10,10 +10,10 @@ import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.*;
import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
import gnu.trove.map.hash.THashMap;
import gnu.trove.set.hash.THashSet;
@@ -22,6 +22,7 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
public static final int ACTION_WAIT = 0;
@@ -35,6 +36,7 @@ public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
public static final WiredEffectType type = WiredEffectType.MOVE_DIRECTION;
private final THashMap<HabboItem, WiredChangeDirectionSetting> items = new THashMap<>(0);
private final ConcurrentHashMap<Integer, WiredChangeDirectionSetting> runtimeItems = new ConcurrentHashMap<>();
private RoomUserRotation startRotation = RoomUserRotation.NORTH;
private int blockedAction = 0;
private int furniSource = WiredSourceUtil.SOURCE_TRIGGER;
@@ -57,6 +59,7 @@ public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
THashMap<HabboItem, WiredChangeDirectionSetting> effectiveItems;
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
this.runtimeItems.clear();
THashSet<HabboItem> toRemove = new THashSet<>();
for (HabboItem item : this.items.keySet()) {
if (item == null || Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId()).getHabboItem(item.getId()) == null)
@@ -67,10 +70,13 @@ public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
}
effectiveItems = this.items;
} else {
this.pruneRuntimeItems(room);
effectiveItems = new THashMap<>();
for (HabboItem item : resolvedItems) {
if (item != null) {
WiredChangeDirectionSetting setting = this.items.get(item);
WiredChangeDirectionSetting setting = this.runtimeItems.computeIfAbsent(
item.getId(),
key -> new WiredChangeDirectionSetting(item.getId(), item.getRotation(), this.startRotation));
if (setting == null) {
setting = new WiredChangeDirectionSetting(item.getId(), item.getRotation(), this.startRotation);
}
@@ -91,7 +97,7 @@ public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
RoomTile targetTile = room.getLayout().getTileInFront(itemTile, entry.getValue().direction.getValue());
int count = 1;
while (this.shouldSearchNextDirection(room, item, targetTile) && count < 8) {
while (this.shouldSearchNextDirection(room, item, targetTile, ctx) && count < 8) {
entry.getValue().direction = this.nextRotation(entry.getValue().direction);
RoomTile tile = room.getLayout().getTileInFront(itemTile, entry.getValue().direction.getValue());
@@ -115,35 +121,30 @@ public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
RoomTile targetTile = room.getLayout().getTileInFront(itemTile, newDirection);
if(item.getRotation() != entry.getValue().rotation) {
if(targetTile == null || room.furnitureFitsAt(targetTile, item, entry.getValue().rotation, false) != FurnitureMovementError.NONE)
if (targetTile == null || room.furnitureFitsAt(targetTile, item, entry.getValue().rotation, false) != FurnitureMovementError.NONE)
continue;
room.moveFurniTo(entry.getKey(), targetTile, entry.getValue().rotation, null, true);
WiredMoveCarryHelper.moveFurni(room, this, entry.getKey(), targetTile, entry.getValue().rotation, null, true, ctx);
}
if (targetTile == null) continue;
boolean hasRoomUnits = false;
THashSet<RoomTile> newOccupiedTiles = room.getLayout().getTilesAt(targetTile, item.getBaseItem().getWidth(), item.getBaseItem().getLength(), item.getRotation());
for(RoomTile tile : newOccupiedTiles) {
for (RoomUnit _roomUnit : room.getRoomUnits(tile)) {
hasRoomUnits = true;
if(_roomUnit.getCurrentLocation() == targetTile) {
Emulator.getThreading().run(() -> {
WiredManager.triggerBotCollision(room, _roomUnit);
});
FurnitureMovementError movementError = WiredMoveCarryHelper.getMovementError(room, this, entry.getKey(), targetTile, item.getRotation(), ctx);
if (movementError == FurnitureMovementError.TILE_HAS_HABBOS
|| movementError == FurnitureMovementError.TILE_HAS_BOTS
|| movementError == FurnitureMovementError.TILE_HAS_PETS) {
Emulator.getThreading().run(() -> {
for (RoomUnit roomUnit : room.getRoomUnits(targetTile)) {
WiredManager.triggerBotCollision(room, roomUnit);
break;
}
}
});
}
if (targetTile.state != RoomTileState.INVALID && room.furnitureFitsAt(targetTile, item, item.getRotation(), false) == FurnitureMovementError.NONE) {
if (!hasRoomUnits) {
RoomTile oldLocation = room.getLayout().getTile(entry.getKey().getX(), entry.getKey().getY());
double oldZ = entry.getKey().getZ();
if(oldLocation != null && room.moveFurniTo(entry.getKey(), targetTile, item.getRotation(), null, false) == FurnitureMovementError.NONE) {
room.sendComposer(new FloorItemOnRollerComposer(entry.getKey(), null, oldLocation, oldZ, targetTile, entry.getKey().getZ(), 0, room).compose());
}
if (targetTile.state != RoomTileState.INVALID && movementError == FurnitureMovementError.NONE) {
RoomTile oldLocation = room.getLayout().getTile(entry.getKey().getX(), entry.getKey().getY());
if (oldLocation != null && WiredMoveCarryHelper.moveFurni(room, this, entry.getKey(), targetTile, item.getRotation(), null, false, ctx) == FurnitureMovementError.NONE) {
}
}
}
@@ -165,6 +166,7 @@ public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.items.clear();
this.runtimeItems.clear();
String wiredData = set.getString("wired_data");
@@ -228,6 +230,7 @@ public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
public void onPickUp() {
this.setDelay(0);
this.items.clear();
this.runtimeItems.clear();
this.blockedAction = 0;
this.startRotation = RoomUserRotation.NORTH;
this.furniSource = WiredSourceUtil.SOURCE_TRIGGER;
@@ -305,6 +308,7 @@ public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
throw new WiredSaveException("Delay too long");
this.items.clear();
this.runtimeItems.clear();
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
this.items.putAll(newItems);
}
@@ -315,7 +319,15 @@ public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
return true;
}
private boolean shouldSearchNextDirection(Room room, HabboItem item, RoomTile targetTile) {
private void pruneRuntimeItems(Room room) {
if (room == null || this.runtimeItems.isEmpty()) {
return;
}
this.runtimeItems.entrySet().removeIf(entry -> room.getHabboItem(entry.getKey()) == null);
}
private boolean shouldSearchNextDirection(Room room, HabboItem item, RoomTile targetTile, WiredContext ctx) {
if (targetTile == null || targetTile.state == RoomTileState.INVALID) {
return true;
}
@@ -328,7 +340,7 @@ public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
return false;
}
FurnitureMovementError unitCollision = room.furnitureFitsAt(targetTile, item, item.getRotation(), true);
FurnitureMovementError unitCollision = WiredMoveCarryHelper.getMovementError(room, this, item, targetTile, item.getRotation(), ctx);
return unitCollision == FurnitureMovementError.TILE_HAS_HABBOS;
}
@@ -12,10 +12,10 @@ import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.WiredEffectType;
import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -65,18 +65,14 @@ public class WiredEffectFurniToFurni extends InteractionWiredEffect {
return;
}
RoomTile oldLocation = room.getLayout().getTile(moveItem.getX(), moveItem.getY());
double oldZ = moveItem.getZ();
FurnitureMovementError error = room.moveFurniTo(moveItem, targetTile, moveItem.getRotation(), null, false, false);
FurnitureMovementError error = WiredMoveCarryHelper.moveFurni(room, this, moveItem, targetTile, moveItem.getRotation(), null, false, ctx);
if (error == FurnitureMovementError.NONE) {
this.sendRollerAnimation(room, moveItem, oldLocation, oldZ, targetTile);
return;
}
error = room.moveFurniTo(moveItem, targetTile, moveItem.getRotation(), targetItem.getZ(), null, false, false);
error = WiredMoveCarryHelper.moveFurni(room, this, moveItem, targetTile, moveItem.getRotation(), targetItem.getZ(), null, false, ctx);
if (error == FurnitureMovementError.NONE) {
this.sendRollerAnimation(room, moveItem, oldLocation, oldZ, targetTile);
return;
}
}
@@ -232,14 +228,6 @@ public class WiredEffectFurniToFurni extends InteractionWiredEffect {
return type;
}
private void sendRollerAnimation(Room room, HabboItem item, RoomTile oldLocation, double oldZ, RoomTile newLocation) {
if (room == null || item == null || oldLocation == null || newLocation == null) {
return;
}
room.sendComposer(new FloorItemOnRollerComposer(item, null, oldLocation, oldZ, newLocation, item.getZ(), 0, room).compose());
}
@Override
protected long requiredCooldown() {
return COOLDOWN_MOVEMENT;
@@ -8,7 +8,7 @@ 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.habbohotel.wired.core.WiredContext;
import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -39,19 +39,15 @@ public class WiredEffectFurniToUser extends WiredEffectUserFurniBase {
return;
}
RoomTile oldLocation = room.getLayout().getTile(item.getX(), item.getY());
double oldZ = item.getZ();
FurnitureMovementError error = room.moveFurniTo(item, targetTile, item.getRotation(), null, false, false);
FurnitureMovementError error = WiredMoveCarryHelper.moveFurni(room, this, item, targetTile, item.getRotation(), null, false, ctx);
if (error == FurnitureMovementError.NONE) {
this.sendRollerAnimation(room, item, oldLocation, oldZ, targetTile);
return;
}
if (item.getBaseItem().getStateCount() > 0) {
error = room.moveFurniTo(item, targetTile, item.getRotation(), item.getZ(), null, false, false);
error = WiredMoveCarryHelper.moveFurni(room, this, item, targetTile, item.getRotation(), item.getZ(), null, false, ctx);
if (error == FurnitureMovementError.NONE) {
this.sendRollerAnimation(room, item, oldLocation, oldZ, targetTile);
return;
}
}
}
@@ -67,11 +63,4 @@ public class WiredEffectFurniToUser extends WiredEffectUserFurniBase {
return type;
}
private void sendRollerAnimation(Room room, HabboItem item, RoomTile oldLocation, double oldZ, RoomTile newLocation) {
if (room == null || item == null || oldLocation == null || newLocation == null) {
return;
}
room.sendComposer(new FloorItemOnRollerComposer(item, null, oldLocation, oldZ, newLocation, item.getZ(), 0, room).compose());
}
}
@@ -12,10 +12,10 @@ import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.WiredEffectType;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.WiredMatchFurniSetting;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
import gnu.trove.set.hash.THashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -64,7 +64,7 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
for (WiredMatchFurniSetting setting : this.settings) {
HabboItem item = room.getHabboItem(setting.item_id);
if (item != null) {
this.applySetting(room, item, setting);
this.applySetting(room, item, setting, ctx);
}
}
@@ -82,7 +82,7 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
WiredMatchFurniSetting setting = this.resolveSettingForTarget(room, item);
if (setting == null) continue;
this.applySetting(room, item, setting);
this.applySetting(room, item, setting, ctx);
}
}
@@ -106,7 +106,7 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
return fallback;
}
private void applySetting(Room room, HabboItem item, WiredMatchFurniSetting setting) {
private void applySetting(Room room, HabboItem item, WiredMatchFurniSetting setting, WiredContext ctx) {
if (this.state && (this.checkForWiredResetPermission && item.allowWiredResetState())) {
if (!setting.state.equals(" ") && !item.getExtradata().equals(setting.state)) {
item.setExtradata(setting.state);
@@ -117,17 +117,16 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
RoomTile oldLocation = room.getLayout().getTile(item.getX(), item.getY());
if (oldLocation == null) return;
double oldZ = item.getZ();
if(this.direction && !this.position) {
if(item.getRotation() != setting.rotation && room.furnitureFitsAt(oldLocation, item, setting.rotation, false) == FurnitureMovementError.NONE) {
room.moveFurniTo(item, oldLocation, setting.rotation, null, true);
WiredMoveCarryHelper.moveFurni(room, this, item, oldLocation, setting.rotation, null, true, ctx);
}
}
else if(this.altitude && !this.position) {
int newRotation = this.direction ? setting.rotation : item.getRotation();
if(BigDecimal.valueOf(item.getZ()).compareTo(BigDecimal.valueOf(setting.z)) != 0 || newRotation != item.getRotation()) {
room.moveFurniTo(item, oldLocation, newRotation, setting.z, null, true, false);
WiredMoveCarryHelper.moveFurni(room, this, item, oldLocation, newRotation, setting.z, null, true, ctx);
}
}
else if(this.position) {
@@ -136,11 +135,10 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
int newRotation = this.direction ? setting.rotation : item.getRotation();
double newZ = this.altitude ? setting.z : item.getZ();
if(newLocation != null && newLocation.state != RoomTileState.INVALID && (newLocation != oldLocation || newRotation != item.getRotation()) && room.furnitureFitsAt(newLocation, item, newRotation, true) == FurnitureMovementError.NONE) {
if(room.moveFurniTo(item, newLocation, newRotation, newZ, null, !slideAnimation, true) == FurnitureMovementError.NONE) {
if(slideAnimation) {
room.sendComposer(new FloorItemOnRollerComposer(item, null, oldLocation, oldZ, newLocation, item.getZ(), 0, room).compose());
}
if (newLocation != null && newLocation.state != RoomTileState.INVALID
&& (newLocation != oldLocation || newRotation != item.getRotation())
&& WiredMoveCarryHelper.getMovementError(room, this, item, newLocation, newRotation, ctx) == FurnitureMovementError.NONE) {
if (WiredMoveCarryHelper.moveFurni(room, this, item, newLocation, newRotation, newZ, null, !slideAnimation, ctx) == FurnitureMovementError.NONE) {
}
}
}
@@ -10,11 +10,11 @@ import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.WiredEffectType;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredSimulation;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
import gnu.trove.set.hash.THashSet;
import java.sql.ResultSet;
@@ -98,11 +98,10 @@ public class WiredEffectMoveFurniAway extends InteractionWiredEffect {
RoomTile newLocation = room.getLayout().getTile((short) (item.getX() + x), (short) (item.getY() + y));
RoomTile oldLocation = room.getLayout().getTile(item.getX(), item.getY());
double oldZ = item.getZ();
if(newLocation != null && newLocation.state != RoomTileState.INVALID && newLocation != oldLocation && room.furnitureFitsAt(newLocation, item, item.getRotation(), true) == FurnitureMovementError.NONE) {
if(room.moveFurniTo(item, newLocation, item.getRotation(), null, false) == FurnitureMovementError.NONE) {
room.sendComposer(new FloorItemOnRollerComposer(item, null, oldLocation, oldZ, newLocation, item.getZ(), 0, room).compose());
if (newLocation != null && newLocation.state != RoomTileState.INVALID && newLocation != oldLocation
&& WiredMoveCarryHelper.getMovementError(room, this, item, newLocation, item.getRotation(), ctx) == FurnitureMovementError.NONE) {
if (WiredMoveCarryHelper.moveFurni(room, this, item, newLocation, item.getRotation(), null, false, ctx) == FurnitureMovementError.NONE) {
}
}
}
@@ -5,6 +5,7 @@ import com.eu.habbo.habbohotel.gameclients.GameClient;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.FurnitureMovementError;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomTile;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
@@ -12,13 +13,12 @@ import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.WiredEffectType;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredSimulation;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
import gnu.trove.set.hash.THashSet;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -112,11 +112,6 @@ public class WiredEffectMoveFurniTo extends InteractionWiredEffect {
RoomTile objectTile = room.getLayout().getTile(targetItem.getX(), targetItem.getY());
if (objectTile != null) {
RoomTile sourceTile = room.getLayout().getTile(((HabboItem) object).getX(), ((HabboItem) object).getY());
if (sourceTile == null) continue;
THashSet<RoomTile> refreshTiles = room.getLayout().getTilesAt(sourceTile, ((HabboItem) object).getBaseItem().getWidth(), ((HabboItem) object).getBaseItem().getLength(), ((HabboItem) object).getRotation());
RoomTile tile = room.getLayout().getTileInFront(objectTile, this.direction, indexOffset);
if (tile == null || !tile.getAllowStack()) {
indexOffset = 0;
@@ -127,13 +122,18 @@ public class WiredEffectMoveFurniTo extends InteractionWiredEffect {
continue;
}
room.sendComposer(new FloorItemOnRollerComposer((HabboItem) object, null, tile, tile.getStackHeight() - ((HabboItem) object).getZ(), room).compose());
RoomTile newSourceTile = room.getLayout().getTile(((HabboItem) object).getX(), ((HabboItem) object).getY());
if (newSourceTile != null) {
refreshTiles.addAll(room.getLayout().getTilesAt(newSourceTile, ((HabboItem) object).getBaseItem().getWidth(), ((HabboItem) object).getBaseItem().getLength(), ((HabboItem) object).getRotation()));
HabboItem movingItem = (HabboItem) object;
RoomTile oldLocation = room.getLayout().getTile(movingItem.getX(), movingItem.getY());
if (oldLocation == null) {
continue;
}
room.updateTiles(refreshTiles);
FurnitureMovementError movementError = WiredMoveCarryHelper.moveFurni(room, this, movingItem, tile, movingItem.getRotation(), null, false, ctx);
if (movementError != FurnitureMovementError.NONE) {
continue;
}
this.indexOffset.put(targetItem.getId(), indexOffset);
}
}
@@ -10,11 +10,11 @@ import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.WiredEffectType;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredSimulation;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
import com.eu.habbo.threading.runnables.WiredCollissionRunnable;
import gnu.trove.map.hash.THashMap;
import gnu.trove.set.hash.THashSet;
@@ -53,7 +53,7 @@ public class WiredEffectMoveFurniTowards extends InteractionWiredEffect {
this.lastDirections = new THashMap<>();
}
public List<RoomUserRotation> getAvailableDirections(HabboItem item, Room room) {
public List<RoomUserRotation> getAvailableDirections(HabboItem item, Room room, WiredContext ctx) {
List<RoomUserRotation> availableDirections = new ArrayList<>();
RoomLayout layout = room.getLayout();
@@ -73,7 +73,7 @@ public class WiredEffectMoveFurniTowards extends InteractionWiredEffect {
if (!layout.tileExists(tile.x, tile.y))
continue;
if (room.furnitureFitsAt(tile, item, item.getRotation()) == FurnitureMovementError.INVALID_MOVE)
if (WiredMoveCarryHelper.getMovementError(room, this, item, tile, item.getRotation(), ctx) != FurnitureMovementError.NONE)
continue;
HabboItem topItem = room.getTopItemAt(tile.x, tile.y);
@@ -192,7 +192,7 @@ public class WiredEffectMoveFurniTowards extends InteractionWiredEffect {
3+ available - move in random direction, but never the opposite
*/
List<RoomUserRotation> availableDirections = this.getAvailableDirections(item, room);
List<RoomUserRotation> availableDirections = this.getAvailableDirections(item, room, ctx);
if (moveDirection != null && !availableDirections.contains(moveDirection))
moveDirection = null;
@@ -228,13 +228,11 @@ public class WiredEffectMoveFurniTowards extends InteractionWiredEffect {
RoomTile newTile = room.getLayout().getTileInFront(oldLocation, moveDirection.getValue());
double oldZ = item.getZ();
if(newTile != null) {
lastDirections.put(item.getId(), moveDirection);
if(newTile.state != RoomTileState.INVALID && newTile != oldLocation && room.furnitureFitsAt(newTile, item, item.getRotation(), true) == FurnitureMovementError.NONE) {
if (room.moveFurniTo(item, newTile, item.getRotation(), null, false) == FurnitureMovementError.NONE) {
room.sendComposer(new FloorItemOnRollerComposer(item, null, oldLocation, oldZ, newTile, item.getZ(), 0, room).compose());
if (newTile.state != RoomTileState.INVALID && newTile != oldLocation
&& WiredMoveCarryHelper.getMovementError(room, this, item, newTile, item.getRotation(), ctx) == FurnitureMovementError.NONE) {
if (WiredMoveCarryHelper.moveFurni(room, this, item, newTile, item.getRotation(), null, false, ctx) == FurnitureMovementError.NONE) {
}
}
}
@@ -11,11 +11,11 @@ import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.WiredEffectType;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredSimulation;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
import gnu.trove.set.hash.THashSet;
import java.sql.ResultSet;
@@ -61,7 +61,6 @@ public class WiredEffectMoveRotateFurni extends InteractionWiredEffect implement
int newRotation = this.rotation > 0 ? this.getNewRotation(item) : item.getRotation();
RoomTile newLocation = room.getLayout().getTile(item.getX(), item.getY());
RoomTile oldLocation = room.getLayout().getTile(item.getX(), item.getY());
double oldZ = item.getZ();
if(this.direction > 0) {
// Use pre-selected direction if available, otherwise pick random
@@ -77,13 +76,14 @@ public class WiredEffectMoveRotateFurni extends InteractionWiredEffect implement
boolean slideAnimation = item.getRotation() == newRotation;
FurnitureMovementError furniMoveTest = room.furnitureFitsAt(newLocation, item, newRotation, true);
if(newLocation != null && newLocation.state != RoomTileState.INVALID && (newLocation != oldLocation || newRotation != item.getRotation()) && (furniMoveTest == FurnitureMovementError.NONE || ((furniMoveTest == FurnitureMovementError.TILE_HAS_BOTS || furniMoveTest == FurnitureMovementError.TILE_HAS_HABBOS || furniMoveTest == FurnitureMovementError.TILE_HAS_PETS) && newLocation == oldLocation))) {
if(room.furnitureFitsAt(newLocation, item, newRotation, false) == FurnitureMovementError.NONE && room.moveFurniTo(item, newLocation, newRotation, null, !slideAnimation) == FurnitureMovementError.NONE) {
FurnitureMovementError furniMoveTest = WiredMoveCarryHelper.getMovementError(room, this, item, newLocation, newRotation, ctx);
if (newLocation != null && newLocation.state != RoomTileState.INVALID && (newLocation != oldLocation || newRotation != item.getRotation())
&& (furniMoveTest == FurnitureMovementError.NONE
|| ((furniMoveTest == FurnitureMovementError.TILE_HAS_BOTS
|| furniMoveTest == FurnitureMovementError.TILE_HAS_HABBOS
|| furniMoveTest == FurnitureMovementError.TILE_HAS_PETS) && newLocation == oldLocation))) {
if (WiredMoveCarryHelper.moveFurni(room, this, item, newLocation, newRotation, null, !slideAnimation, ctx) == FurnitureMovementError.NONE) {
this.itemCooldowns.add(item);
if(slideAnimation) {
room.sendComposer(new FloorItemOnRollerComposer(item, null, oldLocation, oldZ, newLocation, item.getZ(), 0, room).compose());
}
}
}
}
@@ -14,10 +14,11 @@ import com.eu.habbo.habbohotel.rooms.RoomUserRotation;
import com.eu.habbo.habbohotel.wired.WiredEffectType;
import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.habbohotel.wired.core.WiredUserMovementHelper;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserStatusComposer;
import gnu.trove.procedure.TObjectProcedure;
import java.sql.ResultSet;
@@ -53,21 +54,26 @@ public class WiredEffectMoveRotateUser extends InteractionWiredEffect {
}
boolean hasRotation = this.rotationDirection >= 0;
RoomUserRotation targetBodyRotation = hasRotation ? this.getTargetRotation(roomUnit) : roomUnit.getBodyRotation();
RoomUserRotation targetHeadRotation = hasRotation ? targetBodyRotation : roomUnit.getHeadRotation();
RoomTile targetTile = (this.movementDirection >= 0) ? this.getTargetTile(room, roomUnit, this.movementDirection) : null;
boolean canMove = this.canMoveTo(room, roomUnit, targetTile);
if (hasRotation) {
roomUnit.setRotation(this.getTargetRotation(roomUnit));
}
boolean noAnimation = WiredMoveCarryHelper.hasNoAnimationExtra(room, this);
if (canMove) {
double targetZ = targetTile.getStackHeight() + ((targetTile.state == RoomTileState.SIT) ? -0.5 : 0);
room.teleportRoomUnitToLocation(roomUnit, targetTile.x, targetTile.y, targetZ);
int animationDuration = noAnimation ? 0 : WiredMoveCarryHelper.getAnimationDuration(room, this, WiredUserMovementHelper.DEFAULT_ANIMATION_DURATION);
if (!WiredUserMovementHelper.moveUser(room, roomUnit, targetTile, targetZ, targetBodyRotation, targetHeadRotation,
animationDuration, noAnimation)) {
if (hasRotation) {
WiredUserMovementHelper.updateUserDirection(room, roomUnit, targetBodyRotation, targetHeadRotation);
}
}
continue;
}
if (hasRotation) {
room.sendComposer(new RoomUserStatusComposer(roomUnit).compose());
WiredUserMovementHelper.updateUserDirection(room, roomUnit, targetBodyRotation, targetHeadRotation);
}
}
}
@@ -209,9 +215,6 @@ public class WiredEffectMoveRotateUser extends InteractionWiredEffect {
private RoomTile getTargetTile(Room room, RoomUnit roomUnit, int direction) {
RoomTile currentTile = roomUnit.getCurrentLocation();
if (currentTile == null) {
currentTile = room.getLayout().getTile(roomUnit.getX(), roomUnit.getY());
}
if (currentTile == null) {
return null;
@@ -12,6 +12,7 @@ import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.WiredEffectType;
import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
@@ -81,7 +82,7 @@ public class WiredEffectRelativeMove extends InteractionWiredEffect {
continue;
}
room.moveFurniTo(item, targetTile, item.getRotation(), null, true, false);
WiredMoveCarryHelper.moveFurni(room, this, item, targetTile, item.getRotation(), null, true, ctx);
}
}
@@ -12,6 +12,7 @@ import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.WiredEffectType;
import com.eu.habbo.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
@@ -73,7 +74,7 @@ public class WiredEffectSetAltitude extends InteractionWiredEffect {
}
double nextAltitude = this.computeAltitude(item.getZ());
room.moveFurniTo(item, tile, item.getRotation(), nextAltitude, null, true, false);
WiredMoveCarryHelper.moveFurni(room, this, item, tile, item.getRotation(), nextAltitude, null, true, ctx);
}
}
@@ -8,15 +8,17 @@ import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomTile;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
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.habbohotel.wired.core.WiredContext;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.habbohotel.wired.core.WiredUserMovementHelper;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
import com.eu.habbo.messages.outgoing.rooms.users.RoomUnitOnRollerComposer;
import gnu.trove.procedure.TObjectProcedure;
import java.sql.ResultSet;
@@ -234,39 +236,58 @@ public class WiredEffectUserToFurni extends WiredEffectUserFurniBase {
RoomTile oldLocation = roomUnit.getCurrentLocation();
RoomTile previousGoal = roomUnit.getGoal();
boolean wasWalking = roomUnit.isWalking();
if (oldLocation == null) {
oldLocation = room.getLayout().getTile(roomUnit.getX(), roomUnit.getY());
}
boolean noAnimation = WiredMoveCarryHelper.hasNoAnimationExtra(room, this);
if (oldLocation == null) {
return;
}
double oldZ = roomUnit.getZ();
double newZ = item.getZ() + Item.getCurrentHeight(item);
room.sendComposer(new RoomUnitOnRollerComposer(roomUnit, null, oldLocation, oldZ, targetTile, newZ, room).compose());
int animationDuration = noAnimation ? 0 : WiredMoveCarryHelper.getAnimationDuration(room, this, WiredUserMovementHelper.DEFAULT_ANIMATION_DURATION);
if (!WiredUserMovementHelper.moveUser(room, roomUnit, targetTile, newZ,
roomUnit.getBodyRotation(), roomUnit.getHeadRotation(), animationDuration, noAnimation)) {
return;
}
this.applyWalkMode(roomUnit, oldLocation, previousGoal, targetTile, wasWalking);
roomUnit.setPreviousLocationZ(newZ);
this.applyWalkMode(roomUnit, oldLocation, previousGoal, targetTile, wasWalking,
animationDuration);
roomUnit.setPreviousLocationZ(roomUnit.getZ());
}
private void applyWalkMode(RoomUnit roomUnit, RoomTile oldLocation, RoomTile previousGoal, RoomTile targetTile, boolean wasWalking) {
private void applyWalkMode(RoomUnit roomUnit, RoomTile oldLocation, RoomTile previousGoal, RoomTile targetTile, boolean wasWalking, int delay) {
if (roomUnit == null || targetTile == null) {
return;
}
if (this.walkMode == WALKMODE_STOP || !wasWalking || previousGoal == null) {
roomUnit.setGoalLocation(targetTile);
Runnable applyGoal = () -> {
if (roomUnit.getCurrentLocation() == null
|| roomUnit.isWalking()
|| roomUnit.hasStatus(RoomUnitStatus.SIT)
|| roomUnit.hasStatus(RoomUnitStatus.LAY)
|| roomUnit.getCurrentLocation().x != targetTile.x
|| roomUnit.getCurrentLocation().y != targetTile.y) {
return;
}
if (this.walkMode == WALKMODE_STOP || !wasWalking || previousGoal == null) {
roomUnit.setGoalLocation(targetTile);
return;
}
if (this.walkMode == WALKMODE_IF_CLOSER && !this.isCloserToGoal(oldLocation, targetTile, previousGoal)) {
roomUnit.setGoalLocation(targetTile);
return;
}
roomUnit.setGoalLocation(previousGoal);
};
if (delay > 0) {
Emulator.getThreading().run(applyGoal, delay);
return;
}
if (this.walkMode == WALKMODE_IF_CLOSER && !this.isCloserToGoal(oldLocation, targetTile, previousGoal)) {
roomUnit.setGoalLocation(targetTile);
return;
}
roomUnit.setGoalLocation(previousGoal);
applyGoal.run();
}
private boolean isCloserToGoal(RoomTile oldLocation, RoomTile newLocation, RoomTile goalLocation) {
@@ -0,0 +1,125 @@
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
import com.eu.habbo.habbohotel.gameclients.GameClient;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.outgoing.rooms.WiredMovementsComposer;
import java.sql.ResultSet;
import java.sql.SQLException;
public class WiredExtraAnimationTime extends InteractionWiredExtra {
public static final int CODE = 60;
public static final int MIN_DURATION_MS = 50;
public static final int MAX_DURATION_MS = 2000;
private int durationMs = WiredMovementsComposer.DEFAULT_DURATION;
public WiredExtraAnimationTime(ResultSet set, Item baseItem) throws SQLException {
super(set, baseItem);
}
public WiredExtraAnimationTime(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
super(id, userId, item, extradata, limitedStack, limitedSells);
}
@Override
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
return false;
}
@Override
public boolean saveData(WiredSettings settings, GameClient gameClient) {
int value = (settings.getIntParams().length > 0) ? settings.getIntParams()[0] : this.durationMs;
if (value == this.durationMs && settings.getStringParam() != null && !settings.getStringParam().isEmpty()) {
try {
value = Integer.parseInt(settings.getStringParam());
} catch (NumberFormatException ignored) {
value = this.durationMs;
}
}
this.durationMs = normalizeDuration(value);
return true;
}
@Override
public String getWiredData() {
return WiredManager.getGson().toJson(new JsonData(this.durationMs));
}
@Override
public void serializeWiredData(ServerMessage message, Room room) {
message.appendBoolean(false);
message.appendInt(0);
message.appendInt(0);
message.appendInt(this.getBaseItem().getSpriteId());
message.appendInt(this.getId());
message.appendString("");
message.appendInt(1);
message.appendInt(this.durationMs);
message.appendInt(0);
message.appendInt(CODE);
message.appendInt(0);
message.appendInt(0);
}
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.durationMs = normalizeDuration((data != null) ? data.durationMs : WiredMovementsComposer.DEFAULT_DURATION);
return;
}
try {
this.durationMs = normalizeDuration(Integer.parseInt(wiredData));
} catch (NumberFormatException ignored) {
this.durationMs = WiredMovementsComposer.DEFAULT_DURATION;
}
}
@Override
public void onPickUp() {
this.durationMs = WiredMovementsComposer.DEFAULT_DURATION;
}
@Override
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) throws Exception {
}
@Override
public boolean hasConfiguration() {
return true;
}
public int getDurationMs() {
return this.durationMs;
}
private static int normalizeDuration(int value) {
return Math.max(MIN_DURATION_MS, Math.min(MAX_DURATION_MS, value));
}
static class JsonData {
int durationMs;
JsonData(int durationMs) {
this.durationMs = durationMs;
}
}
}
@@ -0,0 +1,157 @@
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
import com.eu.habbo.habbohotel.gameclients.GameClient;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import java.sql.ResultSet;
import java.sql.SQLException;
public class WiredExtraMoveCarryUsers extends InteractionWiredExtra {
public static final int CODE = 58;
public static final int MODE_DIRECTLY_ON_FURNI = 0;
public static final int MODE_SAME_TILE = 1;
public static final int SOURCE_ALL_ROOM_USERS = 900;
private int carryMode = MODE_DIRECTLY_ON_FURNI;
private int userSource = WiredSourceUtil.SOURCE_TRIGGER;
public WiredExtraMoveCarryUsers(ResultSet set, Item baseItem) throws SQLException {
super(set, baseItem);
}
public WiredExtraMoveCarryUsers(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
super(id, userId, item, extradata, limitedStack, limitedSells);
}
@Override
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
return false;
}
@Override
public boolean saveData(WiredSettings settings, GameClient gameClient) {
int[] params = settings.getIntParams();
this.carryMode = this.normalizeCarryMode((params.length > 0) ? params[0] : MODE_DIRECTLY_ON_FURNI);
this.userSource = this.normalizeUserSource((params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER);
return true;
}
@Override
public String getWiredData() {
return WiredManager.getGson().toJson(new JsonData(this.carryMode, this.userSource));
}
@Override
public void serializeWiredData(ServerMessage message, Room room) {
message.appendBoolean(false);
message.appendInt(0);
message.appendInt(0);
message.appendInt(this.getBaseItem().getSpriteId());
message.appendInt(this.getId());
message.appendString("");
message.appendInt(2);
message.appendInt(this.carryMode);
message.appendInt(this.userSource);
message.appendInt(0);
message.appendInt(CODE);
message.appendInt(0);
message.appendInt(0);
}
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
if (data != null) {
this.carryMode = this.normalizeCarryMode(data.carryMode);
this.userSource = this.normalizeUserSource(data.userSource);
}
return;
}
String[] legacyData = wiredData.split("\t");
if (legacyData.length > 0) {
try {
this.carryMode = this.normalizeCarryMode(Integer.parseInt(legacyData[0]));
} catch (NumberFormatException ignored) {
this.carryMode = MODE_DIRECTLY_ON_FURNI;
}
}
if (legacyData.length > 1) {
try {
this.userSource = this.normalizeUserSource(Integer.parseInt(legacyData[1]));
} catch (NumberFormatException ignored) {
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
}
}
}
@Override
public void onPickUp() {
this.carryMode = MODE_DIRECTLY_ON_FURNI;
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
}
@Override
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) throws Exception {
}
@Override
public boolean hasConfiguration() {
return true;
}
public int getCarryMode() {
return this.carryMode;
}
public int getUserSource() {
return this.userSource;
}
private int normalizeCarryMode(int value) {
return (value == MODE_SAME_TILE) ? MODE_SAME_TILE : MODE_DIRECTLY_ON_FURNI;
}
private int normalizeUserSource(int value) {
switch (value) {
case SOURCE_ALL_ROOM_USERS:
case WiredSourceUtil.SOURCE_SELECTOR:
case WiredSourceUtil.SOURCE_SIGNAL:
case WiredSourceUtil.SOURCE_TRIGGER:
return value;
default:
return WiredSourceUtil.SOURCE_TRIGGER;
}
}
static class JsonData {
int carryMode;
int userSource;
JsonData(int carryMode, int userSource) {
this.carryMode = carryMode;
this.userSource = userSource;
}
}
}
@@ -0,0 +1,78 @@
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
import com.eu.habbo.habbohotel.gameclients.GameClient;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.messages.ServerMessage;
import java.sql.ResultSet;
import java.sql.SQLException;
public class WiredExtraMoveNoAnimation extends InteractionWiredExtra {
public static final int CODE = 59;
public WiredExtraMoveNoAnimation(ResultSet set, Item baseItem) throws SQLException {
super(set, baseItem);
}
public WiredExtraMoveNoAnimation(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
super(id, userId, item, extradata, limitedStack, limitedSells);
}
@Override
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
return false;
}
@Override
public boolean saveData(WiredSettings settings, GameClient gameClient) {
return true;
}
@Override
public String getWiredData() {
return WiredManager.getGson().toJson(new JsonData());
}
@Override
public void serializeWiredData(ServerMessage message, Room room) {
message.appendBoolean(false);
message.appendInt(0);
message.appendInt(0);
message.appendInt(this.getBaseItem().getSpriteId());
message.appendInt(this.getId());
message.appendString("");
message.appendInt(0);
message.appendInt(0);
message.appendInt(CODE);
message.appendInt(0);
message.appendInt(0);
}
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
}
@Override
public void onPickUp() {
}
@Override
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) throws Exception {
}
@Override
public boolean hasConfiguration() {
return true;
}
static class JsonData {
}
}
@@ -0,0 +1,229 @@
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
import com.eu.habbo.habbohotel.gameclients.GameClient;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
import com.eu.habbo.messages.ServerMessage;
import java.sql.ResultSet;
import java.sql.SQLException;
public class WiredExtraMovePhysics extends InteractionWiredExtra {
public static final int CODE = 61;
public static final int SOURCE_ALL_ROOM = 900;
private boolean keepAltitude = false;
private boolean moveThroughFurni = false;
private boolean moveThroughUsers = false;
private boolean blockByFurni = false;
private int moveThroughFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
private int moveThroughUsersSource = WiredSourceUtil.SOURCE_TRIGGER;
private int blockByFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
public WiredExtraMovePhysics(ResultSet set, Item baseItem) throws SQLException {
super(set, baseItem);
}
public WiredExtraMovePhysics(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
super(id, userId, item, extradata, limitedStack, limitedSells);
}
@Override
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
return false;
}
@Override
public boolean saveData(WiredSettings settings, GameClient gameClient) {
int[] params = settings.getIntParams();
this.keepAltitude = readFlag(params, 0);
this.moveThroughFurni = readFlag(params, 1);
this.moveThroughUsers = readFlag(params, 2);
this.blockByFurni = readFlag(params, 3);
this.moveThroughFurniSource = normalizeSource(readInt(params, 4, WiredSourceUtil.SOURCE_TRIGGER));
this.blockByFurniSource = normalizeSource(readInt(params, 5, WiredSourceUtil.SOURCE_TRIGGER));
this.moveThroughUsersSource = normalizeSource(readInt(params, 6, WiredSourceUtil.SOURCE_TRIGGER));
return true;
}
@Override
public String getWiredData() {
return WiredManager.getGson().toJson(new JsonData(
this.keepAltitude,
this.moveThroughFurni,
this.moveThroughUsers,
this.blockByFurni,
this.moveThroughFurniSource,
this.blockByFurniSource,
this.moveThroughUsersSource));
}
@Override
public void serializeWiredData(ServerMessage message, Room room) {
message.appendBoolean(false);
message.appendInt(0);
message.appendInt(0);
message.appendInt(this.getBaseItem().getSpriteId());
message.appendInt(this.getId());
message.appendString("");
message.appendInt(7);
message.appendInt(this.keepAltitude ? 1 : 0);
message.appendInt(this.moveThroughFurni ? 1 : 0);
message.appendInt(this.moveThroughUsers ? 1 : 0);
message.appendInt(this.blockByFurni ? 1 : 0);
message.appendInt(this.moveThroughFurniSource);
message.appendInt(this.blockByFurniSource);
message.appendInt(this.moveThroughUsersSource);
message.appendInt(0);
message.appendInt(CODE);
message.appendInt(0);
message.appendInt(0);
}
@Override
public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
return;
}
if (wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
if (data != null) {
this.keepAltitude = data.keepAltitude;
this.moveThroughFurni = data.moveThroughFurni;
this.moveThroughUsers = data.moveThroughUsers;
this.blockByFurni = data.blockByFurni;
this.moveThroughFurniSource = normalizeSource(data.moveThroughFurniSource);
this.blockByFurniSource = normalizeSource(data.blockByFurniSource);
this.moveThroughUsersSource = normalizeSource(data.moveThroughUsersSource);
}
return;
}
String[] legacyData = wiredData.split("\t");
this.keepAltitude = readLegacyFlag(legacyData, 0);
this.moveThroughFurni = readLegacyFlag(legacyData, 1);
this.moveThroughUsers = readLegacyFlag(legacyData, 2);
this.blockByFurni = readLegacyFlag(legacyData, 3);
this.moveThroughFurniSource = normalizeSource(readLegacyInt(legacyData, 4, WiredSourceUtil.SOURCE_TRIGGER));
this.blockByFurniSource = normalizeSource(readLegacyInt(legacyData, 5, WiredSourceUtil.SOURCE_TRIGGER));
this.moveThroughUsersSource = normalizeSource(readLegacyInt(legacyData, 6, WiredSourceUtil.SOURCE_TRIGGER));
}
@Override
public void onPickUp() {
this.keepAltitude = false;
this.moveThroughFurni = false;
this.moveThroughUsers = false;
this.blockByFurni = false;
this.moveThroughFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
this.moveThroughUsersSource = WiredSourceUtil.SOURCE_TRIGGER;
this.blockByFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
}
@Override
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) throws Exception {
}
@Override
public boolean hasConfiguration() {
return true;
}
public boolean isKeepAltitude() {
return this.keepAltitude;
}
public boolean isMoveThroughFurni() {
return this.moveThroughFurni;
}
public boolean isMoveThroughUsers() {
return this.moveThroughUsers;
}
public boolean isBlockByFurni() {
return this.blockByFurni;
}
public int getMoveThroughFurniSource() {
return this.moveThroughFurniSource;
}
public int getMoveThroughUsersSource() {
return this.moveThroughUsersSource;
}
public int getBlockByFurniSource() {
return this.blockByFurniSource;
}
private static boolean readFlag(int[] params, int index) {
return readInt(params, index, 0) == 1;
}
private static int readInt(int[] params, int index, int fallback) {
return (params.length > index) ? params[index] : fallback;
}
private static boolean readLegacyFlag(String[] data, int index) {
return readLegacyInt(data, index, 0) == 1;
}
private static int readLegacyInt(String[] data, int index, int fallback) {
if (data.length <= index) {
return fallback;
}
try {
return Integer.parseInt(data[index]);
} catch (NumberFormatException ignored) {
return fallback;
}
}
private static int normalizeSource(int value) {
switch (value) {
case SOURCE_ALL_ROOM:
case WiredSourceUtil.SOURCE_TRIGGER:
case WiredSourceUtil.SOURCE_SELECTOR:
case WiredSourceUtil.SOURCE_SIGNAL:
return value;
default:
return WiredSourceUtil.SOURCE_TRIGGER;
}
}
static class JsonData {
boolean keepAltitude;
boolean moveThroughFurni;
boolean moveThroughUsers;
boolean blockByFurni;
int moveThroughFurniSource;
int blockByFurniSource;
int moveThroughUsersSource;
JsonData(boolean keepAltitude, boolean moveThroughFurni, boolean moveThroughUsers, boolean blockByFurni, int moveThroughFurniSource, int blockByFurniSource, int moveThroughUsersSource) {
this.keepAltitude = keepAltitude;
this.moveThroughFurni = moveThroughFurni;
this.moveThroughUsers = moveThroughUsers;
this.blockByFurni = blockByFurni;
this.moveThroughFurniSource = moveThroughFurniSource;
this.blockByFurniSource = blockByFurniSource;
this.moveThroughUsersSource = moveThroughUsersSource;
}
}
}
@@ -28,6 +28,8 @@ public class WiredEffectFurniArea extends InteractionWiredEffect {
private int rootY = 0;
private int areaWidth = 0;
private int areaHeight = 0;
private boolean filterExisting = false;
private boolean invert = false;
public WiredEffectFurniArea(ResultSet set, Item baseItem) throws SQLException {
super(set, baseItem);
@@ -43,9 +45,12 @@ public class WiredEffectFurniArea extends InteractionWiredEffect {
if (room == null || areaWidth <= 0 || areaHeight <= 0) return;
List<HabboItem> furniInArea = getFurniInArea(room);
if (!furniInArea.isEmpty()) {
ctx.targets().setItems(furniInArea);
}
ctx.targets().setItems(this.applySelectorModifiers(
furniInArea,
this.getSelectableFloorItems(room),
ctx.targets().items(),
this.filterExisting,
this.invert));
}
private List<HabboItem> getFurniInArea(Room room) {
@@ -78,6 +83,8 @@ public class WiredEffectFurniArea extends InteractionWiredEffect {
this.rootY = params[1];
this.areaWidth = params[2];
this.areaHeight = params[3];
this.filterExisting = params.length >= 5 && params[4] == 1;
this.invert = params.length >= 6 && params[5] == 1;
this.setDelay(settings.getDelay());
return true;
@@ -95,7 +102,7 @@ public class WiredEffectFurniArea extends InteractionWiredEffect {
@Override
public String getWiredData() {
return WiredManager.getGson().toJson(new JsonData(rootX, rootY, areaWidth, areaHeight, getDelay()));
return WiredManager.getGson().toJson(new JsonData(rootX, rootY, areaWidth, areaHeight, filterExisting, invert, getDelay()));
}
@Override
@@ -108,6 +115,8 @@ public class WiredEffectFurniArea extends InteractionWiredEffect {
this.rootY = data.rootY;
this.areaWidth = data.width;
this.areaHeight = data.height;
this.filterExisting = data.filterExisting;
this.invert = data.invert;
this.setDelay(data.delay);
}
}
@@ -118,6 +127,8 @@ public class WiredEffectFurniArea extends InteractionWiredEffect {
this.rootY = 0;
this.areaWidth = 0;
this.areaHeight = 0;
this.filterExisting = false;
this.invert = false;
this.setDelay(0);
}
@@ -131,11 +142,13 @@ public class WiredEffectFurniArea extends InteractionWiredEffect {
message.appendInt(this.getBaseItem().getSpriteId());
message.appendInt(this.getId());
message.appendString("");
message.appendInt(4);
message.appendInt(6);
message.appendInt(this.rootX);
message.appendInt(this.rootY);
message.appendInt(this.areaWidth);
message.appendInt(this.areaHeight);
message.appendInt(this.filterExisting ? 1 : 0);
message.appendInt(this.invert ? 1 : 0);
message.appendInt(0);
message.appendInt(this.getType().code);
@@ -153,13 +166,17 @@ public class WiredEffectFurniArea extends InteractionWiredEffect {
int rootY;
int width;
int height;
boolean filterExisting;
boolean invert;
int delay;
JsonData(int rootX, int rootY, int width, int height, int delay) {
JsonData(int rootX, int rootY, int width, int height, boolean filterExisting, boolean invert, int delay) {
this.rootX = rootX;
this.rootY = rootY;
this.width = width;
this.height = height;
this.filterExisting = filterExisting;
this.invert = invert;
this.delay = delay;
}
}
@@ -21,6 +21,7 @@ import gnu.trove.set.hash.THashSet;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
@@ -34,7 +35,7 @@ public class WiredTriggerReceiveSignal extends InteractionWiredTrigger {
private int channel = 0; // signal channel (0-based)
private THashSet<HabboItem> items;
private int furniSource = WiredSourceUtil.SOURCE_TRIGGER;
private int furniSource = WiredSourceUtil.SOURCE_SELECTED;
private final AtomicLong activationToken = new AtomicLong();
public WiredTriggerReceiveSignal(ResultSet set, Item baseItem) throws SQLException {
@@ -51,18 +52,16 @@ public class WiredTriggerReceiveSignal extends InteractionWiredTrigger {
public boolean matches(HabboItem triggerItem, WiredEvent event) {
if (event.getType() != WiredEvent.Type.SIGNAL_RECEIVED) return false;
if (event.getSignalChannel() != this.channel) {
return false;
}
HabboItem sourceItem = event.getSourceItem().orElse(null);
if (sourceItem == null) {
return false;
}
return WiredTriggerSourceUtil.resolveItems(this, event, this.furniSource, this.items).stream()
List<HabboItem> resolvedAntennas = WiredTriggerSourceUtil.resolveItems(this, event, this.furniSource, this.items).stream()
.filter(this::isAntennaItem)
.anyMatch(item -> item != null && item.getId() == sourceItem.getId());
.collect(Collectors.toList());
if (!resolvedAntennas.isEmpty()) {
return resolvedAntennas.stream()
.anyMatch(item -> item != null && item.getId() == event.getSignalChannel());
}
return this.channel > 0 && event.getSignalChannel() == this.channel;
}
public int getChannel() {
@@ -90,7 +89,7 @@ public class WiredTriggerReceiveSignal extends InteractionWiredTrigger {
int senderCount = 0;
try {
if (room != null && room.getRoomSpecialTypes() != null) {
senderCount = room.getRoomSpecialTypes().countSendersTargetingReceiver(this.getId());
senderCount = this.getSenderCount(room);
}
} catch (Exception e) {
}
@@ -153,6 +152,11 @@ public class WiredTriggerReceiveSignal extends InteractionWiredTrigger {
}
}
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED && !this.items.isEmpty()) {
HabboItem firstItem = this.items.iterator().next();
this.channel = (firstItem != null) ? firstItem.getId() : this.channel;
}
return true;
}
@@ -212,6 +216,10 @@ public class WiredTriggerReceiveSignal extends InteractionWiredTrigger {
}
if (this.furniSource != WiredSourceUtil.SOURCE_SELECTOR) this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED && !this.items.isEmpty() && this.channel <= 0) {
HabboItem firstItem = this.items.iterator().next();
if (firstItem != null) this.channel = firstItem.getId();
}
}
}
@@ -252,4 +260,30 @@ public class WiredTriggerReceiveSignal extends InteractionWiredTrigger {
String interaction = item.getBaseItem().getInteractionType().getName();
return interaction != null && ANTENNA_INTERACTION.equalsIgnoreCase(interaction);
}
private int getSenderCount(Room room) {
if (room == null || room.getRoomSpecialTypes() == null) {
return 0;
}
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED && !this.items.isEmpty()) {
List<Integer> antennaIds = new ArrayList<>();
for (HabboItem item : this.items) {
if (this.isAntennaItem(item)) {
antennaIds.add(item.getId());
}
}
if (!antennaIds.isEmpty()) {
return room.getRoomSpecialTypes().countSendersTargetingAnyReceiver(antennaIds);
}
}
if (this.channel > 0) {
return room.getRoomSpecialTypes().countSendersTargetingReceiver(this.channel);
}
return 0;
}
}
@@ -18,6 +18,7 @@ import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.WiredUserActionType;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredMovementPhysics;
import com.eu.habbo.messages.ISerialize;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.outgoing.guilds.GuildInfoComposer;
@@ -2440,6 +2441,11 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
return this.itemManager.furnitureFitsAt(tile, item, rotation, checkForUnits);
}
public FurnitureMovementError furnitureFitsAtWithPhysics(RoomTile tile, HabboItem item, int rotation,
boolean checkForUnits, WiredMovementPhysics physics) {
return this.itemManager.furnitureFitsAtWithPhysics(tile, item, rotation, checkForUnits, physics);
}
public FurnitureMovementError placeFloorFurniAt(HabboItem item, RoomTile tile, int rotation,
Habbo owner) {
return this.itemManager.placeFloorFurniAt(item, tile, rotation, owner);
@@ -2476,6 +2482,16 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
return this.itemManager.moveFurniTo(item, tile, rotation, z, actor, sendUpdates, checkForUnits);
}
public FurnitureMovementError moveFurniToWithPhysics(HabboItem item, RoomTile tile, int rotation,
Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) {
return this.itemManager.moveFurniToWithPhysics(item, tile, rotation, actor, sendUpdates, checkForUnits, physics);
}
public FurnitureMovementError moveFurniToWithPhysics(HabboItem item, RoomTile tile, int rotation, double z,
Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) {
return this.itemManager.moveFurniToWithPhysics(item, tile, rotation, z, actor, sendUpdates, checkForUnits, physics);
}
public FurnitureMovementError slideFurniTo(HabboItem item, RoomTile tile, int rotation) {
return this.itemManager.slideFurniTo(item, tile, rotation);
}
@@ -23,6 +23,7 @@ import com.eu.habbo.habbohotel.users.HabboInfo;
import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.users.HabboManager;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredMovementPhysics;
import com.eu.habbo.habbohotel.wired.tick.WiredTickable;
import com.eu.habbo.messages.outgoing.inventory.AddHabboItemComposer;
import com.eu.habbo.messages.outgoing.rooms.items.*;
@@ -1301,6 +1302,56 @@ public class RoomItemManager {
return FurnitureMovementError.NONE;
}
public FurnitureMovementError furnitureFitsAtWithPhysics(RoomTile tile, HabboItem item, int rotation, boolean checkForUnits, WiredMovementPhysics physics) {
if (physics == null || !physics.isActive()) {
return furnitureFitsAt(tile, item, rotation, 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) {
return FurnitureMovementError.NONE;
}
THashSet<RoomTile> occupiedTiles = layout.getTilesAt(tile, item.getBaseItem().getWidth(),
item.getBaseItem().getLength(), rotation);
for (RoomTile t : occupiedTiles) {
if (t.state == RoomTileState.INVALID) {
return FurnitureMovementError.INVALID_MOVE;
}
if (shouldCheckUnits(item, checkForUnits)) {
FurnitureMovementError unitCollision = this.getPhysicsUnitCollision(t, physics);
if (unitCollision != FurnitureMovementError.NONE) {
return unitCollision;
}
}
}
if (this.hasBlockingPhysicsFurni(occupiedTiles, item, physics)) {
return FurnitureMovementError.CANT_STACK;
}
java.util.List<Pair<RoomTile, THashSet<HabboItem>>> tileFurniList = new java.util.ArrayList<>();
for (RoomTile t : occupiedTiles) {
tileFurniList.add(Pair.create(t, this.getPhysicsItemsAt(t, item, physics)));
HabboItem topItem = this.getTopPhysicsItemAt(t.x, t.y, item, physics);
if (topItem != null && !topItem.getBaseItem().allowStack() && !t.getAllowStack()) {
return FurnitureMovementError.CANT_STACK;
}
}
if (!item.canStackAt(this.room, tileFurniList)) {
return FurnitureMovementError.CANT_STACK;
}
return FurnitureMovementError.NONE;
}
/**
* Places a floor furniture item at a position.
*/
@@ -1569,6 +1620,158 @@ public class RoomItemManager {
return FurnitureMovementError.NONE;
}
public FurnitureMovementError moveFurniToWithPhysics(HabboItem item, RoomTile tile, int rotation, double z, Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) {
if (physics == null || !physics.isActive()) {
return moveFurniTo(item, tile, rotation, z, actor, sendUpdates, checkForUnits);
}
if (item == null || tile == null) {
return FurnitureMovementError.INVALID_MOVE;
}
RoomLayout layout = this.room.getLayout();
RoomTile oldLocation = layout.getTile(item.getX(), item.getY());
boolean pluginHelper = false;
if (Emulator.getPluginManager().isRegistered(FurnitureMovedEvent.class, true)) {
FurnitureMovedEvent event = Emulator.getPluginManager()
.fireEvent(new FurnitureMovedEvent(item, actor, oldLocation, tile));
if (event.isCancelled()) {
return FurnitureMovementError.CANCEL_PLUGIN_MOVE;
}
pluginHelper = event.hasPluginHelper();
}
rotation %= 8;
boolean magicTile =
item instanceof InteractionStackHelper ||
item instanceof InteractionTileWalkMagic;
THashSet<RoomTile> occupiedTiles = layout.getTilesAt(
tile,
item.getBaseItem().getWidth(),
item.getBaseItem().getLength(),
rotation
);
THashSet<RoomTile> oldOccupiedTiles = layout.getTilesAt(
layout.getTile(item.getX(), item.getY()),
item.getBaseItem().getWidth(),
item.getBaseItem().getLength(),
item.getRotation()
);
if (!pluginHelper) {
FurnitureMovementError fits = furnitureFitsAtWithPhysics(tile, item, rotation, checkForUnits, physics);
if (fits != FurnitureMovementError.NONE) {
return fits;
}
}
int oldRotation = item.getRotation();
if (oldRotation != rotation) {
item.setRotation(rotation);
if (Emulator.getPluginManager().isRegistered(FurnitureRotatedEvent.class, true)) {
Event rotatedEvent = new FurnitureRotatedEvent(item, actor, oldRotation);
Emulator.getPluginManager().fireEvent(rotatedEvent);
if (rotatedEvent.isCancelled()) {
item.setRotation(oldRotation);
return FurnitureMovementError.CANCEL_PLUGIN_ROTATE;
}
}
}
if (z > Room.MAXIMUM_FURNI_HEIGHT) {
return FurnitureMovementError.CANT_STACK;
}
if (z < layout.getHeightAtSquare(tile.x, tile.y)) {
return FurnitureMovementError.CANT_STACK;
}
if (Emulator.getPluginManager().isRegistered(FurnitureBuildheightEvent.class, true)) {
FurnitureBuildheightEvent event = Emulator.getPluginManager()
.fireEvent(new FurnitureBuildheightEvent(item, actor, 0.00, z));
if (event.hasChangedHeight()) {
z = layout.getHeightAtSquare(tile.x, tile.y) + event.getUpdatedHeight();
}
}
item.setX(tile.x);
item.setY(tile.y);
item.setZ(z);
if (magicTile) {
item.setZ(tile.z);
item.setExtradata("" + (item.getZ() * 100));
}
if (item.getZ() > Room.MAXIMUM_FURNI_HEIGHT) {
item.setZ(Room.MAXIMUM_FURNI_HEIGHT);
}
if (oldLocation != null) {
if (item instanceof InteractionWiredTrigger) {
this.room.getRoomSpecialTypes().updateTriggerLocation((InteractionWiredTrigger) item, oldLocation.x, oldLocation.y);
WiredManager.invalidateRoom(this.room);
} else if (item instanceof InteractionWiredEffect) {
this.room.getRoomSpecialTypes().updateEffectLocation((InteractionWiredEffect) item, oldLocation.x, oldLocation.y);
WiredManager.invalidateRoom(this.room);
} else if (item instanceof InteractionWiredCondition) {
this.room.getRoomSpecialTypes().updateConditionLocation((InteractionWiredCondition) item, oldLocation.x, oldLocation.y);
WiredManager.invalidateRoom(this.room);
} else if (item instanceof InteractionWiredExtra) {
this.room.getRoomSpecialTypes().updateExtraLocation((InteractionWiredExtra) item, oldLocation.x, oldLocation.y);
WiredManager.invalidateRoom(this.room);
}
}
item.onMove(this.room, oldLocation, tile);
item.needsUpdate(true);
Emulator.getThreading().run(item);
if (sendUpdates) {
this.room.sendComposer(new FloorItemUpdateComposer(item).compose());
}
occupiedTiles.removeAll(oldOccupiedTiles);
occupiedTiles.addAll(oldOccupiedTiles);
this.room.updateTiles(occupiedTiles);
for (RoomTile t : occupiedTiles) {
this.room.updateHabbosAt(t.x, t.y, this.room.getHabbosAt(t.x, t.y));
this.room.updateBotsAt(t.x, t.y);
}
if (Emulator.getConfig().getBoolean("wired.place.under", false)) {
THashSet<RoomTile> newOccupiedTiles = layout.getTilesAt(
tile,
item.getBaseItem().getWidth(),
item.getBaseItem().getLength(),
rotation
);
for (RoomTile t : newOccupiedTiles) {
for (Habbo h : this.room.getHabbosAt(t.x, t.y)) {
try {
item.onWalkOn(h.getRoomUnit(), this.room, null);
} catch (Exception ignored) {
}
}
}
}
return FurnitureMovementError.NONE;
}
/**
* Moves furniture to a new position.
*/
@@ -1791,6 +1994,203 @@ public class RoomItemManager {
return FurnitureMovementError.NONE;
}
public FurnitureMovementError moveFurniToWithPhysics(HabboItem item, RoomTile tile, int rotation, Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) {
if (physics == null || !physics.isActive()) {
return moveFurniTo(item, tile, rotation, actor, sendUpdates, checkForUnits);
}
RoomLayout layout = this.room.getLayout();
RoomTile oldLocation = layout.getTile(item.getX(), item.getY());
boolean pluginHelper = false;
if (Emulator.getPluginManager().isRegistered(FurnitureMovedEvent.class, true)) {
FurnitureMovedEvent event = Emulator.getPluginManager()
.fireEvent(new FurnitureMovedEvent(item, actor, oldLocation, tile));
if (event.isCancelled()) {
return FurnitureMovementError.CANCEL_PLUGIN_MOVE;
}
pluginHelper = event.hasPluginHelper();
}
boolean magicTile = item instanceof InteractionStackHelper || item instanceof InteractionTileWalkMagic;
java.util.Optional<HabboItem> stackHelper = this.getItemsAt(tile).stream()
.filter(i -> i instanceof InteractionStackHelper).findAny();
THashSet<RoomTile> occupiedTiles = layout.getTilesAt(tile, item.getBaseItem().getWidth(),
item.getBaseItem().getLength(), rotation);
THashSet<RoomTile> newOccupiedTiles = layout.getTilesAt(tile,
item.getBaseItem().getWidth(), item.getBaseItem().getLength(), rotation);
HabboItem topItem = this.getTopPhysicsItemAt(occupiedTiles, null, physics);
if (!stackHelper.isPresent() && !pluginHelper) {
if (oldLocation != tile) {
for (RoomTile t : occupiedTiles) {
HabboItem tileTopItem = this.getTopPhysicsItemAt(t.x, t.y, item, physics);
if (!magicTile && ((tileTopItem != null && tileTopItem != item ? (
t.state.equals(RoomTileState.INVALID) || !t.getAllowStack()
|| !tileTopItem.getBaseItem().allowStack())
: this.room.calculateTileState(t, item).equals(RoomTileState.INVALID)))) {
return FurnitureMovementError.CANT_STACK;
}
if (shouldCheckUnits(item, checkForUnits)) {
FurnitureMovementError unitCollision = this.getPhysicsUnitCollision(t, physics);
if (!magicTile && unitCollision != FurnitureMovementError.NONE) {
return unitCollision;
}
}
}
}
if (this.hasBlockingPhysicsFurni(occupiedTiles, item, physics)) {
return FurnitureMovementError.CANT_STACK;
}
java.util.List<Pair<RoomTile, THashSet<HabboItem>>> tileFurniList = new java.util.ArrayList<>();
for (RoomTile t : occupiedTiles) {
tileFurniList.add(Pair.create(t, this.getPhysicsItemsAt(t, item, physics)));
}
if (!magicTile && !item.canStackAt(this.room, tileFurniList)) {
return FurnitureMovementError.CANT_STACK;
}
}
THashSet<RoomTile> oldOccupiedTiles = layout.getTilesAt(
layout.getTile(item.getX(), item.getY()), item.getBaseItem().getWidth(),
item.getBaseItem().getLength(), item.getRotation());
int oldRotation = item.getRotation();
if (oldRotation != rotation) {
item.setRotation(rotation);
if (Emulator.getPluginManager().isRegistered(FurnitureRotatedEvent.class, true)) {
Event furnitureRotatedEvent = new FurnitureRotatedEvent(item, actor, oldRotation);
Emulator.getPluginManager().fireEvent(furnitureRotatedEvent);
if (furnitureRotatedEvent.isCancelled()) {
item.setRotation(oldRotation);
return FurnitureMovementError.CANCEL_PLUGIN_ROTATE;
}
}
if ((!stackHelper.isPresent() && topItem != null && topItem != item && !topItem.getBaseItem()
.allowStack()) || (topItem != null && topItem != item
&& topItem.getZ() + Item.getCurrentHeight(topItem) + Item.getCurrentHeight(item)
> Room.MAXIMUM_FURNI_HEIGHT)) {
item.setRotation(oldRotation);
return FurnitureMovementError.CANT_STACK;
}
}
double height;
if (stackHelper.isPresent()) {
height = stackHelper.get().getExtradata().isEmpty() ? Double.parseDouble("0.0")
: (Double.parseDouble(stackHelper.get().getExtradata()) / 100);
} else if (item == topItem) {
height = item.getZ();
} else if (magicTile) {
if (topItem == null) {
height = this.getPhysicsStackHeight(tile.x, tile.y, item, physics);
for (RoomTile til : occupiedTiles) {
double sHeight = this.getPhysicsStackHeight(til.x, til.y, item, physics);
if (sHeight > height) {
height = sHeight;
}
}
} else {
height = topItem.getZ() + topItem.getBaseItem().getHeight();
}
} else {
height = this.getPhysicsStackHeight(tile.x, tile.y, item, physics);
for (RoomTile til : occupiedTiles) {
double sHeight = this.getPhysicsStackHeight(til.x, til.y, item, physics);
if (sHeight > height) {
height = sHeight;
}
}
}
boolean cantStack = false;
boolean pluginHeight = false;
if (height > Room.MAXIMUM_FURNI_HEIGHT) {
cantStack = true;
}
if (height < layout.getHeightAtSquare(tile.x, tile.y)) {
cantStack = true;
}
if (Emulator.getPluginManager().isRegistered(FurnitureBuildheightEvent.class, true)) {
FurnitureBuildheightEvent event = Emulator.getPluginManager()
.fireEvent(new FurnitureBuildheightEvent(item, actor, 0.00, height));
if (event.hasChangedHeight()) {
height = layout.getHeightAtSquare(tile.x, tile.y) + event.getUpdatedHeight();
pluginHeight = true;
}
}
if (!pluginHeight && cantStack) {
return FurnitureMovementError.CANT_STACK;
}
item.setX(tile.x);
item.setY(tile.y);
item.setZ(height);
if (magicTile) {
item.setZ(tile.z);
item.setExtradata("" + item.getZ() * 100);
}
if (item.getZ() > Room.MAXIMUM_FURNI_HEIGHT) {
item.setZ(Room.MAXIMUM_FURNI_HEIGHT);
}
if (item instanceof InteractionWiredTrigger) {
this.room.getRoomSpecialTypes().updateTriggerLocation((InteractionWiredTrigger) item, oldLocation.x, oldLocation.y);
WiredManager.invalidateRoom(this.room);
} else if (item instanceof InteractionWiredEffect) {
this.room.getRoomSpecialTypes().updateEffectLocation((InteractionWiredEffect) item, oldLocation.x, oldLocation.y);
WiredManager.invalidateRoom(this.room);
} else if (item instanceof InteractionWiredCondition) {
this.room.getRoomSpecialTypes().updateConditionLocation((InteractionWiredCondition) item, oldLocation.x, oldLocation.y);
WiredManager.invalidateRoom(this.room);
} else if (item instanceof InteractionWiredExtra) {
this.room.getRoomSpecialTypes().updateExtraLocation((InteractionWiredExtra) item, oldLocation.x, oldLocation.y);
WiredManager.invalidateRoom(this.room);
}
item.onMove(this.room, oldLocation, tile);
item.needsUpdate(true);
Emulator.getThreading().run(item);
if (sendUpdates) {
this.room.sendComposer(new FloorItemUpdateComposer(item).compose());
}
occupiedTiles.removeAll(oldOccupiedTiles);
occupiedTiles.addAll(oldOccupiedTiles);
this.room.updateTiles(occupiedTiles);
for (RoomTile t : occupiedTiles) {
this.room.updateHabbosAt(t.x, t.y, this.room.getHabbosAt(t.x, t.y));
this.room.updateBotsAt(t.x, t.y);
}
if (Emulator.getConfig().getBoolean("wired.place.under", false)) {
for (RoomTile t : newOccupiedTiles) {
for (Habbo h : this.room.getHabbosAt(t.x, t.y)) {
try {
item.onWalkOn(h.getRoomUnit(), this.room, null);
} catch (Exception e) {
}
}
}
}
return FurnitureMovementError.NONE;
}
/**
* Slides furniture to a new position.
*/
@@ -1832,4 +2232,153 @@ public class RoomItemManager {
}
return FurnitureMovementError.NONE;
}
private boolean shouldCheckUnits(HabboItem item, boolean checkForUnits) {
if (!checkForUnits) {
return false;
}
if (!Emulator.getConfig().getBoolean("wired.place.under", false)) {
return true;
}
return !item.isWalkable()
&& !item.getBaseItem().allowSit()
&& !item.getBaseItem().allowLay();
}
private FurnitureMovementError getPhysicsUnitCollision(RoomTile tile, WiredMovementPhysics physics) {
for (RoomUnit roomUnit : this.room.getRoomUnits(tile)) {
if (roomUnit == null) {
continue;
}
switch (roomUnit.getRoomUnitType()) {
case BOT:
return FurnitureMovementError.TILE_HAS_BOTS;
case PET:
return FurnitureMovementError.TILE_HAS_PETS;
case USER:
if (physics == null || !physics.shouldIgnoreUser(roomUnit)) {
return FurnitureMovementError.TILE_HAS_HABBOS;
}
break;
default:
return FurnitureMovementError.TILE_HAS_HABBOS;
}
}
return FurnitureMovementError.NONE;
}
private boolean hasBlockingPhysicsFurni(THashSet<RoomTile> occupiedTiles, HabboItem exclude, WiredMovementPhysics physics) {
if (physics == null || !physics.hasBlockingFurni()) {
return false;
}
for (RoomTile tile : occupiedTiles) {
for (HabboItem item : this.getItemsAt(tile)) {
if (item == null || item == exclude) {
continue;
}
if (physics.isBlockingFurni(item)) {
return true;
}
}
}
return false;
}
private THashSet<HabboItem> getPhysicsItemsAt(RoomTile tile, HabboItem exclude, WiredMovementPhysics physics) {
THashSet<HabboItem> items = new THashSet<>();
for (HabboItem item : this.getItemsAt(tile)) {
if (item == null || item == exclude) {
continue;
}
if (physics != null && physics.shouldIgnoreFurni(item)) {
continue;
}
items.add(item);
}
return items;
}
private HabboItem getTopPhysicsItemAt(int x, int y, HabboItem exclude, WiredMovementPhysics physics) {
RoomTile tile = this.room.getLayout().getTile((short) x, (short) y);
if (tile == null) {
return null;
}
HabboItem highestItem = null;
for (HabboItem item : this.getPhysicsItemsAt(tile, exclude, physics)) {
if (highestItem != null && highestItem.getZ() + Item.getCurrentHeight(highestItem)
> item.getZ() + Item.getCurrentHeight(item)) {
continue;
}
highestItem = item;
}
return highestItem;
}
private HabboItem getTopPhysicsItemAt(THashSet<RoomTile> tiles, HabboItem exclude, WiredMovementPhysics physics) {
HabboItem highestItem = null;
for (RoomTile tile : tiles) {
if (tile == null) {
continue;
}
HabboItem topItem = this.getTopPhysicsItemAt(tile.x, tile.y, exclude, physics);
if (topItem == null) {
continue;
}
if (highestItem != null && highestItem.getZ() + Item.getCurrentHeight(highestItem)
> topItem.getZ() + Item.getCurrentHeight(topItem)) {
continue;
}
highestItem = topItem;
}
return highestItem;
}
private double getPhysicsStackHeight(short x, short y, HabboItem exclude, WiredMovementPhysics physics) {
RoomLayout layout = this.room.getLayout();
if (x < 0 || y < 0 || layout == null) {
return 0.0;
}
double height = layout.getHeightAtSquare(x, y);
RoomTile tile = layout.getTile(x, y);
if (tile == null) {
return height;
}
for (HabboItem item : this.getPhysicsItemsAt(tile, exclude, physics)) {
if (item instanceof InteractionStackHelper || item instanceof InteractionTileWalkMagic) {
return item.getZ();
}
}
HabboItem topItem = this.getTopPhysicsItemAt(x, y, exclude, physics);
if (topItem != null) {
return topItem.getZ() + (topItem.getBaseItem().allowSit() ? 0 : Item.getCurrentHeight(topItem));
}
return height;
}
}
@@ -30,7 +30,9 @@ import gnu.trove.set.hash.THashSet;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -376,6 +378,39 @@ public class RoomSpecialTypes {
return countSendersTargetingReceiver(receiverItemId, null);
}
public int countSendersTargetingAnyReceiver(Collection<Integer> receiverItemIds, InteractionWiredEffect excludeSender) {
if (receiverItemIds == null || receiverItemIds.isEmpty()) {
return 0;
}
Set<InteractionWiredEffect> senders = this.wiredEffects.get(WiredEffectType.SEND_SIGNAL);
if (senders == null) {
return 0;
}
Set<Integer> uniqueSenderIds = new HashSet<>();
for (InteractionWiredEffect effect : senders) {
if (excludeSender != null && effect.getId() == excludeSender.getId()) continue;
if (!(effect instanceof WiredEffectSendSignal)) continue;
WiredEffectSendSignal sender = (WiredEffectSendSignal) effect;
for (Integer receiverItemId : receiverItemIds) {
if (receiverItemId == null) continue;
if (!sender.hasPickedItem(receiverItemId)) continue;
uniqueSenderIds.add(effect.getId());
break;
}
}
return uniqueSenderIds.size();
}
public int countSendersTargetingAnyReceiver(Collection<Integer> receiverItemIds) {
return countSendersTargetingAnyReceiver(receiverItemIds, null);
}
public void addTrigger(InteractionWiredTrigger trigger) {
// Add to type-based index
this.wiredTriggers.computeIfAbsent(trigger.getType(), k -> ConcurrentHashMap.newKeySet())
@@ -9,6 +9,8 @@ import com.eu.habbo.habbohotel.items.interactions.InteractionWaterItem;
import com.eu.habbo.habbohotel.items.interactions.interfaces.ConditionalGate;
import com.eu.habbo.habbohotel.pets.Pet;
import com.eu.habbo.habbohotel.pets.RideablePet;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredUserMovementHelper;
import com.eu.habbo.habbohotel.users.DanceType;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboItem;
@@ -614,6 +616,11 @@ public class RoomUnit {
public void setStatus(RoomUnitStatus key, String value) {
if (key != null && value != null) {
if (key == RoomUnitStatus.MOVE) {
WiredMoveCarryHelper.clearStatusComposerSuppression(this);
WiredUserMovementHelper.clearStatusComposerSuppression(this);
}
this.status.put(key, value);
}
}
@@ -14,6 +14,8 @@ import com.eu.habbo.habbohotel.users.HabboGender;
import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.core.WiredFreezeUtil;
import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredUserMovementHelper;
import com.eu.habbo.habbohotel.wired.WiredUserActionType;
import com.eu.habbo.messages.outgoing.generic.alerts.GenericErrorMessagesComposer;
import com.eu.habbo.messages.outgoing.inventory.AddPetComposer;
@@ -360,6 +362,11 @@ public class RoomUnitManager {
continue;
}
if (WiredMoveCarryHelper.shouldSuppressStatusUpdate(habbo.getRoomUnit())
|| WiredUserMovementHelper.shouldSuppressStatusUpdate(habbo.getRoomUnit())) {
continue;
}
double z = habbo.getRoomUnit().getCurrentLocation().getStackHeight();
boolean hadLayStatus = habbo.getRoomUnit().hasStatus(RoomUnitStatus.LAY);
@@ -432,9 +439,17 @@ public class RoomUnitManager {
if (!habbos.isEmpty()) {
THashSet<RoomUnit> roomUnits = new THashSet<>();
for (Habbo habbo : habbos) {
if (habbo.getRoomUnit() == null
|| WiredMoveCarryHelper.shouldSuppressStatusUpdate(habbo.getRoomUnit())
|| WiredUserMovementHelper.shouldSuppressStatusUpdate(habbo.getRoomUnit())) {
continue;
}
roomUnits.add(habbo.getRoomUnit());
}
this.room.sendComposer(new RoomUserStatusComposer(roomUnits, true).compose());
if (!roomUnits.isEmpty()) {
this.room.sendComposer(new RoomUserStatusComposer(roomUnits, true).compose());
}
}
if (topItem != null && topItem.getBaseItem().allowLay()) {
@@ -197,7 +197,7 @@ public final class RoomWiredStackIndex implements WiredStackIndex {
}
List<IWiredCondition> conditions = new ArrayList<>(rawConditions.size());
for (InteractionWiredCondition condition : rawConditions) {
for (InteractionWiredCondition condition : WiredExecutionOrderUtil.sort(rawConditions)) {
conditions.add(condition);
}
return conditions;
@@ -212,7 +212,7 @@ public final class RoomWiredStackIndex implements WiredStackIndex {
}
List<IWiredEffect> effects = new ArrayList<>(rawEffects.size());
for (InteractionWiredEffect effect : rawEffects) {
for (InteractionWiredEffect effect : WiredExecutionOrderUtil.sort(rawEffects)) {
effects.add(effect);
}
return effects;
@@ -0,0 +1,34 @@
package com.eu.habbo.habbohotel.wired.core;
import com.eu.habbo.habbohotel.users.HabboItem;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
public final class WiredExecutionOrderUtil {
private static final Comparator<HabboItem> WIRED_STACK_ORDER = Comparator
.comparingDouble(HabboItem::getZ)
.thenComparingInt(HabboItem::getId);
private WiredExecutionOrderUtil() {
}
public static <T extends HabboItem> List<T> sort(Collection<T> items) {
List<T> sorted = new ArrayList<>();
if (items == null || items.isEmpty()) {
return sorted;
}
for (T item : items) {
if (item != null) {
sorted.add(item);
}
}
sorted.sort(WIRED_STACK_ORDER);
return sorted;
}
}
@@ -0,0 +1,714 @@
package com.eu.habbo.habbohotel.wired.core;
import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraAnimationTime;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMoveCarryUsers;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMovePhysics;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMoveNoAnimation;
import com.eu.habbo.habbohotel.rooms.FurnitureMovementError;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomTile;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
import com.eu.habbo.habbohotel.rooms.RoomUnitType;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.messages.outgoing.rooms.WiredMovementsComposer;
import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserStatusComposer;
import gnu.trove.set.hash.THashSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public final class WiredMoveCarryHelper {
private static final double DIRECT_HEIGHT_TOLERANCE = 0.1D;
private static final int STATUS_SUPPRESSION_GRACE_MS = 250;
private static final ThreadLocal<Set<Integer>> SUPPRESSED_STATUS_ROOM_UNIT_IDS = new ThreadLocal<>();
private static final ConcurrentHashMap<Integer, Long> SUPPRESSED_STATUS_COMPOSER_UNTIL = new ConcurrentHashMap<>();
private WiredMoveCarryHelper() {
}
public static FurnitureMovementError getMovementError(Room room, HabboItem stackItem, HabboItem movingItem, RoomTile targetTile, int rotation, WiredContext ctx) {
if (room == null || movingItem == null || targetTile == null) {
return FurnitureMovementError.INVALID_MOVE;
}
if (!hasMovementBehaviorExtra(room, stackItem)) {
return room.furnitureFitsAt(targetTile, movingItem, rotation, true);
}
CarryContext carryContext = prepareCarryContext(room, stackItem, movingItem, ctx);
WiredMovementPhysics movementPhysics = getMovementPhysics(room, stackItem, movingItem, ctx);
FurnitureMovementError movementError = room.furnitureFitsAtWithPhysics(targetTile, movingItem, rotation, false, movementPhysics);
if (movementError != FurnitureMovementError.NONE) {
return movementError;
}
if (!carryContext.active) {
return room.furnitureFitsAtWithPhysics(targetTile, movingItem, rotation, true, movementPhysics);
}
return getBlockingUnitError(room, movingItem, targetTile, rotation, carryContext, movementPhysics);
}
public static FurnitureMovementError moveFurni(Room room, HabboItem stackItem, HabboItem movingItem, RoomTile targetTile, int rotation, Habbo actor, boolean sendUpdates, WiredContext ctx) {
return moveFurni(room, stackItem, movingItem, targetTile, rotation, null, actor, sendUpdates, ctx);
}
public static FurnitureMovementError moveFurni(Room room, HabboItem stackItem, HabboItem movingItem, RoomTile targetTile, int rotation, Double z, Habbo actor, boolean sendUpdates, WiredContext ctx) {
if (room == null || movingItem == null || targetTile == null) {
return FurnitureMovementError.INVALID_MOVE;
}
if (!hasMovementBehaviorExtra(room, stackItem)) {
return moveFurniLegacy(room, movingItem, targetTile, rotation, z, actor, sendUpdates);
}
RoomTile oldLocation = room.getLayout() == null ? null : room.getLayout().getTile(movingItem.getX(), movingItem.getY());
double oldZ = movingItem.getZ();
CarryContext carryContext = prepareCarryContext(room, stackItem, movingItem, ctx);
WiredMovementPhysics movementPhysics = getMovementPhysics(room, stackItem, movingItem, ctx);
FurnitureMovementError movementError = room.furnitureFitsAtWithPhysics(targetTile, movingItem, rotation, false, movementPhysics);
if (movementError != FurnitureMovementError.NONE) {
return movementError;
}
if (carryContext.active) {
movementError = getBlockingUnitError(room, movingItem, targetTile, rotation, carryContext, movementPhysics);
if (movementError != FurnitureMovementError.NONE) {
return movementError;
}
} else {
movementError = room.furnitureFitsAtWithPhysics(targetTile, movingItem, rotation, true, movementPhysics);
if (movementError != FurnitureMovementError.NONE) {
return movementError;
}
}
boolean useWiredMovements = !hasNoAnimationExtra(room, stackItem);
int animationDuration = getAnimationDuration(room, stackItem, WiredMovementsComposer.DEFAULT_DURATION);
Set<Integer> previousSuppressedRoomUnitIds = SUPPRESSED_STATUS_ROOM_UNIT_IDS.get();
if (carryContext.active) {
HashSet<Integer> suppressedRoomUnitIds = previousSuppressedRoomUnitIds == null
? new HashSet<>()
: new HashSet<>(previousSuppressedRoomUnitIds);
suppressedRoomUnitIds.addAll(carryContext.carriedUserIds);
SUPPRESSED_STATUS_ROOM_UNIT_IDS.set(suppressedRoomUnitIds);
}
FurnitureMovementError result;
Double targetZ = z;
if (targetZ == null && movementPhysics.isKeepAltitude()) {
targetZ = oldZ;
}
try {
result = (targetZ == null)
? room.moveFurniToWithPhysics(movingItem, targetTile, rotation, actor, !useWiredMovements, false, movementPhysics)
: room.moveFurniToWithPhysics(movingItem, targetTile, rotation, targetZ, actor, !useWiredMovements, false, movementPhysics);
} finally {
if (carryContext.active) {
if (previousSuppressedRoomUnitIds == null || previousSuppressedRoomUnitIds.isEmpty()) {
SUPPRESSED_STATUS_ROOM_UNIT_IDS.remove();
} else {
SUPPRESSED_STATUS_ROOM_UNIT_IDS.set(previousSuppressedRoomUnitIds);
}
}
}
if (result == FurnitureMovementError.NONE) {
if (!useWiredMovements) {
applyInstantCarryState(room, movingItem, targetTile, rotation, carryContext);
} else if (oldLocation != null) {
sendAnimatedMove(room, movingItem, oldLocation, oldZ, targetTile, rotation, carryContext, animationDuration);
}
}
return result;
}
private static FurnitureMovementError moveFurniLegacy(Room room, HabboItem movingItem, RoomTile targetTile, int rotation, Double z, Habbo actor, boolean sendUpdates) {
if (room == null || movingItem == null || targetTile == null) {
return FurnitureMovementError.INVALID_MOVE;
}
RoomTile oldLocation = room.getLayout() == null ? null : room.getLayout().getTile(movingItem.getX(), movingItem.getY());
double oldZ = movingItem.getZ();
FurnitureMovementError result = (z == null)
? room.moveFurniTo(movingItem, targetTile, rotation, actor, sendUpdates)
: room.moveFurniTo(movingItem, targetTile, rotation, z, actor, sendUpdates, false);
if (result == FurnitureMovementError.NONE
&& !sendUpdates
&& oldLocation != null
&& (oldLocation.x != targetTile.x || oldLocation.y != targetTile.y || Double.compare(oldZ, movingItem.getZ()) != 0)) {
room.sendComposer(new FloorItemOnRollerComposer(movingItem, null, oldLocation, oldZ, targetTile, movingItem.getZ(), 0, room).compose());
}
return result;
}
public static boolean shouldSuppressStatusUpdate(RoomUnit roomUnit) {
if (roomUnit == null) {
return false;
}
Set<Integer> suppressedRoomUnitIds = SUPPRESSED_STATUS_ROOM_UNIT_IDS.get();
return suppressedRoomUnitIds != null && suppressedRoomUnitIds.contains(roomUnit.getId());
}
public static boolean shouldSuppressStatusComposer(RoomUnit roomUnit) {
if (roomUnit == null) {
return false;
}
Long suppressedUntil = SUPPRESSED_STATUS_COMPOSER_UNTIL.get(roomUnit.getId());
if (suppressedUntil == null) {
return false;
}
if (suppressedUntil <= System.currentTimeMillis()) {
SUPPRESSED_STATUS_COMPOSER_UNTIL.remove(roomUnit.getId(), suppressedUntil);
return false;
}
return true;
}
public static void clearStatusComposerSuppression(RoomUnit roomUnit) {
if (roomUnit == null) {
return;
}
SUPPRESSED_STATUS_COMPOSER_UNTIL.remove(roomUnit.getId());
}
public static boolean hasNoAnimationExtra(Room room, HabboItem stackItem) {
return getNoAnimationExtra(room, stackItem) != null;
}
public static int getAnimationDuration(Room room, HabboItem stackItem, int fallbackDuration) {
WiredExtraAnimationTime extra = getAnimationTimeExtra(room, stackItem);
return (extra != null) ? extra.getDurationMs() : fallbackDuration;
}
private static boolean hasMovementBehaviorExtra(Room room, HabboItem stackItem) {
THashSet<InteractionWiredExtra> extras = getMovementExtras(room, stackItem);
if (extras == null || extras.isEmpty()) {
return false;
}
for (InteractionWiredExtra extra : extras) {
if (extra instanceof WiredExtraMoveCarryUsers
|| extra instanceof WiredExtraMoveNoAnimation
|| extra instanceof WiredExtraAnimationTime
|| extra instanceof WiredExtraMovePhysics) {
return true;
}
}
return false;
}
private static CarryContext prepareCarryContext(Room room, HabboItem stackItem, HabboItem movingItem, WiredContext ctx) {
WiredExtraMoveCarryUsers extra = getActiveExtra(room, stackItem);
if (extra == null || ctx == null || room.getLayout() == null) {
return CarryContext.disabled();
}
RoomTile anchorTile = room.getLayout().getTile(movingItem.getX(), movingItem.getY());
if (anchorTile == null) {
return CarryContext.disabled();
}
THashSet<RoomTile> occupiedTiles = room.getLayout().getTilesAt(
anchorTile,
movingItem.getBaseItem().getWidth(),
movingItem.getBaseItem().getLength(),
movingItem.getRotation());
if (occupiedTiles == null || occupiedTiles.isEmpty()) {
return CarryContext.disabled();
}
Collection<RoomUnit> targetUsers = resolveUsers(room, ctx, extra.getUserSource());
if (targetUsers == null || targetUsers.isEmpty()) {
return CarryContext.disabled();
}
List<CarriedRoomUnit> carriedUnits = new ArrayList<>();
HashSet<Integer> carriedIds = new HashSet<>();
for (RoomUnit roomUnit : targetUsers) {
if (!isEligibleUser(room, movingItem, roomUnit, occupiedTiles, extra.getCarryMode())) {
continue;
}
CarriedRoomUnit carriedRoomUnit = new CarriedRoomUnit(
roomUnit,
roomUnit.getCurrentLocation(),
roomUnit.getZ(),
roomUnit.getZ() - getCarrySurfaceZ(movingItem, roomUnit, roomUnit.getZ()),
roomUnit.getX() - anchorTile.x,
roomUnit.getY() - anchorTile.y);
carriedUnits.add(carriedRoomUnit);
carriedIds.add(roomUnit.getId());
}
if (carriedUnits.isEmpty()) {
return CarryContext.disabled();
}
return new CarryContext(true, carriedUnits, carriedIds);
}
private static Collection<RoomUnit> resolveUsers(Room room, WiredContext ctx, int userSource) {
if (userSource == WiredExtraMoveCarryUsers.SOURCE_ALL_ROOM_USERS) {
return new ArrayList<>(room.getRoomUnits());
}
return WiredSourceUtil.resolveUsers(ctx, userSource);
}
private static boolean isEligibleUser(Room room, HabboItem movingItem, RoomUnit roomUnit, THashSet<RoomTile> occupiedTiles, int carryMode) {
if (roomUnit == null
|| roomUnit.getRoomUnitType() != RoomUnitType.USER
|| roomUnit.getCurrentLocation() == null
|| !roomUnit.isInRoom()
|| roomUnit.isWalking()) {
return false;
}
Habbo habbo = room.getHabbo(roomUnit);
if (habbo != null && habbo.getHabboInfo() != null && habbo.getHabboInfo().getRiding() != null) {
return false;
}
if (!occupiesMovingFurni(occupiedTiles, roomUnit)) {
return false;
}
if (carryMode == WiredExtraMoveCarryUsers.MODE_DIRECTLY_ON_FURNI) {
return isDirectlyOnMovingFurni(room, movingItem, roomUnit);
}
return true;
}
private static boolean isDirectlyOnMovingFurni(Room room, HabboItem movingItem, RoomUnit roomUnit) {
HabboItem topItem = room.getTopItemAt(roomUnit.getX(), roomUnit.getY());
if (topItem == movingItem) {
return true;
}
double carrySurfaceZ = getCarrySurfaceZ(movingItem, roomUnit, roomUnit.getZ());
return Math.abs(roomUnit.getZ() - carrySurfaceZ) <= DIRECT_HEIGHT_TOLERANCE;
}
private static boolean occupiesMovingFurni(THashSet<RoomTile> occupiedTiles, RoomUnit roomUnit) {
for (RoomTile occupiedTile : occupiedTiles) {
if (occupiedTile != null
&& occupiedTile.x == roomUnit.getX()
&& occupiedTile.y == roomUnit.getY()) {
return true;
}
}
return false;
}
private static FurnitureMovementError getBlockingUnitError(Room room, HabboItem movingItem, RoomTile targetTile, int rotation, CarryContext carryContext, WiredMovementPhysics movementPhysics) {
THashSet<RoomTile> occupiedTiles = room.getLayout().getTilesAt(
targetTile,
movingItem.getBaseItem().getWidth(),
movingItem.getBaseItem().getLength(),
rotation);
if (occupiedTiles == null || occupiedTiles.isEmpty()) {
return FurnitureMovementError.NONE;
}
for (RoomTile tile : occupiedTiles) {
for (RoomUnit roomUnit : room.getRoomUnits(tile)) {
if (roomUnit == null || carryContext.carriedUserIds.contains(roomUnit.getId())) {
continue;
}
if (movementPhysics.shouldIgnoreUser(roomUnit)) {
continue;
}
switch (roomUnit.getRoomUnitType()) {
case BOT:
return FurnitureMovementError.TILE_HAS_BOTS;
case PET:
return FurnitureMovementError.TILE_HAS_PETS;
case USER:
default:
return FurnitureMovementError.TILE_HAS_HABBOS;
}
}
}
return FurnitureMovementError.NONE;
}
private static void sendAnimatedMove(Room room, HabboItem movingItem, RoomTile oldLocation, double oldZ, RoomTile targetTile, int rotation, CarryContext carryContext, int animationDuration) {
List<CarriedUnitMove> carriedMoves = getCarriedUnitMoves(room, movingItem, targetTile, rotation, carryContext);
List<WiredMovementsComposer.MovementData> movements = new ArrayList<>();
movements.add(WiredMovementsComposer.furniMovement(
movingItem.getId(),
oldLocation.x,
oldLocation.y,
targetTile.x,
targetTile.y,
oldZ,
movingItem.getZ(),
movingItem.getRotation(),
animationDuration));
for (CarriedUnitMove carriedMove : carriedMoves) {
suppressStatusComposer(carriedMove.roomUnit, animationDuration);
movements.add(WiredMovementsComposer.userSlideMovement(
carriedMove.roomUnit.getId(),
carriedMove.oldLocation.x,
carriedMove.oldLocation.y,
carriedMove.destinationTile.x,
carriedMove.destinationTile.y,
carriedMove.oldZ,
carriedMove.newZ,
carriedMove.roomUnit.getBodyRotation().getValue(),
carriedMove.roomUnit.getHeadRotation().getValue(),
animationDuration));
}
room.sendComposer(new WiredMovementsComposer(movements).compose());
for (CarriedUnitMove carriedMove : carriedMoves) {
updateCarriedUnitState(carriedMove);
}
}
private static void applyInstantCarryState(Room room, HabboItem movingItem, RoomTile targetTile, int rotation, CarryContext carryContext) {
if (!carryContext.active || room == null || movingItem == null || targetTile == null) {
return;
}
List<CarriedUnitMove> carriedMoves = getCarriedUnitMoves(room, movingItem, targetTile, rotation, carryContext);
for (CarriedUnitMove carriedMove : carriedMoves) {
updateCarriedUnitStateInstant(carriedMove);
Habbo habbo = room.getHabbo(carriedMove.roomUnit);
if (habbo != null && shouldRefreshPostureWithTileUpdate(carriedMove.roomUnit)) {
THashSet<Habbo> movedHabbos = new THashSet<>();
movedHabbos.add(habbo);
room.updateHabbosAt(carriedMove.destinationTile.x, carriedMove.destinationTile.y, movedHabbos);
}
room.sendComposer(new RoomUserStatusComposer(carriedMove.roomUnit).compose());
}
}
private static List<CarriedUnitMove> getCarriedUnitMoves(Room room, HabboItem movingItem, RoomTile targetTile, int rotation, CarryContext carryContext) {
List<CarriedUnitMove> carriedMoves = new ArrayList<>();
if (!carryContext.active) {
return carriedMoves;
}
THashSet<RoomTile> occupiedTiles = room.getLayout().getTilesAt(
targetTile,
movingItem.getBaseItem().getWidth(),
movingItem.getBaseItem().getLength(),
rotation);
for (CarriedRoomUnit carriedRoomUnit : carryContext.carriedUsers) {
RoomUnit roomUnit = carriedRoomUnit.roomUnit;
if (roomUnit == null || roomUnit.getCurrentLocation() == null || roomUnit.isWalking()) {
continue;
}
RoomTile destinationTile = room.getLayout().getTile(
(short) (targetTile.x + carriedRoomUnit.relativeX),
(short) (targetTile.y + carriedRoomUnit.relativeY));
if (destinationTile == null || destinationTile.state == null || !occupiedTiles.contains(destinationTile)) {
destinationTile = targetTile;
}
double carrySurfaceZ = getCarrySurfaceZ(movingItem, roomUnit, carriedRoomUnit.oldZ);
double newZ = carrySurfaceZ + carriedRoomUnit.heightOffset;
carriedMoves.add(new CarriedUnitMove(roomUnit, carriedRoomUnit.oldLocation, carriedRoomUnit.oldZ, destinationTile, newZ));
}
return carriedMoves;
}
private static boolean shouldRefreshPostureWithTileUpdate(RoomUnit roomUnit) {
return roomUnit != null
&& (roomUnit.hasStatus(RoomUnitStatus.SIT) || roomUnit.hasStatus(RoomUnitStatus.LAY));
}
private static double getCarrySurfaceZ(HabboItem movingItem, RoomUnit roomUnit, double referenceZ) {
if (movingItem == null) {
return referenceZ;
}
double baseZ = movingItem.getZ();
double topZ = baseZ + Item.getCurrentHeight(movingItem);
if (roomUnit != null && (roomUnit.hasStatus(RoomUnitStatus.SIT) || roomUnit.hasStatus(RoomUnitStatus.LAY))) {
return baseZ;
}
if (movingItem.getBaseItem().allowSit() || movingItem.getBaseItem().allowLay()) {
return (Math.abs(referenceZ - baseZ) <= Math.abs(referenceZ - topZ)) ? baseZ : topZ;
}
return topZ;
}
private static void updateCarriedUnitState(CarriedUnitMove carriedMove) {
carriedMove.roomUnit.setLocation(carriedMove.destinationTile);
carriedMove.roomUnit.setZ(carriedMove.newZ);
carriedMove.roomUnit.setLastRollerTime(System.currentTimeMillis());
carriedMove.roomUnit.setPreviousLocation(carriedMove.destinationTile);
carriedMove.roomUnit.setPreviousLocationZ(carriedMove.newZ);
if (carriedMove.roomUnit.hasStatus(RoomUnitStatus.SIT)) {
carriedMove.roomUnit.sitUpdate = true;
}
}
private static void updateCarriedUnitStateInstant(CarriedUnitMove carriedMove) {
carriedMove.roomUnit.setLocation(carriedMove.destinationTile);
carriedMove.roomUnit.setZ(carriedMove.newZ);
carriedMove.roomUnit.setPreviousLocation(carriedMove.destinationTile);
carriedMove.roomUnit.setPreviousLocationZ(carriedMove.newZ);
carriedMove.roomUnit.statusUpdate(false);
if (carriedMove.roomUnit.hasStatus(RoomUnitStatus.SIT)) {
carriedMove.roomUnit.sitUpdate = true;
}
}
private static void suppressStatusComposer(RoomUnit roomUnit, int duration) {
if (roomUnit == null) {
return;
}
long suppressedUntil = System.currentTimeMillis() + Math.max(duration, WiredMovementsComposer.DEFAULT_DURATION) + STATUS_SUPPRESSION_GRACE_MS;
SUPPRESSED_STATUS_COMPOSER_UNTIL.put(roomUnit.getId(), suppressedUntil);
}
private static WiredExtraMoveCarryUsers getActiveExtra(Room room, HabboItem stackItem) {
THashSet<InteractionWiredExtra> extras = getMovementExtras(room, stackItem);
if (extras == null || extras.isEmpty()) {
return null;
}
for (InteractionWiredExtra extra : extras) {
if (extra instanceof WiredExtraMoveCarryUsers) {
return (WiredExtraMoveCarryUsers) extra;
}
}
return null;
}
private static WiredExtraMoveNoAnimation getNoAnimationExtra(Room room, HabboItem stackItem) {
THashSet<InteractionWiredExtra> extras = getMovementExtras(room, stackItem);
if (extras == null || extras.isEmpty()) {
return null;
}
for (InteractionWiredExtra extra : extras) {
if (extra instanceof WiredExtraMoveNoAnimation) {
return (WiredExtraMoveNoAnimation) extra;
}
}
return null;
}
private static WiredExtraAnimationTime getAnimationTimeExtra(Room room, HabboItem stackItem) {
THashSet<InteractionWiredExtra> extras = getMovementExtras(room, stackItem);
if (extras == null || extras.isEmpty()) {
return null;
}
for (InteractionWiredExtra extra : extras) {
if (extra instanceof WiredExtraAnimationTime) {
return (WiredExtraAnimationTime) extra;
}
}
return null;
}
private static WiredMovementPhysics getMovementPhysics(Room room, HabboItem stackItem, HabboItem movingItem, WiredContext ctx) {
WiredExtraMovePhysics extra = getMovementPhysicsExtra(room, stackItem);
if (extra == null) {
return WiredMovementPhysics.NONE;
}
HashSet<Integer> passThroughFurniIds = new HashSet<>();
HashSet<Integer> passThroughUserIds = new HashSet<>();
HashSet<Integer> blockingFurniIds = new HashSet<>();
if (extra.isMoveThroughFurni()) {
for (HabboItem item : resolveFurniSources(room, ctx, extra.getMoveThroughFurniSource())) {
if (item != null && item != movingItem) {
passThroughFurniIds.add(item.getId());
}
}
}
if (extra.isMoveThroughUsers()) {
for (RoomUnit roomUnit : resolvePhysicsUsers(room, ctx, extra.getMoveThroughUsersSource())) {
if (roomUnit != null && roomUnit.getRoomUnitType() == RoomUnitType.USER) {
passThroughUserIds.add(roomUnit.getId());
}
}
}
if (extra.isBlockByFurni()) {
for (HabboItem item : resolveFurniSources(room, ctx, extra.getBlockByFurniSource())) {
if (item != null && item != movingItem) {
blockingFurniIds.add(item.getId());
}
}
}
return new WiredMovementPhysics(extra.isKeepAltitude(), passThroughFurniIds, passThroughUserIds, blockingFurniIds);
}
private static Collection<HabboItem> resolveFurniSources(Room room, WiredContext ctx, int sourceType) {
if (room == null) {
return new ArrayList<>();
}
if (sourceType == WiredExtraMovePhysics.SOURCE_ALL_ROOM) {
return new ArrayList<>(room.getFloorItems());
}
if (ctx == null) {
return new ArrayList<>();
}
return WiredSourceUtil.resolveItems(ctx, sourceType, null);
}
private static Collection<RoomUnit> resolvePhysicsUsers(Room room, WiredContext ctx, int userSource) {
if (room == null) {
return new ArrayList<>();
}
if (userSource == WiredExtraMovePhysics.SOURCE_ALL_ROOM) {
return new ArrayList<>(room.getRoomUnits());
}
if (ctx == null) {
return new ArrayList<>();
}
return WiredSourceUtil.resolveUsers(ctx, userSource);
}
private static WiredExtraMovePhysics getMovementPhysicsExtra(Room room, HabboItem stackItem) {
THashSet<InteractionWiredExtra> extras = getMovementExtras(room, stackItem);
if (extras == null || extras.isEmpty()) {
return null;
}
for (InteractionWiredExtra extra : extras) {
if (extra instanceof WiredExtraMovePhysics) {
return (WiredExtraMovePhysics) extra;
}
}
return null;
}
private static THashSet<InteractionWiredExtra> getMovementExtras(Room room, HabboItem stackItem) {
if (room == null || stackItem == null || room.getRoomSpecialTypes() == null) {
return null;
}
THashSet<InteractionWiredExtra> extras = room.getRoomSpecialTypes().getExtras(stackItem.getX(), stackItem.getY());
if (extras == null || extras.isEmpty()) {
return null;
}
return extras;
}
private static final class CarryContext {
private final boolean active;
private final List<CarriedRoomUnit> carriedUsers;
private final HashSet<Integer> carriedUserIds;
private CarryContext(boolean active, List<CarriedRoomUnit> carriedUsers, HashSet<Integer> carriedUserIds) {
this.active = active;
this.carriedUsers = carriedUsers;
this.carriedUserIds = carriedUserIds;
}
private static CarryContext disabled() {
return new CarryContext(false, new ArrayList<>(), new HashSet<>());
}
}
private static final class CarriedRoomUnit {
private final RoomUnit roomUnit;
private final RoomTile oldLocation;
private final double oldZ;
private final double heightOffset;
private final int relativeX;
private final int relativeY;
private CarriedRoomUnit(RoomUnit roomUnit, RoomTile oldLocation, double oldZ, double heightOffset, int relativeX, int relativeY) {
this.roomUnit = roomUnit;
this.oldLocation = oldLocation;
this.oldZ = oldZ;
this.heightOffset = heightOffset;
this.relativeX = relativeX;
this.relativeY = relativeY;
}
}
private static final class CarriedUnitMove {
private final RoomUnit roomUnit;
private final RoomTile oldLocation;
private final double oldZ;
private final RoomTile destinationTile;
private final double newZ;
private CarriedUnitMove(RoomUnit roomUnit, RoomTile oldLocation, double oldZ, RoomTile destinationTile, double newZ) {
this.roomUnit = roomUnit;
this.oldLocation = oldLocation;
this.oldZ = oldZ;
this.destinationTile = destinationTile;
this.newZ = newZ;
}
}
}
@@ -0,0 +1,56 @@
package com.eu.habbo.habbohotel.wired.core;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.rooms.RoomUnitType;
import com.eu.habbo.habbohotel.users.HabboItem;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public final class WiredMovementPhysics {
public static final WiredMovementPhysics NONE = new WiredMovementPhysics(false, Collections.emptySet(), Collections.emptySet(), Collections.emptySet());
private final boolean keepAltitude;
private final Set<Integer> passThroughFurniIds;
private final Set<Integer> passThroughUserIds;
private final Set<Integer> blockingFurniIds;
public WiredMovementPhysics(boolean keepAltitude, Set<Integer> passThroughFurniIds, Set<Integer> passThroughUserIds, Set<Integer> blockingFurniIds) {
this.keepAltitude = keepAltitude;
this.passThroughFurniIds = Collections.unmodifiableSet(new HashSet<>(passThroughFurniIds));
this.passThroughUserIds = Collections.unmodifiableSet(new HashSet<>(passThroughUserIds));
this.blockingFurniIds = Collections.unmodifiableSet(new HashSet<>(blockingFurniIds));
}
public boolean isKeepAltitude() {
return this.keepAltitude;
}
public boolean isActive() {
return this.keepAltitude
|| !this.passThroughFurniIds.isEmpty()
|| !this.passThroughUserIds.isEmpty()
|| !this.blockingFurniIds.isEmpty();
}
public boolean hasBlockingFurni() {
return !this.blockingFurniIds.isEmpty();
}
public boolean shouldIgnoreFurni(HabboItem item) {
return item != null
&& this.passThroughFurniIds.contains(item.getId())
&& !this.blockingFurniIds.contains(item.getId());
}
public boolean isBlockingFurni(HabboItem item) {
return item != null && this.blockingFurniIds.contains(item.getId());
}
public boolean shouldIgnoreUser(RoomUnit roomUnit) {
return roomUnit != null
&& roomUnit.getRoomUnitType() == RoomUnitType.USER
&& this.passThroughUserIds.contains(roomUnit.getId());
}
}
@@ -1,7 +1,15 @@
package com.eu.habbo.habbohotel.wired.core;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterFurni;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterUser;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.wired.api.IWiredEffect;
import gnu.trove.set.hash.THashSet;
import java.util.ArrayList;
import java.util.Collection;
@@ -24,8 +32,9 @@ public final class WiredSourceUtil {
case SOURCE_SELECTED:
return (selectedItems != null) ? new ArrayList<>(selectedItems) : Collections.emptyList();
case SOURCE_SELECTOR:
return ctx.targets().isItemsModifiedBySelector()
? new ArrayList<>(ctx.targets().items())
WiredTargets itemTargets = getSelectorTargets(ctx);
return itemTargets.isItemsModifiedBySelector()
? new ArrayList<>(itemTargets.items())
: Collections.emptyList();
case SOURCE_SIGNAL:
if (ctx.eventType() == WiredEvent.Type.SIGNAL_RECEIVED) {
@@ -48,8 +57,9 @@ public final class WiredSourceUtil {
case SOURCE_SELECTED:
return (selectedUsers != null) ? new ArrayList<>(selectedUsers) : Collections.emptyList();
case SOURCE_SELECTOR:
return ctx.targets().isUsersModifiedBySelector()
? new ArrayList<>(ctx.targets().users())
WiredTargets userTargets = getSelectorTargets(ctx);
return userTargets.isUsersModifiedBySelector()
? new ArrayList<>(userTargets.users())
: Collections.emptyList();
case SOURCE_SIGNAL:
if (ctx.eventType() == WiredEvent.Type.SIGNAL_RECEIVED) {
@@ -60,4 +70,147 @@ public final class WiredSourceUtil {
return ctx.actor().map(Collections::singletonList).orElse(Collections.emptyList());
}
}
private static WiredTargets getSelectorTargets(WiredContext ctx) {
if (ctx == null) {
return new WiredTargets();
}
if (ctx.targets().isItemsModifiedBySelector() || ctx.targets().isUsersModifiedBySelector()) {
return ctx.targets();
}
WiredContext selectorContext = executeSelectors(ctx);
if (selectorContext == null) {
return ctx.targets();
}
if (selectorContext.targets().isItemsModifiedBySelector()) {
ctx.targets().setItems(selectorContext.targets().items());
}
if (selectorContext.targets().isUsersModifiedBySelector()) {
ctx.targets().setUsers(selectorContext.targets().users());
}
return ctx.targets();
}
private static WiredContext executeSelectors(WiredContext originalCtx) {
if (originalCtx == null) {
return null;
}
Room room = originalCtx.room();
HabboItem triggerItem = originalCtx.triggerItem();
if (room == null || triggerItem == null || room.getRoomSpecialTypes() == null) {
return null;
}
WiredContext selectorCtx = new WiredContext(
originalCtx.event(),
triggerItem,
originalCtx.stack(),
originalCtx.services(),
new WiredState(100),
originalCtx.legacySettings()
);
List<InteractionWiredEffect> selectorEffects = getOrderedSelectorEffects(originalCtx, room, triggerItem);
for (InteractionWiredEffect effect : selectorEffects) {
if (effect.requiresActor() && !selectorCtx.hasActor()) {
continue;
}
try {
selectorCtx.state().step();
effect.execute(selectorCtx);
} catch (Exception ignored) {
}
}
applySelectionFilterExtras(room, triggerItem, selectorCtx);
return selectorCtx;
}
private static List<InteractionWiredEffect> getOrderedSelectorEffects(WiredContext originalCtx, Room room, HabboItem triggerItem) {
List<InteractionWiredEffect> selectorEffects = new ArrayList<>();
if (originalCtx != null && originalCtx.hasStack()) {
for (IWiredEffect effect : originalCtx.stack().effects()) {
if (effect instanceof InteractionWiredEffect && effect.isSelector()) {
selectorEffects.add((InteractionWiredEffect) effect);
}
}
if (!selectorEffects.isEmpty()) {
return selectorEffects;
}
}
THashSet<InteractionWiredEffect> roomEffects = room.getRoomSpecialTypes().getEffects(triggerItem.getX(), triggerItem.getY());
for (InteractionWiredEffect effect : WiredExecutionOrderUtil.sort(roomEffects)) {
if (effect != null && effect.isSelector()) {
selectorEffects.add(effect);
}
}
return selectorEffects;
}
private static void applySelectionFilterExtras(Room room, HabboItem triggerItem, WiredContext selectorCtx) {
if (room == null || triggerItem == null || selectorCtx == null || room.getRoomSpecialTypes() == null) {
return;
}
THashSet<InteractionWiredExtra> extras = room.getRoomSpecialTypes().getExtras(triggerItem.getX(), triggerItem.getY());
if (extras == null || extras.isEmpty()) {
return;
}
int furniLimit = Integer.MAX_VALUE;
int userLimit = Integer.MAX_VALUE;
for (InteractionWiredExtra extra : extras) {
if (extra instanceof WiredExtraFilterFurni) {
furniLimit = Math.min(furniLimit, ((WiredExtraFilterFurni) extra).getAmount());
} else if (extra instanceof WiredExtraFilterUser) {
userLimit = Math.min(userLimit, ((WiredExtraFilterUser) extra).getAmount());
}
}
if (selectorCtx.targets().isItemsModifiedBySelector() && furniLimit != Integer.MAX_VALUE) {
selectorCtx.targets().setItems(limitIterable(selectorCtx.targets().items(), furniLimit));
}
if (selectorCtx.targets().isUsersModifiedBySelector() && userLimit != Integer.MAX_VALUE) {
selectorCtx.targets().setUsers(limitIterable(selectorCtx.targets().users(), userLimit));
}
}
private static <T> List<T> limitIterable(Iterable<T> values, int limit) {
List<T> result = new ArrayList<>();
if (values == null || limit <= 0) {
return result;
}
for (T value : values) {
if (value != null) {
result.add(value);
}
}
if (result.size() <= limit) {
return result;
}
Collections.shuffle(result, Emulator.getRandom());
return new ArrayList<>(result.subList(0, limit));
}
}
@@ -1,7 +1,10 @@
package com.eu.habbo.habbohotel.wired.core;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterFurni;
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterUser;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.users.HabboItem;
@@ -120,18 +123,9 @@ public final class WiredTriggerSourceUtil {
return null;
}
THashSet<InteractionWiredEffect> effects = room.getRoomSpecialTypes().getEffects(trigger.getX(), trigger.getY());
if (effects == null || effects.isEmpty()) {
return null;
}
WiredContext ctx = new WiredContext(event, trigger, DefaultWiredServices.getInstance(), new WiredState(100));
for (InteractionWiredEffect effect : effects) {
if (effect == null || !effect.isSelector()) {
continue;
}
for (InteractionWiredEffect effect : getOrderedSelectorEffects(room, trigger)) {
if (effect.requiresActor() && !ctx.hasActor()) {
continue;
}
@@ -143,6 +137,76 @@ public final class WiredTriggerSourceUtil {
}
}
applySelectionFilterExtras(room, trigger, ctx);
return ctx;
}
private static List<InteractionWiredEffect> getOrderedSelectorEffects(Room room, InteractionWiredTrigger trigger) {
if (room == null || trigger == null || room.getRoomSpecialTypes() == null) {
return Collections.emptyList();
}
THashSet<InteractionWiredEffect> effects = room.getRoomSpecialTypes().getEffects(trigger.getX(), trigger.getY());
List<InteractionWiredEffect> selectorEffects = new ArrayList<>();
for (InteractionWiredEffect effect : WiredExecutionOrderUtil.sort(effects)) {
if (effect != null && effect.isSelector()) {
selectorEffects.add(effect);
}
}
return selectorEffects;
}
private static void applySelectionFilterExtras(Room room, HabboItem triggerItem, WiredContext selectorCtx) {
if (room == null || triggerItem == null || selectorCtx == null || room.getRoomSpecialTypes() == null) {
return;
}
THashSet<InteractionWiredExtra> extras = room.getRoomSpecialTypes().getExtras(triggerItem.getX(), triggerItem.getY());
if (extras == null || extras.isEmpty()) {
return;
}
int furniLimit = Integer.MAX_VALUE;
int userLimit = Integer.MAX_VALUE;
for (InteractionWiredExtra extra : extras) {
if (extra instanceof WiredExtraFilterFurni) {
furniLimit = Math.min(furniLimit, ((WiredExtraFilterFurni) extra).getAmount());
} else if (extra instanceof WiredExtraFilterUser) {
userLimit = Math.min(userLimit, ((WiredExtraFilterUser) extra).getAmount());
}
}
if (selectorCtx.targets().isItemsModifiedBySelector() && furniLimit != Integer.MAX_VALUE) {
selectorCtx.targets().setItems(limitIterable(selectorCtx.targets().items(), furniLimit));
}
if (selectorCtx.targets().isUsersModifiedBySelector() && userLimit != Integer.MAX_VALUE) {
selectorCtx.targets().setUsers(limitIterable(selectorCtx.targets().users(), userLimit));
}
}
private static <T> List<T> limitIterable(Iterable<T> values, int limit) {
List<T> result = new ArrayList<>();
if (values == null || limit <= 0) {
return result;
}
for (T value : values) {
if (value != null) {
result.add(value);
}
}
if (result.size() <= limit) {
return result;
}
return new ArrayList<>(result.subList(0, limit));
}
}
@@ -0,0 +1,305 @@
package com.eu.habbo.habbohotel.wired.core;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.items.interactions.InteractionRoller;
import com.eu.habbo.habbohotel.rooms.Room;
import com.eu.habbo.habbohotel.rooms.RoomTile;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
import com.eu.habbo.habbohotel.rooms.RoomUserRotation;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.messages.outgoing.rooms.WiredMovementsComposer;
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserStatusComposer;
import gnu.trove.set.hash.THashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public final class WiredUserMovementHelper {
public static final int DEFAULT_ANIMATION_DURATION = WiredMovementsComposer.DEFAULT_DURATION;
private static final int STATUS_SUPPRESSION_GRACE_MS = 250;
private static final Logger LOGGER = LoggerFactory.getLogger(WiredUserMovementHelper.class);
private static final ThreadLocal<Set<Integer>> SUPPRESSED_STATUS_ROOM_UNIT_IDS = new ThreadLocal<>();
private static final ConcurrentHashMap<Integer, Long> SUPPRESSED_STATUS_COMPOSER_UNTIL = new ConcurrentHashMap<>();
private WiredUserMovementHelper() {
}
public static boolean moveUser(Room room, RoomUnit roomUnit, RoomTile targetTile, double targetZ, int duration) {
return moveUser(room, roomUnit, targetTile, targetZ, roomUnit == null ? null : roomUnit.getBodyRotation(),
roomUnit == null ? null : roomUnit.getHeadRotation(), duration, false);
}
public static boolean moveUser(Room room, RoomUnit roomUnit, RoomTile targetTile, double targetZ, RoomUserRotation bodyRotation, RoomUserRotation headRotation, int duration) {
return moveUser(room, roomUnit, targetTile, targetZ, bodyRotation, headRotation, duration, false);
}
public static boolean moveUser(Room room, RoomUnit roomUnit, RoomTile targetTile, double targetZ, RoomUserRotation bodyRotation, RoomUserRotation headRotation, int duration, boolean noAnimation) {
if (room == null || roomUnit == null || targetTile == null || room.getLayout() == null) {
return false;
}
RoomTile oldLocation = roomUnit.getCurrentLocation();
if (oldLocation == null || hasBlockingUnits(room, roomUnit, targetTile)) {
return false;
}
RoomUserRotation resolvedBodyRotation = bodyRotation == null ? roomUnit.getBodyRotation() : bodyRotation;
RoomUserRotation resolvedHeadRotation = headRotation == null ? roomUnit.getHeadRotation() : headRotation;
double oldZ = roomUnit.getZ();
HabboItem oldTopItem = room.getTopItemAt(oldLocation.x, oldLocation.y);
HabboItem newTopItem = room.getTopItemAt(targetTile.x, targetTile.y);
Habbo habbo = room.getHabbo(roomUnit);
int animationDuration = Math.max(1, duration);
if (noAnimation) {
return moveUserInstant(room, roomUnit, targetTile, targetZ, resolvedBodyRotation, resolvedHeadRotation, oldLocation, oldTopItem, newTopItem, habbo);
}
runWithSuppressedStatusUpdates(Collections.singletonList(roomUnit), () -> {
roomUnit.setPreviousLocation(oldLocation);
roomUnit.setCurrentLocation(targetTile);
roomUnit.removeStatus(RoomUnitStatus.MOVE);
roomUnit.setZ(targetZ);
roomUnit.setBodyRotation(resolvedBodyRotation);
roomUnit.setHeadRotation(resolvedHeadRotation);
roomUnit.stopWalking();
roomUnit.resetIdleTimer();
if (habbo != null) {
THashSet<Habbo> movedHabbos = new THashSet<>();
movedHabbos.add(habbo);
room.updateHabbosAt(targetTile.x, targetTile.y, movedHabbos);
}
roomUnit.statusUpdate(false);
});
List<WiredMovementsComposer.MovementData> movements = new ArrayList<>();
movements.add(WiredMovementsComposer.userSlideMovement(
roomUnit.getId(),
oldLocation.x,
oldLocation.y,
targetTile.x,
targetTile.y,
oldZ,
roomUnit.getZ(),
resolvedBodyRotation.getValue(),
resolvedHeadRotation.getValue(),
animationDuration));
suppressStatusComposer(roomUnit, animationDuration);
room.sendComposer(new WiredMovementsComposer(movements).compose());
roomUnit.setPreviousLocation(targetTile);
roomUnit.setPreviousLocationZ(roomUnit.getZ());
scheduleTileCallbacks(room, roomUnit, oldLocation, targetTile, oldTopItem, newTopItem, animationDuration);
schedulePostureSync(room, roomUnit, targetTile, animationDuration);
return true;
}
public static boolean updateUserDirection(Room room, RoomUnit roomUnit, RoomUserRotation bodyRotation, RoomUserRotation headRotation) {
if (room == null || roomUnit == null) {
return false;
}
RoomUserRotation resolvedBodyRotation = bodyRotation == null ? roomUnit.getBodyRotation() : bodyRotation;
RoomUserRotation resolvedHeadRotation = headRotation == null ? roomUnit.getHeadRotation() : headRotation;
roomUnit.setBodyRotation(resolvedBodyRotation);
roomUnit.setHeadRotation(resolvedHeadRotation);
room.sendComposer(new WiredMovementsComposer(Collections.singletonList(
WiredMovementsComposer.userDirectionUpdate(
roomUnit.getId(),
resolvedHeadRotation.getValue(),
resolvedBodyRotation.getValue()))).compose());
return true;
}
public static boolean shouldSuppressStatusUpdate(RoomUnit roomUnit) {
if (roomUnit == null) {
return false;
}
Set<Integer> suppressedRoomUnitIds = SUPPRESSED_STATUS_ROOM_UNIT_IDS.get();
return suppressedRoomUnitIds != null && suppressedRoomUnitIds.contains(roomUnit.getId());
}
public static boolean shouldSuppressStatusComposer(RoomUnit roomUnit) {
if (roomUnit == null) {
return false;
}
Long suppressedUntil = SUPPRESSED_STATUS_COMPOSER_UNTIL.get(roomUnit.getId());
if (suppressedUntil == null) {
return false;
}
if (suppressedUntil <= System.currentTimeMillis()) {
SUPPRESSED_STATUS_COMPOSER_UNTIL.remove(roomUnit.getId(), suppressedUntil);
return false;
}
return true;
}
public static void clearStatusComposerSuppression(RoomUnit roomUnit) {
if (roomUnit == null) {
return;
}
SUPPRESSED_STATUS_COMPOSER_UNTIL.remove(roomUnit.getId());
}
private static boolean hasBlockingUnits(Room room, RoomUnit roomUnit, RoomTile targetTile) {
Collection<RoomUnit> units = room.getRoomUnitsAt(targetTile);
if (units == null || units.isEmpty()) {
return false;
}
for (RoomUnit targetUnit : units) {
if (targetUnit != null && targetUnit != roomUnit) {
return true;
}
}
return false;
}
private static boolean moveUserInstant(Room room, RoomUnit roomUnit, RoomTile targetTile, double targetZ, RoomUserRotation bodyRotation, RoomUserRotation headRotation, RoomTile oldLocation, HabboItem oldTopItem, HabboItem newTopItem, Habbo habbo) {
runWithSuppressedStatusUpdates(Collections.singletonList(roomUnit), () -> {
roomUnit.setPreviousLocation(oldLocation);
roomUnit.setCurrentLocation(targetTile);
roomUnit.removeStatus(RoomUnitStatus.MOVE);
roomUnit.setZ(targetZ);
roomUnit.setBodyRotation(bodyRotation);
roomUnit.setHeadRotation(headRotation);
roomUnit.stopWalking();
roomUnit.resetIdleTimer();
if (habbo != null) {
THashSet<Habbo> movedHabbos = new THashSet<>();
movedHabbos.add(habbo);
room.updateHabbosAt(targetTile.x, targetTile.y, movedHabbos);
}
roomUnit.setPreviousLocation(targetTile);
roomUnit.setPreviousLocationZ(roomUnit.getZ());
roomUnit.statusUpdate(false);
});
processTileCallbacks(room, roomUnit, oldLocation, targetTile, oldTopItem, newTopItem);
room.sendComposer(new RoomUserStatusComposer(roomUnit).compose());
return true;
}
private static void scheduleTileCallbacks(Room room, RoomUnit roomUnit, RoomTile oldLocation, RoomTile targetTile, HabboItem oldTopItem, HabboItem newTopItem, int delay) {
if (oldTopItem == null && newTopItem == null) {
return;
}
Emulator.getThreading().run(() -> {
processTileCallbacks(room, roomUnit, oldLocation, targetTile, oldTopItem, newTopItem);
}, Math.max(delay, InteractionRoller.DELAY));
}
private static void processTileCallbacks(Room room, RoomUnit roomUnit, RoomTile oldLocation, RoomTile targetTile, HabboItem oldTopItem, HabboItem newTopItem) {
if (room == null || !room.isLoaded() || roomUnit == null || roomUnit.getCurrentLocation() == null) {
return;
}
if (roomUnit.getCurrentLocation().x != targetTile.x || roomUnit.getCurrentLocation().y != targetTile.y) {
return;
}
if (oldTopItem != null && oldTopItem != newTopItem) {
try {
oldTopItem.onWalkOff(roomUnit, room, new Object[]{oldLocation, targetTile});
} catch (Exception exception) {
LOGGER.error("Failed to process wired user walk off callback", exception);
}
}
if (newTopItem != null && newTopItem != oldTopItem) {
try {
newTopItem.onWalkOn(roomUnit, room, new Object[]{oldLocation, targetTile});
} catch (Exception exception) {
LOGGER.error("Failed to process wired user walk on callback", exception);
}
}
}
private static void schedulePostureSync(Room room, RoomUnit roomUnit, RoomTile targetTile, int delay) {
if (!roomUnit.hasStatus(RoomUnitStatus.SIT) && !roomUnit.hasStatus(RoomUnitStatus.LAY)) {
return;
}
Emulator.getThreading().run(() -> {
if (room == null || !room.isLoaded() || roomUnit == null || roomUnit.getCurrentLocation() == null) {
return;
}
if (roomUnit.getCurrentLocation().x != targetTile.x || roomUnit.getCurrentLocation().y != targetTile.y) {
return;
}
room.sendComposer(new RoomUserStatusComposer(roomUnit).compose());
}, delay + STATUS_SUPPRESSION_GRACE_MS + 25);
}
private static void suppressStatusComposer(RoomUnit roomUnit, int duration) {
if (roomUnit == null) {
return;
}
long suppressedUntil = System.currentTimeMillis() + Math.max(duration, InteractionRoller.DELAY) + STATUS_SUPPRESSION_GRACE_MS;
SUPPRESSED_STATUS_COMPOSER_UNTIL.put(roomUnit.getId(), suppressedUntil);
}
private static void runWithSuppressedStatusUpdates(Collection<RoomUnit> roomUnits, Runnable action) {
if (action == null) {
return;
}
Set<Integer> previousSuppressedRoomUnitIds = SUPPRESSED_STATUS_ROOM_UNIT_IDS.get();
HashSet<Integer> suppressedRoomUnitIds = previousSuppressedRoomUnitIds == null
? new HashSet<>()
: new HashSet<>(previousSuppressedRoomUnitIds);
if (roomUnits != null) {
for (RoomUnit roomUnit : roomUnits) {
if (roomUnit != null) {
suppressedRoomUnitIds.add(roomUnit.getId());
}
}
}
if (suppressedRoomUnitIds.isEmpty()) {
action.run();
return;
}
SUPPRESSED_STATUS_ROOM_UNIT_IDS.set(suppressedRoomUnitIds);
try {
action.run();
} finally {
if (previousSuppressedRoomUnitIds == null || previousSuppressedRoomUnitIds.isEmpty()) {
SUPPRESSED_STATUS_ROOM_UNIT_IDS.remove();
} else {
SUPPRESSED_STATUS_ROOM_UNIT_IDS.set(previousSuppressedRoomUnitIds);
}
}
}
}
@@ -41,6 +41,7 @@ public class Outgoing {
public final static int HotelViewComposer = 122;
public final static int UpdateFriendComposer = 2800;
public final static int FloorItemUpdateComposer = 3776;
public final static int WiredMovementsComposer = 3999;
public final static int RoomAccessDeniedComposer = 878;
public final static int GuildFurniWidgetComposer = 3293;
public final static int GiftConfigurationComposer = 2234;
@@ -0,0 +1,206 @@
package com.eu.habbo.messages.outgoing.rooms;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.outgoing.MessageComposer;
import com.eu.habbo.messages.outgoing.Outgoing;
import java.util.ArrayList;
import java.util.List;
public class WiredMovementsComposer extends MessageComposer {
public static final int TYPE_USER_MOVE = 0;
public static final int TYPE_FURNI_MOVE = 1;
public static final int TYPE_WALL_ITEM_MOVE = 2;
public static final int TYPE_USER_DIRECTION = 3;
public static final int USER_MOVEMENT_WALK = 0;
public static final int USER_MOVEMENT_SLIDE = 1;
public static final int DEFAULT_DURATION = 500;
private final List<MovementData> movements;
public WiredMovementsComposer(List<MovementData> movements) {
this.movements = movements == null ? new ArrayList<>() : movements;
}
@Override
protected ServerMessage composeInternal() {
this.response.init(Outgoing.WiredMovementsComposer);
this.response.appendInt(this.movements.size());
for (MovementData movement : this.movements) {
this.response.appendInt(movement.getType());
movement.append(this.response);
}
return this.response;
}
public static MovementData furniMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ) {
return furniMovement(id, fromX, fromY, toX, toY, fromZ, toZ, 0, DEFAULT_DURATION);
}
public static MovementData furniMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int rotation, int duration) {
return new FurniMovementData(id, fromX, fromY, toX, toY, fromZ, toZ, rotation, duration);
}
public static MovementData userWalkMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int bodyDirection, int headDirection, int duration) {
return new UserMovementData(id, fromX, fromY, toX, toY, fromZ, toZ, USER_MOVEMENT_WALK, bodyDirection, headDirection, duration);
}
public static MovementData userSlideMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int bodyDirection, int headDirection, int duration) {
return new UserMovementData(id, fromX, fromY, toX, toY, fromZ, toZ, USER_MOVEMENT_SLIDE, bodyDirection, headDirection, duration);
}
public static MovementData userDirectionUpdate(int id, int headDirection, int bodyDirection) {
return new UserDirectionData(id, headDirection, bodyDirection);
}
public static MovementData wallItemMovement(int id, boolean enabled, int[] values) {
return new WallItemMovementData(id, enabled, values);
}
public interface MovementData {
int getType();
void append(ServerMessage response);
}
private abstract static class BaseMovementData implements MovementData {
private final int type;
private BaseMovementData(int type) {
this.type = type;
}
@Override
public int getType() {
return this.type;
}
}
private static final class UserMovementData extends BaseMovementData {
private final int fromX;
private final int fromY;
private final int toX;
private final int toY;
private final double fromZ;
private final double toZ;
private final int id;
private final int movementType;
private final int bodyDirection;
private final int headDirection;
private final int duration;
private UserMovementData(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int movementType, int bodyDirection, int headDirection, int duration) {
super(TYPE_USER_MOVE);
this.id = id;
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
this.fromZ = fromZ;
this.toZ = toZ;
this.movementType = movementType;
this.bodyDirection = bodyDirection;
this.headDirection = headDirection;
this.duration = duration;
}
@Override
public void append(ServerMessage response) {
response.appendInt(this.fromX);
response.appendInt(this.fromY);
response.appendInt(this.toX);
response.appendInt(this.toY);
response.appendString(Double.toString(this.fromZ));
response.appendString(Double.toString(this.toZ));
response.appendInt(this.id);
response.appendInt(this.movementType);
response.appendInt(this.bodyDirection);
response.appendInt(this.headDirection);
response.appendInt(this.duration);
}
}
private static final class FurniMovementData extends BaseMovementData {
private final int fromX;
private final int fromY;
private final int toX;
private final int toY;
private final double fromZ;
private final double toZ;
private final int id;
private final int rotation;
private final int duration;
private FurniMovementData(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int rotation, int duration) {
super(TYPE_FURNI_MOVE);
this.id = id;
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
this.fromZ = fromZ;
this.toZ = toZ;
this.rotation = rotation;
this.duration = duration;
}
@Override
public void append(ServerMessage response) {
response.appendInt(this.fromX);
response.appendInt(this.fromY);
response.appendInt(this.toX);
response.appendInt(this.toY);
response.appendString(Double.toString(this.fromZ));
response.appendString(Double.toString(this.toZ));
response.appendInt(this.id);
response.appendInt(this.rotation);
response.appendInt(this.duration);
}
}
private static final class UserDirectionData extends BaseMovementData {
private final int id;
private final int headDirection;
private final int bodyDirection;
private UserDirectionData(int id, int headDirection, int bodyDirection) {
super(TYPE_USER_DIRECTION);
this.id = id;
this.headDirection = headDirection;
this.bodyDirection = bodyDirection;
}
@Override
public void append(ServerMessage response) {
response.appendInt(this.id);
response.appendInt(this.headDirection);
response.appendInt(this.bodyDirection);
}
}
private static final class WallItemMovementData extends BaseMovementData {
private final int id;
private final boolean enabled;
private final int[] values;
private WallItemMovementData(int id, boolean enabled, int[] values) {
super(TYPE_WALL_ITEM_MOVE);
this.id = id;
this.enabled = enabled;
this.values = values == null ? new int[9] : values;
}
@Override
public void append(ServerMessage response) {
response.appendInt(this.id);
response.appendBoolean(this.enabled);
for (int index = 0; index < 9; index++) {
response.appendInt(index < this.values.length ? this.values[index] : 0);
}
}
}
}
@@ -1,5 +1,7 @@
package com.eu.habbo.messages.outgoing.rooms.users;
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
import com.eu.habbo.habbohotel.wired.core.WiredUserMovementHelper;
import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
import com.eu.habbo.habbohotel.users.Habbo;
@@ -8,7 +10,9 @@ import com.eu.habbo.messages.outgoing.MessageComposer;
import com.eu.habbo.messages.outgoing.Outgoing;
import gnu.trove.set.hash.THashSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class RoomUserStatusComposer extends MessageComposer {
@@ -38,8 +42,20 @@ public class RoomUserStatusComposer extends MessageComposer {
protected ServerMessage composeInternal() {
this.response.init(Outgoing.RoomUserStatusComposer);
if (this.roomUnits != null) {
this.response.appendInt(this.roomUnits.size());
List<RoomUnit> roomUnits = new ArrayList<>();
for (RoomUnit roomUnit : this.roomUnits) {
if (roomUnit == null
|| WiredMoveCarryHelper.shouldSuppressStatusComposer(roomUnit)
|| WiredUserMovementHelper.shouldSuppressStatusComposer(roomUnit)) {
continue;
}
roomUnits.add(roomUnit);
}
this.response.appendInt(roomUnits.size());
for (RoomUnit roomUnit : roomUnits) {
this.response.appendInt(roomUnit.getId());
this.response.appendInt(roomUnit.getPreviousLocation().x);
this.response.appendInt(roomUnit.getPreviousLocation().y);
@@ -59,8 +75,21 @@ public class RoomUserStatusComposer extends MessageComposer {
}
} else {
synchronized (this.habbos) {
this.response.appendInt(this.habbos.size());
List<Habbo> habbos = new ArrayList<>();
for (Habbo habbo : this.habbos) {
if (habbo == null
|| habbo.getRoomUnit() == null
|| WiredMoveCarryHelper.shouldSuppressStatusComposer(habbo.getRoomUnit())
|| WiredUserMovementHelper.shouldSuppressStatusComposer(habbo.getRoomUnit())) {
continue;
}
habbos.add(habbo);
}
this.response.appendInt(habbos.size());
for (Habbo habbo : habbos) {
this.response.appendInt(habbo.getRoomUnit().getId());
this.response.appendInt(habbo.getRoomUnit().getPreviousLocation().x);
this.response.appendInt(habbo.getRoomUnit().getPreviousLocation().y);