Skip to content

Commit

Permalink
feat: Add the option to random teleport cross-server (#647)
Browse files Browse the repository at this point in the history
* feat: Cross-Server RTP

* feat: Cross-Server RTP

* feat: Cross-Server RTP

* docs

* fix req changes

* amend for api whoops
  • Loading branch information
ProdPreva1l authored Jun 24, 2024
1 parent dac1b9f commit af3a691
Show file tree
Hide file tree
Showing 13 changed files with 296 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public enum Type {
TPA_HERE_COMMAND((plugin) -> new TeleportRequestCommand(plugin, TeleportRequest.Type.TPA_HERE)),
TPACCEPT_COMMAND((plugin) -> new TpRespondCommand(plugin, true)),
TPDECLINE_COMMAND((plugin) -> new TpRespondCommand(plugin, false)),
RTP_COMMAND(RtpCommand::new),
RTP_COMMAND(RTPCommand::new),
TP_IGNORE_COMMAND(TpIgnoreCommand::new),
TP_OFFLINE_COMMAND(TpOfflineCommand::new),
TP_ALL_COMMAND(TpAllCommand::new),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import net.william278.huskhomes.HuskHomes;
import net.william278.huskhomes.config.Locales;
import net.william278.huskhomes.config.Settings;
import net.william278.huskhomes.network.Broker;
import net.william278.huskhomes.network.Message;
import net.william278.huskhomes.network.Payload;
import net.william278.huskhomes.position.Home;
import net.william278.huskhomes.position.Position;
import net.william278.huskhomes.position.Warp;
Expand All @@ -38,10 +41,7 @@

import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.stream.Collectors;
Expand All @@ -63,6 +63,11 @@ public class BaseHuskHomesAPI {
*/
protected final HuskHomes plugin;

/**
* <b>(Internal use only</b> - Random integer for RTP.
*/
private final Random random = new Random();

/**
* <b>(Internal use only)</b> - Constructor, instantiating the base API class.
*/
Expand Down Expand Up @@ -766,16 +771,67 @@ public final TeleportBuilder teleportBuilder() {

/**
* Attempt to teleport an {@link OnlineUser} to a randomly generated {@link Position}. The {@link Position} will be
* generated by the current {@link RandomTeleportEngine}.
* generated by the current {@link RandomTeleportEngine} on a randomly chosen server from
* {@link Settings.RtpSettings Allowed Servers} (If {@link Settings.CrossServerSettings Broker Type}
* is {@link Broker.Type#REDIS}.
*
* @param user The {@link OnlineUser} to teleport
* @param timedTeleport Whether the teleport should be timed or not (requiring a warmup where they must stand still
* for a period of time)
* @param rtpArgs Arguments that will be passed to the implementing {@link RandomTeleportEngine}
* @since 3.0
* @apiNote This method was updated in version 4.6.3 to support the new Cross-Server RTP function,
* for the original function use {@link #randomlyTeleportPlayerLocally(OnlineUser, boolean, String...)}
*/
public final void randomlyTeleportPlayer(@NotNull OnlineUser user, boolean timedTeleport,
@NotNull String... rtpArgs) {
if (plugin.getSettings().getRtp().isCrossServer() && (plugin.getSettings().getCrossServer().isEnabled()
&& plugin.getSettings().getCrossServer().getBrokerType() == Broker.Type.REDIS)) {
List<String> allowedServers = plugin.getSettings().getRtp().getRandomTargetServers();
String randomServer = allowedServers.get(random.nextInt(allowedServers.size()));
if (randomServer.equals(plugin.getServerName())) {
randomlyTeleportPlayerLocally(user, timedTeleport, rtpArgs);
return;
}
Message.builder()
.scope(Message.Scope.SERVER)
.target(randomServer)
.type(Message.Type.REQUEST_RTP_LOCATION)
.payload(Payload.withStringList(
List.of(user.getPosition().getWorld().getName(), user.getUsername())))
.build().send(plugin.getMessenger(), user);
return;
}
randomlyTeleportPlayerLocally(user, timedTeleport, rtpArgs);
}

/**
* Attempt to teleport an {@link OnlineUser} to a randomly generated {@link Position}. The {@link Position} will be
* generated by the current {@link RandomTeleportEngine}.
*
* @param user The {@link OnlineUser} to teleport
* @since 3.0
* @apiNote This method was updated in version 4.6.3 to support the new Cross-Server RTP function,
* for the original function use {@link #randomlyTeleportPlayerLocally(OnlineUser)}
*/
public final void randomlyTeleportPlayer(@NotNull OnlineUser user) {
this.randomlyTeleportPlayer(user, false);
}


/**
* Attempt to teleport an {@link OnlineUser} to a randomly generated {@link Position}. The {@link Position} will be
* generated by the current {@link RandomTeleportEngine}. (Does not RTP cross-server, use
* {@link #randomlyTeleportPlayer(OnlineUser, boolean, String...)})
*
* @param user The {@link OnlineUser} to teleport
* @param timedTeleport Whether the teleport should be timed or not (requiring a warmup where they must stand still
* for a period of time)
* @param rtpArgs Arguments that will be passed to the implementing {@link RandomTeleportEngine}
* @since 4.6.3
*/
public final void randomlyTeleportPlayerLocally(@NotNull OnlineUser user, boolean timedTeleport,
@NotNull String... rtpArgs) {
plugin.getRandomTeleportEngine()
.getRandomPosition(user.getPosition().getWorld(), rtpArgs)
.thenAccept(position -> {
Expand All @@ -794,13 +850,14 @@ public final void randomlyTeleportPlayer(@NotNull OnlineUser user, boolean timed

/**
* Attempt to teleport an {@link OnlineUser} to a randomly generated {@link Position}. The {@link Position} will be
* generated by the current {@link RandomTeleportEngine}.
* generated by the current {@link RandomTeleportEngine}. (Does not RTP cross-server, use
* {@link #randomlyTeleportPlayer(OnlineUser)})
*
* @param user The {@link OnlineUser} to teleport
* @since 3.0
* @since 4.6.3
*/
public final void randomlyTeleportPlayer(@NotNull OnlineUser user) {
this.randomlyTeleportPlayer(user, false);
public final void randomlyTeleportPlayerLocally(@NotNull OnlineUser user) {
this.randomlyTeleportPlayerLocally(user, false);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
package net.william278.huskhomes.command;

import net.william278.huskhomes.HuskHomes;
import net.william278.huskhomes.network.Broker;
import net.william278.huskhomes.network.Message;
import net.william278.huskhomes.network.Payload;
import net.william278.huskhomes.position.World;
import net.william278.huskhomes.teleport.Teleport;
import net.william278.huskhomes.teleport.TeleportBuilder;
Expand All @@ -32,10 +35,13 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;

public class RtpCommand extends Command implements UserListTabProvider {
public class RTPCommand extends Command implements UserListTabProvider {

protected RtpCommand(@NotNull HuskHomes plugin) {
private final Random random = new Random();

protected RTPCommand(@NotNull HuskHomes plugin) {
super("rtp", List.of(), "[player] [world]", plugin);

addAdditionalPermissions(Map.of(
Expand Down Expand Up @@ -140,6 +146,37 @@ private void executeRtp(@NotNull OnlineUser teleporter, @NotNull CommandUser exe
// Generate a random position
plugin.getLocales().getLocale("teleporting_random_generation")
.ifPresent(teleporter::sendMessage);

if (plugin.getSettings().getRtp().isCrossServer() && plugin.getSettings().getCrossServer().isEnabled()
&& plugin.getSettings().getCrossServer().getBrokerType() == Broker.Type.REDIS) {
List<String> allowedServers = plugin.getSettings().getRtp().getRandomTargetServers();
String randomServer = allowedServers.get(random.nextInt(allowedServers.size()));
if (randomServer.equals(plugin.getServerName())) {
performLocalRTP(teleporter, executor, world, args);
return;
}
Message.builder()
.type(Message.Type.REQUEST_RTP_LOCATION)
.scope(Message.Scope.SERVER)
.target(randomServer)
.payload(Payload.withRTPRequest(Payload.RTPRequest.of(teleporter.getUsername(), world.getName())))
.build().send(plugin.getMessenger(), teleporter);
return;
}

performLocalRTP(teleporter, executor, world, args);
}

/**
* Performs the RTP locally.
*
* @param teleporter person to teleport
* @param executor the person executing the teleport
* @param world the world to teleport to
* @param args rtp engine args
*/
private void performLocalRTP(@NotNull OnlineUser teleporter, @NotNull CommandUser executor, @NotNull World world,
@NotNull String[] args) {
plugin.getRandomTeleportEngine()
.getRandomPosition(world, args.length > 1 ? removeFirstArg(args) : args)
.thenAccept(position -> {
Expand All @@ -157,5 +194,4 @@ private void executeRtp(@NotNull OnlineUser teleporter, @NotNull CommandUser exe
builder.buildAndComplete(executor.equals(teleporter), args);
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,13 @@ public boolean isWorldRtpRestricted(@NotNull World world) {
.map(n -> n.startsWith("minecraft:") ? n.substring(10) : n)
.anyMatch(n -> n.equalsIgnoreCase(filteredName));
}

@Comment("Whether or not RTP should perform cross-server.")
private boolean crossServer = false;

@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 List<String> randomTargetServers = List.of("server-01", "server-02");
}

@Comment("Action cooldown settings. Docs: https://william278.net/docs/huskhomes/cooldowns")
Expand Down
55 changes: 55 additions & 0 deletions common/src/main/java/net/william278/huskhomes/network/Broker.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@
import net.william278.huskhomes.HuskHomes;
import net.william278.huskhomes.position.Home;
import net.william278.huskhomes.position.Warp;
import net.william278.huskhomes.position.World;
import net.william278.huskhomes.teleport.Teleport;
import net.william278.huskhomes.teleport.TeleportBuilder;
import net.william278.huskhomes.user.OnlineUser;
import net.william278.huskhomes.util.TransactionResolver;
import org.jetbrains.annotations.NotNull;

import java.util.Locale;
Expand Down Expand Up @@ -113,10 +116,55 @@ protected void handle(@NotNull OnlineUser receiver, @NotNull Message message) {
plugin.getManager().homes().updatePublicHomeCache();
plugin.getManager().warps().updateWarpCache();
}
case RTP_LOCATION -> message.getPayload()
.getRTPResponse()
.ifPresentOrElse(response -> {
final TeleportBuilder builder = Teleport.builder(plugin)
.teleporter(receiver)
.actions(TransactionResolver.Action.RANDOM_TELEPORT)
.target(response.getPosition());
builder.buildAndComplete(true);
}, () -> plugin.getLocales().getLocale("error_rtp_randomization_timeout")
.ifPresent(receiver::sendMessage));
default -> throw new IllegalStateException("Unexpected value: " + message.getType());
}
}

/**
* Separate handler for RTP Request because it doesn't need a receiver to handle it.
*
* @param message the message to handle
*/
protected void handleRTPRequest(@NotNull Message message) {
if (message.getSourceServer().equals(getServer())) {
return;
}

message.getPayload()
.getRTPRequest()
.ifPresent((request) -> {
Optional<World> world = plugin.getWorlds().stream()
.filter(w -> w.getName().equals(request.getWorldName())).findFirst();
if (world.isEmpty()) {
throw new RuntimeException("%s requested a position in a world we don't have! World: %s"
.formatted(message.getSourceServer(), request.getWorldName()));
}
plugin.getRandomTeleportEngine().getRandomPosition(world.get(), null)
.thenAccept((position) -> {
final Message.Builder builder = Message.builder()
.type(Message.Type.RTP_LOCATION)
.target(request.getUsername());
if (position.isEmpty()) {
builder.payload(Payload.empty());
} else {
builder.payload(Payload.withRTPResponse(
Payload.RTPResponse.of(request.getUsername(), position.get())));
}
builder.build().send(plugin.getMessenger(), request.getUsername());
});
});
}

/**
* Initialize the message broker.
*
Expand All @@ -132,6 +180,13 @@ protected void handle(@NotNull OnlineUser receiver, @NotNull Message message) {
*/
protected abstract void send(@NotNull Message message, @NotNull OnlineUser sender);

/**
* Send a message to the broker. (For Redis Only)
*
* @param message the message to send
*/
protected abstract void send(@NotNull Message message);

/**
* Move an {@link OnlineUser} to a new server on the proxy network.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ public void send(@NotNull Broker broker, @NotNull OnlineUser sender) {
broker.send(this, sender);
}

public void send(@NotNull Broker broker, @NotNull String sender) {
this.sender = sender;
this.sourceServer = broker.getServer();
broker.send(this);
}


@NotNull
public Type getType() {
return type;
Expand Down Expand Up @@ -173,6 +180,8 @@ public enum Type {
UPDATE_HOME,
UPDATE_WARP,
UPDATE_CACHES,
REQUEST_RTP_LOCATION,
RTP_LOCATION,
}

public enum Scope {
Expand Down
Loading

0 comments on commit af3a691

Please sign in to comment.