From 1eebdb27188c2d3e351c14f22d9788eb2e9af372 Mon Sep 17 00:00:00 2001 From: William Date: Fri, 13 Dec 2024 17:33:49 +0000 Subject: [PATCH] fix: correct issues with same-server RTP validation --- .../huskhomes/command/RtpCommand.java | 59 ++++++++++++++----- .../william278/huskhomes/config/Settings.java | 2 +- .../william278/huskhomes/position/World.java | 5 ++ .../network/MessageSerializationTests.java | 4 +- .../position/SavedPositionTests.java | 4 +- .../random/NormalDistributionTests.java | 2 +- 6 files changed, 56 insertions(+), 20 deletions(-) diff --git a/common/src/main/java/net/william278/huskhomes/command/RtpCommand.java b/common/src/main/java/net/william278/huskhomes/command/RtpCommand.java index a115ae97f..2e007c3a2 100644 --- a/common/src/main/java/net/william278/huskhomes/command/RtpCommand.java +++ b/common/src/main/java/net/william278/huskhomes/command/RtpCommand.java @@ -87,8 +87,8 @@ public void execute(@NotNull CommandUser executor, @NotNull String[] args) { } // Validate world and server, and execute RTP - Optional> validatedTarget = validateRtp(teleporter, executor, worldName, targetServer); - validatedTarget.ifPresent(entry -> executeRtp(teleporter, executor, entry.getKey(), entry.getValue(), args)); + validateRtp(teleporter, executor, worldName.replace("minecraft:", ""), targetServer) + .ifPresent(entry -> executeRtp(teleporter, executor, entry.getKey(), entry.getValue(), args)); } @Nullable @@ -149,14 +149,10 @@ public List suggest(@NotNull CommandUser user, @NotNull String[] args) { }; } - - /** - * Validates the RTP target world and server based on arguments, ensuring the server contains the target world. - * - If no server is specified, randomly selects a server containing the world. - * - Returns both the validated world and server as a pair. + * Validates that a random teleport operation is valid. * - * @param teleporter The player to teleport + * @param teleporter The player being teleported * @param executor The player executing the command * @param worldName The world name to teleport to * @param targetServer The server name to teleport to (optional) @@ -176,9 +172,43 @@ private Optional> validateRtp(@NotNull OnlineUser telep return Optional.empty(); } - Map> randomTargetServers = plugin.getSettings().getRtp().getRandomTargetServers(); + // Validate a cross-server RTP, if applicable + if (plugin.getSettings().getRtp().isCrossServer() && !plugin.getServerName().equals(targetServer)) { + return validateCrossServerRtp(executor, worldName, targetServer); + } + // Find the local world + final Optional localWorld = plugin.getWorlds().stream().filter((world) -> world + .getName().replace("minecraft:", "") + .equalsIgnoreCase(worldName)).findFirst(); + if (localWorld.isEmpty()) { + plugin.getLocales().getLocale("error_invalid_world", worldName) + .ifPresent(executor::sendMessage); + return Optional.empty(); + } + + // Check the local world is not restricted + if (plugin.getSettings().getRtp().isWorldRtpRestricted(localWorld.get())) { + plugin.getLocales().getLocale("error_rtp_restricted_world") + .ifPresent(executor::sendMessage); + return Optional.empty(); + } + return localWorld.map(world -> new AbstractMap.SimpleImmutableEntry<>(world, worldName)); + } + + /** + * Validates the RTP target world and server based on arguments, ensuring the server contains the target world. + * - If no server is specified, randomly selects a server containing the world. + * - Returns both the validated world and server as a pair. + * + * @param executor The player executing the command + * @param worldName The world name to teleport to + * @param targetServer The server name to teleport to (optional) + * @return A pair of the target world and server to use for teleportation, if valid + */ + private Optional> validateCrossServerRtp(CommandUser executor, String worldName, String targetServer) { // Get a list of servers that have the specified world + Map> randomTargetServers = plugin.getSettings().getRtp().getRandomTargetServers(); List eligibleServers = randomTargetServers.entrySet().stream() .filter(entry -> entry.getValue().contains(worldName)) .map(Map.Entry::getKey) @@ -196,11 +226,12 @@ private Optional> validateRtp(@NotNull OnlineUser telep } Optional targetWorld = plugin.getWorlds().stream() - .filter(world -> world.getName().equalsIgnoreCase(worldName)) + .filter(world -> world.getName().replace("minecraft:", "") + .equalsIgnoreCase(worldName)) .findFirst() - .or(() -> Optional.of(World.from(worldName, UUID.randomUUID()))); + .or(() -> Optional.of(World.from(worldName))); - return targetWorld.map(world -> new AbstractMap.SimpleEntry<>(world, selectedServer)); + return targetWorld.map(world -> new AbstractMap.SimpleImmutableEntry<>(world, selectedServer)); } /** @@ -211,7 +242,7 @@ private Optional> validateRtp(@NotNull OnlineUser telep * @param executor The player executing the command * @param world The validated world to teleport to * @param targetServer The validated server to teleport to - * @param args Arguments to pass to the RTP engine + * @param args Arguments to pass to the RTP engine */ private void executeRtp(@NotNull OnlineUser teleporter, @NotNull CommandUser executor, @NotNull World world, @NotNull String targetServer, @NotNull String[] args) { @@ -220,7 +251,7 @@ private void executeRtp(@NotNull OnlineUser teleporter, @NotNull CommandUser exe .ifPresent(teleporter::sendMessage); if (plugin.getSettings().getRtp().isCrossServer() && plugin.getSettings().getCrossServer().isEnabled() - && plugin.getSettings().getCrossServer().getBrokerType() == Broker.Type.REDIS) { + && plugin.getSettings().getCrossServer().getBrokerType() == Broker.Type.REDIS) { if (targetServer.equals(plugin.getServerName())) { performLocalRTP(teleporter, executor, world, args); return; diff --git a/common/src/main/java/net/william278/huskhomes/config/Settings.java b/common/src/main/java/net/william278/huskhomes/config/Settings.java index 6b65ab8d6..55dbb0dff 100644 --- a/common/src/main/java/net/william278/huskhomes/config/Settings.java +++ b/common/src/main/java/net/william278/huskhomes/config/Settings.java @@ -347,7 +347,7 @@ public boolean isWorldRtpRestricted(@NotNull World world) { @Comment({"List of server in which /rtp is allowed. (Only relevant when using cross server mode WITH REDIS)", "If a server is not defined here the RTP logic has no way of knowing its existence."}) private Map> randomTargetServers = new HashMap<>( - Map.of("survival_server", List.of("world", "world_nether", "world_the_end")) + Map.of("server", List.of("world", "world_nether", "world_the_end")) ); } diff --git a/common/src/main/java/net/william278/huskhomes/position/World.java b/common/src/main/java/net/william278/huskhomes/position/World.java index 3d9ddd128..3648df9ed 100644 --- a/common/src/main/java/net/william278/huskhomes/position/World.java +++ b/common/src/main/java/net/william278/huskhomes/position/World.java @@ -50,6 +50,11 @@ public static World from(@NotNull String name, @NotNull UUID uuid) { return new World(name, uuid, null); } + @NotNull + public static World from(@NotNull String name) { + return from(name, UUID.randomUUID()); + } + @NotNull @SuppressWarnings("unused") public Environment getEnvironment() { diff --git a/common/src/test/java/net/william278/huskhomes/network/MessageSerializationTests.java b/common/src/test/java/net/william278/huskhomes/network/MessageSerializationTests.java index d7506c9a9..501ef86b9 100644 --- a/common/src/test/java/net/william278/huskhomes/network/MessageSerializationTests.java +++ b/common/src/test/java/net/william278/huskhomes/network/MessageSerializationTests.java @@ -49,7 +49,7 @@ public class MessageSerializationTests { .target("TestTarget", Message.TargetType.PLAYER) .payload(Payload.position( Position.at(63.25, 127.43, -32, 180f, -94.3f, - World.from("TestWorld", UUID.randomUUID()), "TestServer"))) + World.from("TestWorld"), "TestServer"))) .build(), Message.builder() .type(Message.MessageType.TELEPORT_TO_NETWORKED_USER) @@ -61,7 +61,7 @@ public class MessageSerializationTests { .target("TestTarget", Message.TargetType.PLAYER) .payload(Payload.position( Position.at(63.25, 127.43, -32, 180f, -94.3f, - World.from("TestWorld", UUID.randomUUID()), "TestServer"))) + World.from("TestWorld"), "TestServer"))) .build() ); diff --git a/common/src/test/java/net/william278/huskhomes/position/SavedPositionTests.java b/common/src/test/java/net/william278/huskhomes/position/SavedPositionTests.java index 9b39e911c..70007464f 100644 --- a/common/src/test/java/net/william278/huskhomes/position/SavedPositionTests.java +++ b/common/src/test/java/net/william278/huskhomes/position/SavedPositionTests.java @@ -81,7 +81,7 @@ public void testWarpIdentifiers(@NotNull Warp warp, @NotNull String name, boolea @NotNull private static Stream provideWarpData() { final Position position = Position.at(63.25, 127.43, -32, 180f, -94.3f, - World.from("TestWorld", UUID.randomUUID()), "TestServer"); + World.from("TestWorld"), "TestServer"); return POSITION_UNSAFE_NAMES.entrySet().stream() .map(entry -> Arguments.of( Warp.from(position, PositionMeta.create(entry.getKey(), "")), @@ -93,7 +93,7 @@ private static Stream provideWarpData() { @NotNull private static Stream provideHomeData() { final Position position = Position.at(63.25, 127.43, -32, 180f, -94.3f, - World.from("TestWorld", UUID.randomUUID()), "TestServer"); + World.from("TestWorld"), "TestServer"); return POSITION_UNSAFE_NAMES.entrySet().stream() .map(entry -> Arguments.of( Home.from( diff --git a/common/src/test/java/net/william278/huskhomes/random/NormalDistributionTests.java b/common/src/test/java/net/william278/huskhomes/random/NormalDistributionTests.java index 570ce8ad2..0cafc0df8 100644 --- a/common/src/test/java/net/william278/huskhomes/random/NormalDistributionTests.java +++ b/common/src/test/java/net/william278/huskhomes/random/NormalDistributionTests.java @@ -105,7 +105,7 @@ private static List generateLocations(int amount) { final List locations = new ArrayList<>(); for (int i = 0; i < amount; i++) { locations.add(NormalDistributionEngine.generateLocation( - Location.at(0, 0, 0, 0, 0, World.from("TestWorld", UUID.randomUUID())), + Location.at(0, 0, 0, 0, 0, World.from("TestWorld")), MEAN, STANDARD_DEVIATION, SPAWN_RADIUS, MAX_RADIUS)); } return locations;