🆙 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.updateTiles(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() {
this.cycleOdd = !this.cycleOdd;
this.cycleTimestamp = System.currentTimeMillis();
@ -1238,31 +1280,97 @@ public class Room implements Comparable<Room>, 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<Room>, 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<Room>, ISerialize, Runnable {
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) -> {
// 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<Room>, ISerialize, Runnable {
}
}
// itemsOnRoller.addAll(this.getItemsAt(rollerTile));
itemsOnRoller.remove(roller);
if (!rollerTile.hasUnits() && itemsOnRoller.isEmpty())
@ -1707,7 +1809,6 @@ public class Room implements Comparable<Room>, 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<Room>, ISerialize, Runnable {
return pets;
}
public THashSet<Habbo> getHabbosAt(short x, short 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.setPreviousLocationZ(z);
this.updateRoomUnit(roomUnit);
}
}
@ -4953,6 +5054,7 @@ public class Room implements Comparable<Room>, 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<Room>, 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<Room>, ISerialize, Runnable {
THashSet<RoomUnit> 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<RoomUnit, LoopTracker> loopTrackers = new ConcurrentHashMap<>();
}
}