🆙 Updated the LoopTracker for rollers

This commit is contained in:
DuckieTM 2025-03-01 21:04:37 +01:00
parent 3332bc7f9c
commit d1ff6687d6
2 changed files with 126 additions and 61 deletions

View File

@ -700,6 +700,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
} }
} }
} }
this.sendComposer(new UpdateStackHeightComposer(this, updatedTiles).compose()); this.sendComposer(new UpdateStackHeightComposer(this, updatedTiles).compose());
this.updateTiles(updatedTiles); this.updateTiles(updatedTiles);
for (RoomTile tile : updatedTiles) { for (RoomTile tile : updatedTiles) {
@ -1188,6 +1189,47 @@ public class Room implements Comparable<Room>, 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<RoomUnit, LoopTracker> 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() { private void cycle() {
this.cycleOdd = !this.cycleOdd; this.cycleOdd = !this.cycleOdd;
this.cycleTimestamp = System.currentTimeMillis(); this.cycleTimestamp = System.currentTimeMillis();
@ -1238,31 +1280,97 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
for (Habbo habbo : this.currentHabbos.values()) { for (Habbo habbo : this.currentHabbos.values()) {
RoomUnit unit = habbo.getRoomUnit(); RoomUnit unit = habbo.getRoomUnit();
// Only run loop detection if the unit is on a roller.
if (!unit.hasStatus(RoomUnitStatus.MOVE) && isOnRoller(unit)) { if (!unit.hasStatus(RoomUnitStatus.MOVE) && isOnRoller(unit)) {
double curX = unit.getX(); double curX = unit.getX();
double curY = unit.getY(); double curY = unit.getY();
double curZ = unit.getZ(); double curZ = unit.getZ();
// Get or create a loop tracker for this unit. LoopTracker tracker = loopTrackers.computeIfAbsent(unit, u -> {
LoopTracker tracker = loopTrackers.computeIfAbsent(unit, u -> new LoopTracker(curX, curY, curZ)); 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)) { if (tracker.isSamePosition(curX, curY, curZ)) {
tracker.counter++; InteractionRoller currentRoller = null;
// Compute threshold based on roller speed (max speed = 10). RoomTile currentTile = this.getLayout().getTile((short) curX, (short) curY);
int loopThreshold = Math.max(10, 3 + this.getRollerSpeed()); for (InteractionRoller roller : this.roomSpecialTypes.getRollers().values()) {
if (tracker.counter >= loopThreshold) { if (roller.getX() == currentTile.x && roller.getY() == currentTile.y) {
LOGGER.warn("Loop detected for unit id " + unit.getId() + currentRoller = roller;
" at position: x=" + curX + ", y=" + curY + ", z=" + curZ); break;
// Teleport unit back to the door tile. }
RoomTile doorTile = this.getLayout().getDoorTile(); }
this.teleportRoomUnitToLocation(unit, doorTile.x, doorTile.y, doorTile.z);
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; 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 { } 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]) { if (!foundRightHolder[0]) {
foundRightHolder[0] = habbo.getRoomUnit().getRightsLevel() != RoomRightLevels.NONE; foundRightHolder[0] = habbo.getRoomUnit().getRightsLevel() != RoomRightLevels.NONE;
} }
@ -1314,7 +1422,6 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
this.sendComposer(new RoomUserIgnoredComposer(habbo, RoomUserIgnoredComposer.UNIGNORED).compose()); 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) { if (this.cycleOdd && habbo.getHabboStats().chatCounter.get() > 0) {
habbo.getHabboStats().chatCounter.decrementAndGet(); habbo.getHabboStats().chatCounter.decrementAndGet();
} }
@ -1396,19 +1503,15 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
List<InteractionRoller> rollers = new ArrayList<>(this.roomSpecialTypes.getRollers().values()); List<InteractionRoller> 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) -> { rollers.sort((r1, r2) -> {
// Convert the roller's rotation into an angle in radians.
double angle1 = Math.toRadians(r1.getRotation() * 45); double angle1 = Math.toRadians(r1.getRotation() * 45);
double angle2 = Math.toRadians(r2.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 vx1 = Math.cos(angle1);
double vy1 = Math.sin(angle1); double vy1 = Math.sin(angle1);
double vx2 = Math.cos(angle2); double vx2 = Math.cos(angle2);
double vy2 = Math.sin(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 proj1 = r1.getX() * vx1 + r1.getY() * vy1;
double proj2 = r2.getX() * vx2 + r2.getY() * vy2; double proj2 = r2.getX() * vx2 + r2.getY() * vy2;
@ -1442,7 +1545,6 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
} }
} }
// itemsOnRoller.addAll(this.getItemsAt(rollerTile));
itemsOnRoller.remove(roller); itemsOnRoller.remove(roller);
if (!rollerTile.hasUnits() && itemsOnRoller.isEmpty()) if (!rollerTile.hasUnits() && itemsOnRoller.isEmpty())
@ -1707,7 +1809,6 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
} }
} }
private boolean cycleRoomUnit(RoomUnit unit, RoomUnitType type) { private boolean cycleRoomUnit(RoomUnit unit, RoomUnitType type) {
boolean update = unit.needsStatusUpdate(); boolean update = unit.needsStatusUpdate();
if (unit.hasStatus(RoomUnitStatus.SIGN)) { if (unit.hasStatus(RoomUnitStatus.SIGN)) {
@ -3049,6 +3150,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
return pets; return pets;
} }
public THashSet<Habbo> getHabbosAt(short x, short y) { public THashSet<Habbo> getHabbosAt(short x, short y) {
return this.getHabbosAt(this.layout.getTile(x, y)); return this.getHabbosAt(this.layout.getTile(x, y));
} }
@ -3133,8 +3235,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
roomUnit.setZ(z); roomUnit.setZ(z);
roomUnit.setPreviousLocationZ(z); roomUnit.setPreviousLocationZ(z);
this.updateRoomUnit(roomUnit); this.updateRoomUnit(roomUnit);
} }
} }
@ -4953,6 +5054,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
} }
public FurnitureMovementError slideFurniTo(HabboItem item, RoomTile tile, int rotation) { public FurnitureMovementError slideFurniTo(HabboItem item, RoomTile tile, int rotation) {
RoomTile oldLocation = this.layout.getTile(item.getX(), item.getY()); RoomTile oldLocation = this.layout.getTile(item.getX(), item.getY());
HabboItem topItem = this.getTopItemAt(tile.x, tile.y); HabboItem topItem = this.getTopItemAt(tile.x, tile.y);
@ -4976,6 +5078,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
item.setRotation(rotation); item.setRotation(rotation);
//Place at new position //Place at new position
if (magicTile) { if (magicTile) {
item.setZ(tile.z); item.setZ(tile.z);
item.setExtradata("" + item.getZ() * 100); item.setExtradata("" + item.getZ() * 100);
@ -5026,42 +5129,4 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
THashSet<RoomUnit> roomUnits = getRoomUnits(); THashSet<RoomUnit> roomUnits = getRoomUnits();
return roomUnits.stream().filter(unit -> unit.getCurrentLocation() == tile).collect(Collectors.toSet()); 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<RoomUnit, LoopTracker> loopTrackers = new ConcurrentHashMap<>();
}