Replace lobby with consistent teleportation to last SMP world location

This commit is contained in:
NotAlexNoyle committed 2026-07-22 08:14:47 -04:00
1 parent e2738b2a2e
commit dfd7c64dae
11 files changed
+38 -150

No files matched your search

@@ -16,7 +16,6 @@ import me.realized.duels.command.commands.duels.subcommands.HelpCommand;
import me.realized.duels.command.commands.duels.subcommands.InfoCommand;
import me.realized.duels.command.commands.duels.subcommands.ListCommand;
import me.realized.duels.command.commands.duels.subcommands.LoadkitCommand;
import me.realized.duels.command.commands.duels.subcommands.LobbyCommand;
import me.realized.duels.command.commands.duels.subcommands.OptionsCommand;
import me.realized.duels.command.commands.duels.subcommands.PlaysoundCommand;
import me.realized.duels.command.commands.duels.subcommands.ReloadCommand;
@@ -25,7 +24,6 @@ import me.realized.duels.command.commands.duels.subcommands.ResetratingCommand;
import me.realized.duels.command.commands.duels.subcommands.SavekitCommand;
import me.realized.duels.command.commands.duels.subcommands.SetCommand;
import me.realized.duels.command.commands.duels.subcommands.SetitemCommand;
import me.realized.duels.command.commands.duels.subcommands.SetlobbyCommand;
import me.realized.duels.command.commands.duels.subcommands.SetratingCommand;
import me.realized.duels.command.commands.duels.subcommands.TeleportCommand;
import me.realized.duels.command.commands.duels.subcommands.ToggleCommand;
@@ -52,8 +50,6 @@ public class DuelsCommand extends BaseCommand {
new DeletequeueCommand(plugin),
new AddsignCommand(plugin),
new DeletesignCommand(plugin),
new SetlobbyCommand(plugin),
new LobbyCommand(plugin),
new InfoCommand(plugin),
new ListCommand(plugin),
new EditCommand(plugin),
@@ -29,11 +29,10 @@ public class ListCommand extends BaseCommand {
"arenas", !arenas.isEmpty() ? StringUtil.join(arenas, "&r, &r") : lang.getMessage("GENERAL.none"),
"kits", !kits.isEmpty() ? kits : lang.getMessage("GENERAL.none"),
"queues", !queues.isEmpty() ? queues : lang.getMessage("GENERAL.none"),
"queue_signs", !signs.isEmpty() ? signs : lang.getMessage("GENERAL.none"),
"lobby", StringUtil.parse(playerManager.getLobby()));
"queue_signs", !signs.isEmpty() ? signs : lang.getMessage("GENERAL.none"));
}
private String getColor(final ArenaImpl arena) {
return arena.isDisabled() ? "4" : (arena.getPositions().size() < 2 ? "9" : arena.isUsed() ? "c" : "a");
}
}
}
@@ -1,19 +0,0 @@
package me.realized.duels.command.commands.duels.subcommands;
import me.realized.duels.DuelsPlugin;
import me.realized.duels.command.BaseCommand;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class LobbyCommand extends BaseCommand {
public LobbyCommand(final DuelsPlugin plugin) {
super(plugin, "lobby", null, null, 1, true);
}
@Override
protected void execute(final CommandSender sender, final String label, final String[] args) {
((Player) sender).teleport(playerManager.getLobby());
lang.sendMessage(sender, "COMMAND.duels.lobby");
}
}
@@ -1,23 +0,0 @@
package me.realized.duels.command.commands.duels.subcommands;
import me.realized.duels.DuelsPlugin;
import me.realized.duels.command.BaseCommand;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class SetlobbyCommand extends BaseCommand {
public SetlobbyCommand(final DuelsPlugin plugin) {
super(plugin, "setlobby", null, null, 1, true, "setspawn");
}
@Override
protected void execute(final CommandSender sender, final String label, final String[] args) {
if (!playerManager.setLobby((Player) sender)) {
lang.sendMessage(sender, "ERROR.command.lobby-save-failure");
return;
}
lang.sendMessage(sender, "COMMAND.duels.set-lobby");
}
}
@@ -134,8 +134,6 @@ public class Config extends AbstractConfiguration<DuelsPlugin> {
@Getter
private List<String> arenaWhitelistedWorlds;
@Getter
private boolean teleportToLastLocation;
@Getter
private int teleportDelay;
@Getter
private boolean spawnFirework;
@@ -342,7 +340,6 @@ public class Config extends AbstractConfiguration<DuelsPlugin> {
cancelIfMoved = configuration.getBoolean("duel.cancel-if-moved", false);
joinWhitelistedWorlds = configuration.getStringList("duel.join-whitelisted-worlds");
arenaWhitelistedWorlds = configuration.getStringList("duel.arena-whitelisted-worlds");
teleportToLastLocation = configuration.getBoolean("duel.teleport-to-last-location", false);
teleportDelay = configuration.getInt("duel.teleport-delay", 5);
spawnFirework = configuration.getBoolean("duel.spawn-firework", true);
arenaOnlyEndMessage = configuration.getBoolean("duel.arena-only-end-message", false);
@@ -219,11 +219,11 @@ public class DuelManager implements Loadable {
PlayerUtil.reset(player);
if (info != null) {
teleport.tryTeleport(player, info.getLocation());
teleport.tryTeleport(player, playerManager.getReturnLocation(info));
info.restore(player);
} else {
// If somehow PlayerInfo is not found...
teleport.tryTeleport(player, playerManager.getLobby());
teleport.tryTeleport(player, playerManager.getReturnLocation(null));
}
// Give back bet items
@@ -281,8 +281,9 @@ public class DuelManager implements Loadable {
// Always wipe the (clone) inventory before restoring the cached original.
PlayerUtil.reset(player);
teleport.tryTeleport(player, playerManager.getReturnLocation(info));
if (info != null) {
teleport.tryTeleport(player, info.getLocation());
info.restore(player);
}
@@ -140,7 +140,4 @@ public class PlayerInfo {
}
}
boolean hasRideState() {
return rideState != null;
}
}
@@ -10,18 +10,17 @@ import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import lombok.Getter;
import me.realized.duels.DuelsPlugin;
import me.realized.duels.config.Config;
import me.realized.duels.data.LocationData;
import me.realized.duels.data.PlayerData;
import me.realized.duels.hook.hooks.EssentialsHook;
import me.realized.duels.teleport.Teleport;
import me.realized.duels.util.Loadable;
import me.realized.duels.util.Log;
import me.realized.duels.util.PlayerUtil;
import me.realized.duels.util.io.FileUtil;
import me.realized.duels.util.json.JsonUtil;
@@ -37,37 +36,28 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
/**
* Manages:
* (1) player info cache for restoration after matches.
* (2) lobby location for teleportation after matches.
* Manages player info cache for restoration after matches.
*/
public class PlayerInfoManager implements Loadable {
private static final String CACHE_FILE_NAME = "player-cache.json";
private static final String LOBBY_FILE_NAME = "lobby.json";
private static final String ERROR_LOBBY_LOAD = "Could not load lobby location!";
private static final String ERROR_LOBBY_SAVE = "Could not save lobby location!";
private static final String ERROR_LOBBY_DEFAULT = "Lobby location was not set, using %s's spawn location as default. Use the command /duels setlobby in-game to set the lobby location.";
private static final Set<String> RETURN_WORLDS = new HashSet<>(Arrays.asList(
"world",
"world_nether",
"world_the_end"
));
private final DuelsPlugin plugin;
private final Config config;
private final File cacheFile;
private final File lobbyFile;
private final Map<UUID, PlayerInfo> cache = new HashMap<>();
private Teleport teleport;
private EssentialsHook essentials;
@Getter
private Location lobby;
public PlayerInfoManager(final DuelsPlugin plugin) {
this.plugin = plugin;
this.config = plugin.getConfiguration();
this.cacheFile = new File(plugin.getDataFolder(), CACHE_FILE_NAME);
this.lobbyFile = new File(plugin.getDataFolder(), LOBBY_FILE_NAME);
plugin.doSyncAfter(() -> Bukkit.getPluginManager().registerEvents(new PlayerInfoListener(), plugin), 1L);
}
@@ -82,30 +72,15 @@ public class PlayerInfoManager implements Loadable {
if (data != null) {
for (final Map.Entry<UUID, PlayerData> entry : data.entrySet()) {
cache.put(entry.getKey(), entry.getValue().toPlayerInfo());
final PlayerInfo info = entry.getValue().toPlayerInfo();
info.setLocation(safeReturnLocation(info.getLocation()));
cache.put(entry.getKey(), info);
}
}
}
cacheFile.delete();
}
if (FileUtil.checkNonEmpty(lobbyFile, false)) {
try (final Reader reader = new InputStreamReader(new FileInputStream(lobbyFile), Charsets.UTF_8)) {
this.lobby = JsonUtil.getObjectMapper().readValue(reader, LocationData.class).toLocation();
} catch (IOException ex) {
Log.error(this, ERROR_LOBBY_LOAD, ex);
}
}
// If lobby is not found or points at a disabled/unloaded world, use the
// configured dueling world's spawn location for lobby.
if (!isEnabledWorld(lobby)) {
this.lobby = getFallbackLocation();
final World world = this.lobby != null ? this.lobby.getWorld() : null;
Log.warn(this,
String.format(ERROR_LOBBY_DEFAULT, world != null ? world.getName() : "world"));
}
}
@Override
@@ -139,30 +114,6 @@ public class PlayerInfoManager implements Loadable {
cache.clear();
}
/**
* Sets a lobby location at given player's location.
*
* @param player Player to get location for lobby
* @return true if setting lobby was successful, false otherwise
*/
public boolean setLobby(final Player player) {
if (!config.isDuelingWorld(player)) {
return false;
}
final Location lobby = player.getLocation().clone();
try (final Writer writer = new OutputStreamWriter(new FileOutputStream(lobbyFile), Charsets.UTF_8)) {
JsonUtil.getObjectWriter().writeValue(writer, LocationData.fromLocation(lobby));
writer.flush();
this.lobby = lobby;
return true;
} catch (IOException ex) {
Log.error(this, ERROR_LOBBY_SAVE, ex);
return false;
}
}
/**
* Gets cached PlayerInfo instance for given player.
*
@@ -189,11 +140,7 @@ public class PlayerInfoManager implements Loadable {
}
private void create(final Player player, final PlayerInfo info) {
if (!info.hasRideState() && !info.isForceReturnLocation() && !config.isTeleportToLastLocation()) {
info.setLocation(safeReturnLocation(lobby));
} else if (!info.isForceReturnLocation() && !isEnabledWorld(info.getLocation())) {
info.setLocation(safeReturnLocation(info.getLocation()));
}
info.setLocation(safeReturnLocation(info.getLocation()));
cache.put(player.getUniqueId(), info);
}
@@ -217,23 +164,18 @@ public class PlayerInfoManager implements Loadable {
return cache.remove(player.getUniqueId());
}
private boolean isEnabledWorld(final Location location) {
private boolean isReturnWorld(final Location location) {
return location != null && location.getWorld() != null
&& "world".equals(location.getWorld().getName());
&& RETURN_WORLDS.contains(location.getWorld().getName());
}
private Location getFallbackLocation() {
World world = Bukkit.getWorld("world");
if (world == null && !Bukkit.getWorlds().isEmpty()) {
world = Bukkit.getWorlds().get(0);
}
final World world = Bukkit.getWorld("world");
return world != null ? world.getSpawnLocation() : null;
}
private Location safeReturnLocation(final Location location) {
if (isEnabledWorld(location)) {
if (isReturnWorld(location)) {
return location.clone();
}
@@ -241,14 +183,22 @@ public class PlayerInfoManager implements Loadable {
return fallback != null ? fallback.clone() : null;
}
private Location getReturnLocation(final PlayerInfo info) {
final Location location = info.getLocation();
/**
* Gets a safe return location from cached player data. Only the three main
* worlds are accepted; missing or invalid data falls back to world spawn.
*
* @param info Cached player data, or null if it could not be found
* @return safe return location, or null if the main world is unavailable
*/
public Location getReturnLocation(final PlayerInfo info) {
final Location location = safeReturnLocation(info != null ? info.getLocation() : null);
if (info.isForceReturnLocation() && location != null && location.getWorld() != null) {
return location.clone();
if (info != null) {
// PlayerInfo#restore may teleport again when restoring flight state.
info.setLocation(location);
}
return safeReturnLocation(location);
return location;
}
private class PlayerInfoListener implements Listener {
@@ -211,10 +211,10 @@ public class SpectateManagerImpl implements Loadable, SpectateManager {
final PlayerInfo info = playerManager.remove(player);
if (info != null) {
teleport.tryTeleport(player, info.getLocation());
teleport.tryTeleport(player, playerManager.getReturnLocation(info));
info.restore(player);
} else {
teleport.tryTeleport(player, playerManager.getLobby());
teleport.tryTeleport(player, playerManager.getReturnLocation(null));
}
final MatchImpl match = spectator.getArena().getMatch();
@@ -262,10 +262,6 @@ duel:
arena-whitelisted-worlds:
- 'world'
# If set to 'true', players will be teleported to the location where they were before the duel instead of duel lobby.
# default: false
teleport-to-last-location: true
# Seconds to wait before teleporting the winner after the duel.
# default: 5
teleport-delay: 3
-6
View File
@@ -96,7 +96,6 @@ ERROR:
invalid-action: '{PREFIX} &c''%action%'' is not a valid action. Available actions are: %available_actions%'
not-enough-money: '{PREFIX} &cYou do not have enough Diamonds to bet!'
opponent-not-enough-money: '{PREFIX} &c%name% only has %max% Diamond(s) and cannot cover a bet of &B%bet_amount% Diamond(s)&c.'
lobby-save-failure: '{PREFIX} &cCould not save lobby location. Please check the console for more information.'
name-not-alphanumeric: '{PREFIX} &c''%name%'' is not alphanumeric.'
@@ -236,8 +235,6 @@ COMMAND:
- '{HALF_LINE} &eUser Edit Commands {HALF_LINE}'
extra:
- '{HALF_LINE} &aExtra Commands {HALF_LINE}'
- '&f/%command% setlobby &e- &7Sets duel lobby location.'
- '&f/%command% lobby &e- &7Teleports to duel lobby.'
- '&f/%command% playsound [name] &e- &7Plays the selected sound if defined in config.'
- '&f/%command% reload <module> &e- &7Reloads the plugin or the specified module.'
- '{HALF_LINE} &aExtra Commands {HALF_LINE}'
@@ -254,8 +251,6 @@ COMMAND:
delete-queue: '{PREFIX} &7Deleted a queue with kit &d%kit% &7and a bet of &B%bet_amount% Diamond(s) &7.'
add-sign: '{PREFIX} &7Created queue sign at &3%location% &7with kit &d%kit% &7and bet &B%bet_amount% Diamond(s)&7.'
del-sign: '{PREFIX} &7Deleted queue sign at &3%location% &7with kit &d%kit% &7and bet &B%bet_amount% Diamond(s)&7.'
set-lobby: '{PREFIX} &7Duel lobby set at your current location.'
lobby: '{PREFIX} &7You have been teleported to lobby!'
edit: '{PREFIX} &7Following action has been executed for &6%name%&7: &6%action% %amount% %type%'
set-rating: '{PREFIX} &6%name%&7''s rating for kit &d%kit% &7was set to &a%rating%&7.'
reset-rating: '{PREFIX} &7Reset &6%name%&7''s &7rating for kit &d%kit%&7.'
@@ -278,7 +273,6 @@ COMMAND:
- '&7Kits: &9%kits%'
- '&7Queues: &b%queues%'
- '&7Queue Signs: &d%queue_signs%'
- '&7Duel lobby is located at &e%lobby%&7.'
- '{LINE}'
spectate: