diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java index 7156da8..8e3ef27 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java @@ -700,6 +700,7 @@ public class Room implements Comparable, ISerialize, Runnable { } } } + this.sendComposer(new UpdateStackHeightComposer(this, updatedTiles).compose()); this.updateTiles(updatedTiles); for (RoomTile tile : updatedTiles) { @@ -1188,6 +1189,47 @@ public class Room implements Comparable, ISerialize, Runnable { } } + private boolean isOnRoller(RoomUnit unit) { + RoomTile currentTile = unit.getCurrentLocation(); + // Iterate over all rollers in the room. + for (HabboItem roller : this.roomSpecialTypes.getRollers().values()) { + if (roller.getX() == currentTile.x && roller.getY() == currentTile.y) { + return true; + } + } + return false; + } + + private final Map loopTrackers = new ConcurrentHashMap<>(); + + private static class LoopTracker { + double x, y, z; + int counter; + RoomTile nextTile; + + public LoopTracker(double x, double y, double z, RoomTile nextTile) { + this.x = x; + this.y = y; + this.z = z; + this.counter = 0; + this.nextTile = nextTile; + } + + public boolean isSamePosition(double newX, double newY, double newZ) { + // Use an epsilon for double comparison if necessary. + final double EPSILON = 0.001; + return Math.abs(newX - x) < EPSILON && Math.abs(newY - y) < EPSILON && Math.abs(newZ - z) < EPSILON; + } + + public void update(double newX, double newY, double newZ, RoomTile nextTile) { + this.x = newX; + this.y = newY; + this.z = newZ; + this.counter = 0; + this.nextTile = nextTile; + } + } + private void cycle() { this.cycleOdd = !this.cycleOdd; this.cycleTimestamp = System.currentTimeMillis(); @@ -1238,31 +1280,97 @@ public class Room implements Comparable, ISerialize, Runnable { for (Habbo habbo : this.currentHabbos.values()) { RoomUnit unit = habbo.getRoomUnit(); - // Only run loop detection if the unit is on a roller. if (!unit.hasStatus(RoomUnitStatus.MOVE) && isOnRoller(unit)) { double curX = unit.getX(); double curY = unit.getY(); double curZ = unit.getZ(); - // Get or create a loop tracker for this unit. - LoopTracker tracker = loopTrackers.computeIfAbsent(unit, u -> new LoopTracker(curX, curY, curZ)); + LoopTracker tracker = loopTrackers.computeIfAbsent(unit, u -> { + RoomTile nextTile = null; + for (InteractionRoller roller : this.roomSpecialTypes.getRollers().values()) { + RoomTile rollerTile = this.getLayout().getTile((short) roller.getX(), (short) roller.getY()); + RoomTile potentialNextTile = this.getLayout().getTileInFront(rollerTile, roller.getRotation()); + if (potentialNextTile != null) { + nextTile = potentialNextTile; + break; + } + } + return new LoopTracker(curX, curY, curZ, nextTile); + }); if (tracker.isSamePosition(curX, curY, curZ)) { - tracker.counter++; - // Compute threshold based on roller speed (max speed = 10). - int loopThreshold = Math.max(10, 3 + this.getRollerSpeed()); - if (tracker.counter >= loopThreshold) { - LOGGER.warn("Loop detected for unit id " + unit.getId() + - " at position: x=" + curX + ", y=" + curY + ", z=" + curZ); - // Teleport unit back to the door tile. - RoomTile doorTile = this.getLayout().getDoorTile(); - this.teleportRoomUnitToLocation(unit, doorTile.x, doorTile.y, doorTile.z); + InteractionRoller currentRoller = null; + RoomTile currentTile = this.getLayout().getTile((short) curX, (short) curY); + for (InteractionRoller roller : this.roomSpecialTypes.getRollers().values()) { + if (roller.getX() == currentTile.x && roller.getY() == currentTile.y) { + currentRoller = roller; + break; + } + } + + RoomTile currentCalculatedNextTile = null; + if (currentRoller != null) { + RoomTile rollerTile = this.getLayout().getTile((short) currentRoller.getX(), (short) currentRoller.getY()); + currentCalculatedNextTile = this.getLayout().getTileInFront(rollerTile, currentRoller.getRotation()); + } + + if (currentTile != null && unit.getGoal() != null) { + double distanceToGoal = Math.hypot(unit.getGoal().x - currentTile.x, unit.getGoal().y - currentTile.y); + final double ACCEPTABLE_DISTANCE = 0.5; // adjust as needed + if (distanceToGoal <= ACCEPTABLE_DISTANCE) { + tracker.update(curX, curY, curZ, currentCalculatedNextTile); + tracker.counter = 0; + continue; + } + } + + boolean nextTileHasRoller = false; + if (currentCalculatedNextTile != null) { + for (InteractionRoller roller : this.roomSpecialTypes.getRollers().values()) { + if (roller.getX() == currentCalculatedNextTile.x && roller.getY() == currentCalculatedNextTile.y) { + nextTileHasRoller = true; + break; + } + } + } + + if (currentCalculatedNextTile != null && !nextTileHasRoller) { + tracker.update(curX, curY, curZ, currentCalculatedNextTile); tracker.counter = 0; + } else { + if (unit.getGoal() != null && tracker.nextTile != null && + unit.getGoal().x == tracker.nextTile.x && unit.getGoal().y == tracker.nextTile.y) { + tracker.counter = 0; + } else { + tracker.counter++; + int loopThreshold = Math.max(10, 3 + this.getRollerSpeed()); + if (tracker.counter >= loopThreshold) { + RoomTile doorTile = this.getLayout().getDoorTile(); + unit.setBodyRotation(RoomUserRotation.values()[this.getLayout().getDoorDirection()]); + unit.setHeadRotation(RoomUserRotation.values()[this.getLayout().getDoorDirection()]); + this.teleportRoomUnitToLocation(unit, doorTile.x, doorTile.y, doorTile.z); + tracker.counter = 0; + } + } } } else { - tracker.update(curX, curY, curZ); + InteractionRoller currentRoller = null; + RoomTile currentTile = this.getLayout().getTile((short) curX, (short) curY); + for (InteractionRoller roller : this.roomSpecialTypes.getRollers().values()) { + if (roller.getX() == currentTile.x && roller.getY() == currentTile.y) { + currentRoller = roller; + break; + } + } + RoomTile nextTile = null; + if (currentRoller != null) { + RoomTile rollerTile = this.getLayout().getTile((short) currentRoller.getX(), (short) currentRoller.getY()); + nextTile = this.getLayout().getTileInFront(rollerTile, currentRoller.getRotation()); + } + tracker.update(curX, curY, curZ, nextTile); } } + if (!foundRightHolder[0]) { foundRightHolder[0] = habbo.getRoomUnit().getRightsLevel() != RoomRightLevels.NONE; } @@ -1314,7 +1422,6 @@ public class Room implements Comparable, ISerialize, Runnable { this.sendComposer(new RoomUserIgnoredComposer(habbo, RoomUserIgnoredComposer.UNIGNORED).compose()); } - // Substract 1 from the chatCounter every odd cycle, which is every (500ms * 2). if (this.cycleOdd && habbo.getHabboStats().chatCounter.get() > 0) { habbo.getHabboStats().chatCounter.decrementAndGet(); } @@ -1396,19 +1503,15 @@ public class Room implements Comparable, ISerialize, Runnable { List rollers = new ArrayList<>(this.roomSpecialTypes.getRollers().values()); - // Sort rollers using a custom comparator that uses a projection of the roller's position rollers.sort((r1, r2) -> { - // Convert the roller's rotation into an angle in radians. double angle1 = Math.toRadians(r1.getRotation() * 45); double angle2 = Math.toRadians(r2.getRotation() * 45); - // Compute the movement vector for each roller (a unit vector in its direction) double vx1 = Math.cos(angle1); double vy1 = Math.sin(angle1); double vx2 = Math.cos(angle2); double vy2 = Math.sin(angle2); - // Calculate the projection of the roller's position along its movement vector double proj1 = r1.getX() * vx1 + r1.getY() * vy1; double proj2 = r2.getX() * vx2 + r2.getY() * vy2; @@ -1442,7 +1545,6 @@ public class Room implements Comparable, ISerialize, Runnable { } } - // itemsOnRoller.addAll(this.getItemsAt(rollerTile)); itemsOnRoller.remove(roller); if (!rollerTile.hasUnits() && itemsOnRoller.isEmpty()) @@ -1707,7 +1809,6 @@ public class Room implements Comparable, ISerialize, Runnable { } } - private boolean cycleRoomUnit(RoomUnit unit, RoomUnitType type) { boolean update = unit.needsStatusUpdate(); if (unit.hasStatus(RoomUnitStatus.SIGN)) { @@ -3049,6 +3150,7 @@ public class Room implements Comparable, ISerialize, Runnable { return pets; } + public THashSet getHabbosAt(short x, short y) { return this.getHabbosAt(this.layout.getTile(x, y)); } @@ -3133,8 +3235,7 @@ public class Room implements Comparable, ISerialize, Runnable { roomUnit.setZ(z); roomUnit.setPreviousLocationZ(z); this.updateRoomUnit(roomUnit); - - + } } @@ -4953,6 +5054,7 @@ public class Room implements Comparable, ISerialize, Runnable { } public FurnitureMovementError slideFurniTo(HabboItem item, RoomTile tile, int rotation) { + RoomTile oldLocation = this.layout.getTile(item.getX(), item.getY()); HabboItem topItem = this.getTopItemAt(tile.x, tile.y); @@ -4976,6 +5078,7 @@ public class Room implements Comparable, ISerialize, Runnable { item.setRotation(rotation); //Place at new position + if (magicTile) { item.setZ(tile.z); item.setExtradata("" + item.getZ() * 100); @@ -5026,42 +5129,4 @@ public class Room implements Comparable, ISerialize, Runnable { THashSet roomUnits = getRoomUnits(); return roomUnits.stream().filter(unit -> unit.getCurrentLocation() == tile).collect(Collectors.toSet()); } - - private static class LoopTracker { - double x, y, z; - int counter; - - public LoopTracker(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; - this.counter = 0; - } - - public boolean isSamePosition(double newX, double newY, double newZ) { - // Use an epsilon for double comparison if necessary. - final double EPSILON = 0.001; - return Math.abs(newX - x) < EPSILON && Math.abs(newY - y) < EPSILON && Math.abs(newZ - z) < EPSILON; - } - - public void update(double newX, double newY, double newZ) { - this.x = newX; - this.y = newY; - this.z = newZ; - this.counter = 0; - } - } - - private boolean isOnRoller(RoomUnit unit) { - RoomTile currentTile = unit.getCurrentLocation(); - // Iterate over all rollers in the room. - for (HabboItem roller : this.roomSpecialTypes.getRollers().values()) { - if (roller.getX() == currentTile.x && roller.getY() == currentTile.y) { - return true; - } - } - return false; - } - - private final Map loopTrackers = new ConcurrentHashMap<>(); -} \ No newline at end of file +} diff --git a/Latest_Compiled_Version/Habbo-3.6.0-jar-with-dependencies.jar b/Latest_Compiled_Version/Habbo-3.6.0-jar-with-dependencies.jar index ee98f69..f0017e0 100644 Binary files a/Latest_Compiled_Version/Habbo-3.6.0-jar-with-dependencies.jar and b/Latest_Compiled_Version/Habbo-3.6.0-jar-with-dependencies.jar differ