🆙 Wired Highscore LONGESTTIME and Loop detection rollers

This commit is contained in:
DuckieTM 2025-02-28 23:29:42 +01:00
parent 31fd5f2b31
commit 3332bc7f9c
6 changed files with 116 additions and 5 deletions

View File

@ -8,5 +8,5 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="openjdk-21" project-jdk-type="JavaSDK" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_23" default="true" project-jdk-name="openjdk-23" project-jdk-type="JavaSDK" />
</project>

View File

@ -26,14 +26,27 @@ public class SetSpeedCommand extends Command {
return true;
}
if (newSpeed < -1 || newSpeed > Emulator.getConfig().getInt("hotel.rollers.speed.maximum")) {
// First check against the config bounds
int configMax = Emulator.getConfig().getInt("hotel.rollers.speed.maximum");
if (newSpeed < -1 || newSpeed > configMax) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_setspeed.bounds"), RoomChatMessageBubbles.ALERT);
return true;
}
// Enforce maximum speed of 10 regardless of config.
if (newSpeed > 10) {
newSpeed = 10;
gameClient.getHabbo().whisper("Speed cannot be set above 10. Setting speed to 10.", RoomChatMessageBubbles.ALERT);
}
room.setRollerSpeed(newSpeed);
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.succes.cmd_setspeed").replace("%oldspeed%", oldSpeed + "").replace("%newspeed%", newSpeed + ""), RoomChatMessageBubbles.ALERT);
gameClient.getHabbo().whisper(
Emulator.getTexts().getValue("commands.succes.cmd_setspeed")
.replace("%oldspeed%", oldSpeed + "")
.replace("%newspeed%", newSpeed + ""),
RoomChatMessageBubbles.ALERT
);
return true;
}
}

View File

@ -1237,6 +1237,32 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
final long millis = System.currentTimeMillis();
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));
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);
tracker.counter = 0;
}
} else {
tracker.update(curX, curY, curZ);
}
}
if (!foundRightHolder[0]) {
foundRightHolder[0] = habbo.getRoomUnit().getRightsLevel() != RoomRightLevels.NONE;
}
@ -1368,6 +1394,26 @@ 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;
return Double.compare(proj1, proj2);
});
if (this.rollerSpeed != -1 && this.rollerCycle >= this.rollerSpeed) {
this.rollerCycle = 0;
@ -4980,4 +5026,42 @@ 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<>();
}

View File

@ -136,6 +136,19 @@ public class WiredHighscoreManager {
.collect(Collectors.toList());
}
if (scoreType == WiredHighscoreScoreType.LONGESTTIME) {
return highscores
.collect(Collectors.groupingBy(h -> h.getUsers().hashCode()))
.entrySet()
.stream()
.map(e -> e.getValue().stream()
.max(Comparator.comparingInt(WiredHighscoreRow::getValue))
.orElse(null))
.filter(Objects::nonNull)
.sorted(Comparator.comparingInt(WiredHighscoreRow::getValue).reversed())
.collect(Collectors.toList());
}
return null;
}

View File

@ -3,7 +3,8 @@ package com.eu.habbo.habbohotel.wired.highscores;
public enum WiredHighscoreScoreType {
PERTEAM(0),
MOSTWIN(1),
CLASSIC(2);
CLASSIC(2),
LONGESTTIME(3);
public final int type;