You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 15:06:19 +00:00
🆕 Brand new Floorplan
This commit is contained in:
@@ -89,6 +89,7 @@ public class HabboStats implements Runnable {
|
|||||||
public long lastTradeTimestamp = Emulator.getIntUnixTimestamp();
|
public long lastTradeTimestamp = Emulator.getIntUnixTimestamp();
|
||||||
public long lastGiftTimestamp = Emulator.getIntUnixTimestamp();
|
public long lastGiftTimestamp = Emulator.getIntUnixTimestamp();
|
||||||
public long lastPurchaseTimestamp = Emulator.getIntUnixTimestamp();
|
public long lastPurchaseTimestamp = Emulator.getIntUnixTimestamp();
|
||||||
|
public long lastFloorplanSaveTimestamp = 0;
|
||||||
public int uiFlags;
|
public int uiFlags;
|
||||||
public boolean hasGottenDefaultSavedSearches;
|
public boolean hasGottenDefaultSavedSearches;
|
||||||
private HabboInfo habboInfo;
|
private HabboInfo habboInfo;
|
||||||
|
|||||||
+166
-128
@@ -11,16 +11,24 @@ import com.eu.habbo.messages.outgoing.generic.alerts.BubbleAlertKeys;
|
|||||||
import com.eu.habbo.messages.outgoing.generic.alerts.GenericAlertComposer;
|
import com.eu.habbo.messages.outgoing.generic.alerts.GenericAlertComposer;
|
||||||
import com.eu.habbo.messages.outgoing.rooms.ForwardToRoomComposer;
|
import com.eu.habbo.messages.outgoing.rooms.ForwardToRoomComposer;
|
||||||
import gnu.trove.set.hash.THashSet;
|
import gnu.trove.set.hash.THashSet;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class FloorPlanEditorSaveEvent extends MessageHandler {
|
public class FloorPlanEditorSaveEvent extends MessageHandler {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(FloorPlanEditorSaveEvent.class);
|
||||||
|
|
||||||
public static int MAXIMUM_FLOORPLAN_WIDTH_LENGTH = 64;
|
public static int MAXIMUM_FLOORPLAN_WIDTH_LENGTH = 64;
|
||||||
public static int MAXIMUM_FLOORPLAN_SIZE = 64 * 64;
|
public static int MAXIMUM_FLOORPLAN_SIZE = 64 * 64;
|
||||||
|
|
||||||
|
private static final int SAVE_COOLDOWN_SECONDS = 3;
|
||||||
|
private static final Pattern ALLOWED_MAP_CHARS = Pattern.compile("[a-qA-Q0-9xX\r]+");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRatelimit() {
|
public int getRatelimit() {
|
||||||
return 500;
|
return 500;
|
||||||
@@ -38,154 +46,184 @@ public class FloorPlanEditorSaveEvent extends MessageHandler {
|
|||||||
if (room == null)
|
if (room == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (room.getOwnerId() == this.client.getHabbo().getHabboInfo().getId() || this.client.getHabbo().hasPermission(Permission.ACC_ANYROOMOWNER)) {
|
if (!(room.getOwnerId() == this.client.getHabbo().getHabboInfo().getId() || this.client.getHabbo().hasPermission(Permission.ACC_ANYROOMOWNER))) {
|
||||||
StringJoiner errors = new StringJoiner("<br />");
|
return;
|
||||||
String map = this.packet.readString();
|
}
|
||||||
map = map.replace("X", "x");
|
|
||||||
|
|
||||||
String[] mapRows = map.split("\r");
|
long now = Emulator.getIntUnixTimestamp();
|
||||||
|
if (now - this.client.getHabbo().getHabboStats().lastFloorplanSaveTimestamp < SAVE_COOLDOWN_SECONDS) {
|
||||||
|
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FLOORPLAN_EDITOR_ERROR.key, "Please wait a few seconds before saving again."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int firstRowSize = mapRows[0].length();
|
StringJoiner errors = new StringJoiner("<br />");
|
||||||
|
String map = this.packet.readString();
|
||||||
|
|
||||||
if (Emulator.getConfig().getBoolean("hotel.room.floorplan.check.enabled")) {
|
if (map == null || map.length() > MAXIMUM_FLOORPLAN_SIZE) {
|
||||||
if (!map.matches("[a-zA-Z0-9\r]+")) errors.add("${notification.floorplan_editor.error.title}");
|
LOGGER.warn("Floorplan save rejected (oversize): user={} room={} mapLen={}",
|
||||||
|
this.client.getHabbo().getHabboInfo().getId(), room.getId(), map == null ? 0 : map.length());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Arrays.stream(mapRows)
|
if (!ALLOWED_MAP_CHARS.matcher(map).matches()) {
|
||||||
.filter(line -> line.length() != firstRowSize)
|
LOGGER.warn("Floorplan save rejected (illegal chars): user={} room={}",
|
||||||
.findAny()
|
this.client.getHabbo().getHabboInfo().getId(), room.getId());
|
||||||
.ifPresent(s -> errors.add("(General): Line " + (Arrays.asList(mapRows).indexOf(s) + 1) + " is of different length than line 1"));
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (map.isEmpty() || map.replace("x", "").replace("\r", "").isEmpty()) {
|
map = map.replace("X", "x");
|
||||||
errors.add("${notification.floorplan_editor.error.message.effective_height_is_0}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map.length() > MAXIMUM_FLOORPLAN_SIZE) {
|
String[] mapRows = map.split("\r");
|
||||||
errors.add("${notification.floorplan_editor.error.message.too_large_area}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapRows.length > MAXIMUM_FLOORPLAN_WIDTH_LENGTH) errors.add("${notification.floorplan_editor.error.message.too_large_height}");
|
if (mapRows.length == 0 || mapRows.length > MAXIMUM_FLOORPLAN_WIDTH_LENGTH) {
|
||||||
else if (Arrays.stream(mapRows).anyMatch(l -> l.length() > MAXIMUM_FLOORPLAN_WIDTH_LENGTH || l.isEmpty())) errors.add("${notification.floorplan_editor.error.message.too_large_width}");
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (errors.length() > 0) {
|
int firstRowSize = mapRows[0].length();
|
||||||
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FLOORPLAN_EDITOR_ERROR.key, errors.toString()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int doorX = this.packet.readInt();
|
if (firstRowSize == 0 || firstRowSize > MAXIMUM_FLOORPLAN_WIDTH_LENGTH) {
|
||||||
int doorY = this.packet.readInt();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (doorX < 0 || doorX > firstRowSize || doorY < 0 || doorY >= mapRows.length) {
|
for (String row : mapRows) {
|
||||||
errors.add("${notification.floorplan_editor.error.message.entry_tile_outside_map}");
|
if (row.length() != firstRowSize) {
|
||||||
}
|
|
||||||
|
|
||||||
if (doorY < mapRows.length && doorX < mapRows[doorY].length() && mapRows[doorY].charAt(doorX) == 'x') {
|
|
||||||
errors.add("${notification.floorplan_editor.error.message.entry_not_on_tile}");
|
|
||||||
}
|
|
||||||
|
|
||||||
int doorRotation = this.packet.readInt();
|
|
||||||
if (doorRotation < 0 || doorRotation > 7) {
|
|
||||||
errors.add("${notification.floorplan_editor.error.message.invalid_entry_tile_direction}");
|
|
||||||
}
|
|
||||||
|
|
||||||
int wallSize = this.packet.readInt();
|
|
||||||
if (wallSize < -2 || wallSize > 1) {
|
|
||||||
errors.add("${notification.floorplan_editor.error.message.invalid_wall_thickness}");
|
|
||||||
}
|
|
||||||
int floorSize = this.packet.readInt();
|
|
||||||
if (floorSize < -2 || floorSize > 1) {
|
|
||||||
errors.add("${notification.floorplan_editor.error.message.invalid_floor_thickness}");
|
|
||||||
}
|
|
||||||
|
|
||||||
int wallHeight = -1;
|
|
||||||
if (this.packet.bytesAvailable() >= 4)
|
|
||||||
wallHeight = this.packet.readInt();
|
|
||||||
|
|
||||||
if (wallHeight < -1 || wallHeight > 15) {
|
|
||||||
errors.add("${notification.floorplan_editor.error.message.invalid_walls_fixed_height}");
|
|
||||||
}
|
|
||||||
|
|
||||||
THashSet<RoomTile> locked_tileList = room.getLockedTiles();
|
|
||||||
THashSet<RoomTile> new_tileList = new THashSet<>();
|
|
||||||
blockingRoomItemScan:
|
|
||||||
for (int y = 0; y < mapRows.length; y++) {
|
|
||||||
for (int x = 0; x < firstRowSize; x++) {
|
|
||||||
|
|
||||||
RoomTile tile = room.getLayout().getTile((short) x, (short) y);
|
|
||||||
new_tileList.add(tile);
|
|
||||||
String square = String.valueOf(mapRows[y].charAt(x));
|
|
||||||
short height;
|
|
||||||
|
|
||||||
if (square.equalsIgnoreCase("x") && room.getTopItemAt(x, y) != null) {
|
|
||||||
errors.add("${notification.floorplan_editor.error.message.change_blocked_by_room_item}");
|
|
||||||
break blockingRoomItemScan;
|
|
||||||
} else {
|
|
||||||
if (square.isEmpty()) {
|
|
||||||
height = 0;
|
|
||||||
} else if (Emulator.isNumeric(square)) {
|
|
||||||
height = Short.parseShort(square);
|
|
||||||
} else {
|
|
||||||
height = (short) (10 + "ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(square.toUpperCase()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tile != null && tile.state != RoomTileState.INVALID && height != tile.z && room.getTopItemAt(x, y) != null) {
|
|
||||||
errors.add("${notification.floorplan_editor.error.message.change_blocked_by_room_item}");
|
|
||||||
break blockingRoomItemScan;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
locked_tileList.removeAll(new_tileList);
|
|
||||||
if (!locked_tileList.isEmpty()) {
|
|
||||||
errors.add("${notification.floorplan_editor.error.message.change_blocked_by_room_item}");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (errors.length() > 0) {
|
|
||||||
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FLOORPLAN_EDITOR_ERROR.key, errors.toString()));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RoomLayout layout = room.getLayout();
|
if (Emulator.getConfig().getBoolean("hotel.room.floorplan.check.enabled")) {
|
||||||
|
if (map.replace("x", "").replace("\r", "").isEmpty()) {
|
||||||
|
errors.add("${notification.floorplan_editor.error.message.effective_height_is_0}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (layout instanceof CustomRoomLayout) {
|
int doorX = this.packet.readInt();
|
||||||
layout.setDoorX((short) doorX);
|
int doorY = this.packet.readInt();
|
||||||
layout.setDoorY((short) doorY);
|
|
||||||
layout.setDoorDirection(doorRotation);
|
|
||||||
layout.setHeightmap(map);
|
|
||||||
layout.parse();
|
|
||||||
|
|
||||||
if (layout.getDoorTile() == null) {
|
if (doorX < 0 || doorX >= firstRowSize || doorY < 0 || doorY >= mapRows.length) {
|
||||||
this.client.getHabbo().alert("Error");
|
errors.add("${notification.floorplan_editor.error.message.entry_tile_outside_map}");
|
||||||
((CustomRoomLayout) layout).needsUpdate(false);
|
} else if (mapRows[doorY].charAt(doorX) == 'x') {
|
||||||
Emulator.getGameEnvironment().getRoomManager().unloadRoom(room);
|
errors.add("${notification.floorplan_editor.error.message.entry_not_on_tile}");
|
||||||
|
}
|
||||||
|
|
||||||
|
int doorRotation = this.packet.readInt();
|
||||||
|
if (doorRotation < 0 || doorRotation > 7) {
|
||||||
|
errors.add("${notification.floorplan_editor.error.message.invalid_entry_tile_direction}");
|
||||||
|
}
|
||||||
|
|
||||||
|
int wallSize = this.packet.readInt();
|
||||||
|
if (wallSize < -2 || wallSize > 1) {
|
||||||
|
errors.add("${notification.floorplan_editor.error.message.invalid_wall_thickness}");
|
||||||
|
}
|
||||||
|
int floorSize = this.packet.readInt();
|
||||||
|
if (floorSize < -2 || floorSize > 1) {
|
||||||
|
errors.add("${notification.floorplan_editor.error.message.invalid_floor_thickness}");
|
||||||
|
}
|
||||||
|
|
||||||
|
int wallHeight = -1;
|
||||||
|
if (this.packet.bytesAvailable() >= 4)
|
||||||
|
wallHeight = this.packet.readInt();
|
||||||
|
|
||||||
|
if (wallHeight < -1 || wallHeight > 15) {
|
||||||
|
errors.add("${notification.floorplan_editor.error.message.invalid_walls_fixed_height}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length() > 0) {
|
||||||
|
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FLOORPLAN_EDITOR_ERROR.key, errors.toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
THashSet<RoomTile> locked_tileList = room.getLockedTiles();
|
||||||
|
THashSet<RoomTile> new_tileList = new THashSet<>();
|
||||||
|
blockingRoomItemScan:
|
||||||
|
for (int y = 0; y < mapRows.length; y++) {
|
||||||
|
for (int x = 0; x < firstRowSize; x++) {
|
||||||
|
|
||||||
|
RoomTile tile = room.getLayout().getTile((short) x, (short) y);
|
||||||
|
new_tileList.add(tile);
|
||||||
|
String square = String.valueOf(mapRows[y].charAt(x));
|
||||||
|
short height;
|
||||||
|
|
||||||
|
if (square.equalsIgnoreCase("x") && room.getTopItemAt(x, y) != null) {
|
||||||
|
errors.add("${notification.floorplan_editor.error.message.change_blocked_by_room_item}");
|
||||||
|
break blockingRoomItemScan;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (square.isEmpty()) {
|
||||||
|
height = 0;
|
||||||
|
} else if (Emulator.isNumeric(square)) {
|
||||||
|
height = Short.parseShort(square);
|
||||||
|
} else {
|
||||||
|
int idx = "abcdefghijklmnopq".indexOf(square.toLowerCase());
|
||||||
|
if (idx < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
height = (short) (10 + idx);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
((CustomRoomLayout) layout).needsUpdate(true);
|
|
||||||
Emulator.getThreading().run((CustomRoomLayout) layout);
|
|
||||||
} else {
|
|
||||||
layout = Emulator.getGameEnvironment().getRoomManager().insertCustomLayout(room, map, doorX, doorY, doorRotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (layout != null) {
|
if (tile != null && tile.state != RoomTileState.INVALID && height != tile.z && room.getTopItemAt(x, y) != null) {
|
||||||
room.setHasCustomLayout(true);
|
errors.add("${notification.floorplan_editor.error.message.change_blocked_by_room_item}");
|
||||||
room.setNeedsUpdate(true);
|
break blockingRoomItemScan;
|
||||||
room.setLayout(layout);
|
|
||||||
room.setWallSize(wallSize);
|
|
||||||
room.setFloorSize(floorSize);
|
|
||||||
room.setWallHeight(wallHeight);
|
|
||||||
room.save();
|
|
||||||
Collection<Habbo> habbos = new ArrayList<>(room.getUserCount());
|
|
||||||
habbos.addAll(room.getHabbos());
|
|
||||||
Emulator.getGameEnvironment().getRoomManager().unloadRoom(room);
|
|
||||||
room = Emulator.getGameEnvironment().getRoomManager().loadRoom(room.getId());
|
|
||||||
ServerMessage message = new ForwardToRoomComposer(room.getId()).compose();
|
|
||||||
for (Habbo habbo : habbos) {
|
|
||||||
habbo.getClient().sendResponse(message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
locked_tileList.removeAll(new_tileList);
|
||||||
|
if (!locked_tileList.isEmpty()) {
|
||||||
|
errors.add("${notification.floorplan_editor.error.message.change_blocked_by_room_item}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length() > 0) {
|
||||||
|
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FLOORPLAN_EDITOR_ERROR.key, errors.toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomLayout layout = room.getLayout();
|
||||||
|
|
||||||
|
if (layout instanceof CustomRoomLayout) {
|
||||||
|
layout.setDoorX((short) doorX);
|
||||||
|
layout.setDoorY((short) doorY);
|
||||||
|
layout.setDoorDirection(doorRotation);
|
||||||
|
layout.setHeightmap(map);
|
||||||
|
layout.parse();
|
||||||
|
|
||||||
|
if (layout.getDoorTile() == null) {
|
||||||
|
this.client.getHabbo().alert("Error");
|
||||||
|
((CustomRoomLayout) layout).needsUpdate(false);
|
||||||
|
Emulator.getGameEnvironment().getRoomManager().unloadRoom(room);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
((CustomRoomLayout) layout).needsUpdate(true);
|
||||||
|
Emulator.getThreading().run((CustomRoomLayout) layout);
|
||||||
|
} else {
|
||||||
|
layout = Emulator.getGameEnvironment().getRoomManager().insertCustomLayout(room, map, doorX, doorY, doorRotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layout != null) {
|
||||||
|
room.setHasCustomLayout(true);
|
||||||
|
room.setNeedsUpdate(true);
|
||||||
|
room.setLayout(layout);
|
||||||
|
room.setWallSize(wallSize);
|
||||||
|
room.setFloorSize(floorSize);
|
||||||
|
room.setWallHeight(wallHeight);
|
||||||
|
room.save();
|
||||||
|
|
||||||
|
this.client.getHabbo().getHabboStats().lastFloorplanSaveTimestamp = now;
|
||||||
|
LOGGER.info("Floorplan saved: user={} room={} mapLen={} rows={} cols={}",
|
||||||
|
this.client.getHabbo().getHabboInfo().getId(), room.getId(), map.length(), mapRows.length, firstRowSize);
|
||||||
|
|
||||||
|
Collection<Habbo> habbos = new ArrayList<>(room.getUserCount());
|
||||||
|
habbos.addAll(room.getHabbos());
|
||||||
|
Emulator.getGameEnvironment().getRoomManager().unloadRoom(room);
|
||||||
|
room = Emulator.getGameEnvironment().getRoomManager().loadRoom(room.getId());
|
||||||
|
ServerMessage message = new ForwardToRoomComposer(room.getId()).compose();
|
||||||
|
for (Habbo habbo : habbos) {
|
||||||
|
habbo.getClient().sendResponse(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user