diff --git a/Essentials/src/main/java/com/earth2me/essentials/AsyncTeleport.java b/Essentials/src/main/java/com/earth2me/essentials/AsyncTeleport.java index a4f40daf774..fc98e97e175 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/AsyncTeleport.java +++ b/Essentials/src/main/java/com/earth2me/essentials/AsyncTeleport.java @@ -7,7 +7,6 @@ import io.papermc.lib.PaperLib; import net.ess3.api.IEssentials; import net.ess3.api.IUser; -import net.ess3.api.InvalidWorldException; import net.ess3.api.TranslatableException; import net.ess3.api.events.UserWarpEvent; import net.ess3.api.events.teleport.PreTeleportEvent; @@ -424,7 +423,7 @@ public void warp(final IUser otherUser, String warp, final Trade chargeFor, fina final Location loc; try { loc = ess.getWarps().getWarp(warp); - } catch (final WarpNotFoundException | InvalidWorldException e) { + } catch (final WarpNotFoundException e) { future.completeExceptionally(e); return; } diff --git a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java index ad4e4719966..9e360f53841 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java @@ -358,6 +358,10 @@ public void onEnable() { upgrade.convertKits(); execTimer.mark("Kits"); + randomTeleport = new RandomTeleport(this); + confList.add(randomTeleport); + execTimer.mark("Init(RandomTeleport)"); + upgrade.afterSettings(); execTimer.mark("Upgrade3"); @@ -373,13 +377,6 @@ public void onEnable() { confList.add(itemDb); execTimer.mark("Init(ItemDB)"); - randomTeleport = new RandomTeleport(this); - if (randomTeleport.getPreCache()) { - randomTeleport.cacheRandomLocations(randomTeleport.getCenter(), randomTeleport.getMinRange(), randomTeleport.getMaxRange()); - } - confList.add(randomTeleport); - execTimer.mark("Init(RandomTeleport)"); - customItemResolver = new CustomItemResolver(this); try { itemDb.registerResolver(this, "custom_items", customItemResolver); diff --git a/Essentials/src/main/java/com/earth2me/essentials/EssentialsUpgrade.java b/Essentials/src/main/java/com/earth2me/essentials/EssentialsUpgrade.java index 740f722a9ff..753421909a3 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/EssentialsUpgrade.java +++ b/Essentials/src/main/java/com/earth2me/essentials/EssentialsUpgrade.java @@ -3,6 +3,7 @@ import com.earth2me.essentials.config.ConfigurateUtil; import com.earth2me.essentials.config.EssentialsConfiguration; import com.earth2me.essentials.config.EssentialsUserConfiguration; +import com.earth2me.essentials.config.entities.LazyLocation; import com.earth2me.essentials.craftbukkit.BanLookup; import com.earth2me.essentials.userstorage.ModernUUIDCache; import com.earth2me.essentials.utils.AdventureUtil; @@ -156,6 +157,39 @@ public static void uuidFileConvert(final IEssentials ess, final Boolean ignoreUF ess.getLogger().info("To rerun the conversion type /essentials uuidconvert"); } + public void updateRandomTeleport() { + if (doneFile.getBoolean("updateRandomTeleport", false)) { + return; + } + + final EssentialsConfiguration config = ess.getRandomTeleport().getConfig(); + + final LazyLocation center = config.getLocation("center"); + final Location centerLoc = center != null ? center.location() : null; + if (center != null && centerLoc != null) { + final double minRange = config.getDouble("min-range", Double.MIN_VALUE); + final double maxRange = config.getDouble("max-range", Double.MIN_VALUE); + for (final World world : ess.getServer().getWorlds()) { + final String propPrefix = "locations." + world.getName() + "."; + config.setProperty(propPrefix + "center", centerLoc); + + if (minRange != Double.MIN_VALUE) { + config.setProperty(propPrefix + "min-range", minRange); + } + if (maxRange != Double.MIN_VALUE) { + config.setProperty(propPrefix + "max-range", maxRange); + } + } + } + config.removeProperty("center"); + + config.blockingSave(); + + doneFile.setProperty("updateRandomTeleport", true); + doneFile.save(); + ess.getLogger().info("Done converting random teleport config."); + } + public void convertMailList() { if (doneFile.getBoolean("updateUsersMailList", false)) { return; @@ -1068,5 +1102,6 @@ public void afterSettings() { convertStupidCamelCaseUserdataKeys(); convertMailList(); purgeBrokenNpcAccounts(); + updateRandomTeleport(); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/ISettings.java b/Essentials/src/main/java/com/earth2me/essentials/ISettings.java index e725f8fa95a..cbeee9328af 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/ISettings.java +++ b/Essentials/src/main/java/com/earth2me/essentials/ISettings.java @@ -106,6 +106,10 @@ public interface ISettings extends IConf { boolean getRespawnAtHome(); + String getRandomSpawnLocation(); + + String getRandomRespawnLocation(); + boolean isRespawnAtAnchor(); Set getMultipleHomes(); diff --git a/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java b/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java index b1b683ab6fe..1529fd74430 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java +++ b/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java @@ -1,17 +1,22 @@ package com.earth2me.essentials; +import com.earth2me.essentials.config.ConfigurateUtil; import com.earth2me.essentials.config.EssentialsConfiguration; import com.earth2me.essentials.config.entities.LazyLocation; import com.earth2me.essentials.utils.LocationUtil; import com.earth2me.essentials.utils.VersionUtil; import io.papermc.lib.PaperLib; -import net.ess3.api.InvalidWorldException; import net.ess3.provider.BiomeKeyProvider; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.World; import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Queue; import java.util.Random; import java.util.Set; @@ -23,58 +28,72 @@ public class RandomTeleport implements IConf { private static final int HIGHEST_BLOCK_Y_OFFSET = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_R01) ? 1 : 0; private final IEssentials ess; private final EssentialsConfiguration config; - private final ConcurrentLinkedQueue cachedLocations = new ConcurrentLinkedQueue<>(); + private final Map> cachedLocations = new HashMap<>(); public RandomTeleport(final IEssentials essentials) { this.ess = essentials; config = new EssentialsConfiguration(new File(essentials.getDataFolder(), "tpr.yml"), "/tpr.yml", - "Configuration for the random teleport command.\nSome settings may be defaulted, and can be changed via the /settpr command in-game."); + "Configuration for the random teleport command.\nUse the /settpr command in-game to set random teleport locations."); reloadConfig(); } + public EssentialsConfiguration getConfig() { + return config; + } + @Override public void reloadConfig() { config.load(); cachedLocations.clear(); } - public Location getCenter() { - try { - final LazyLocation center = config.getLocation("center"); - if (center != null && center.location() != null) { - return center.location(); - } - } catch (final InvalidWorldException ignored) { + public boolean hasLocation(final String name) { + return config.hasProperty("locations." + name); + } + + public Location getCenter(final String name) { + final LazyLocation center = config.getLocation(locationKey(name, "center")); + if (center != null && center.location() != null) { + return center.location(); } - final Location center = ess.getServer().getWorlds().get(0).getWorldBorder().getCenter(); - center.setY(center.getWorld().getHighestBlockYAt(center) + HIGHEST_BLOCK_Y_OFFSET); - setCenter(center); - return center; + + final Location worldCenter = ess.getServer().getWorlds().get(0).getWorldBorder().getCenter(); + worldCenter.setY(worldCenter.getWorld().getHighestBlockYAt(worldCenter) + HIGHEST_BLOCK_Y_OFFSET); + setCenter(name, worldCenter); + return worldCenter; } - public void setCenter(final Location center) { - config.setProperty("center", center); + public void setCenter(final String name, final Location center) { + config.setProperty(locationKey(name, "center"), center); config.save(); } - public double getMinRange() { - return config.getDouble("min-range", 0d); + public double getMinRange(final String name) { + return config.getDouble(locationKey(name, "min-range"), 0d); } - public void setMinRange(final double minRange) { - config.setProperty("min-range", minRange); + public void setMinRange(final String name, final double minRange) { + config.setProperty(locationKey(name, "min-range"), minRange); config.save(); } - public double getMaxRange() { - return config.getDouble("max-range", getCenter().getWorld().getWorldBorder().getSize() / 2); + public double getMaxRange(final String name) { + return config.getDouble(locationKey(name, "max-range"), getCenter(name).getWorld().getWorldBorder().getSize() / 2); } - public void setMaxRange(final double maxRange) { - config.setProperty("max-range", maxRange); + public void setMaxRange(final String name, final double maxRange) { + config.setProperty(locationKey(name, "max-range"), maxRange); config.save(); } + public String getDefaultLocation() { + return config.getString("default-location", "{world}"); + } + + public boolean isPerLocationPermission() { + return config.getBoolean("per-location-permission", false); + } + public Set getExcludedBiomes() { final Set excludedBiomes = new HashSet<>(); for (final String key : config.getList("excluded-biomes", String.class)) { @@ -91,39 +110,48 @@ public int getCacheThreshold() { return config.getInt("cache-threshold", 10); } - public boolean getPreCache() { - return config.getBoolean("pre-cache", false); + public List listLocations() { + return new ArrayList<>(ConfigurateUtil.getKeys(config.getRootNode().node("locations"))); } - public Queue getCachedLocations() { - return cachedLocations; + public Queue getCachedLocations(final String name) { + this.cachedLocations.computeIfAbsent(name, x -> new ConcurrentLinkedQueue<>()); + return cachedLocations.get(name); } - // Get a random location; cached if possible. Otherwise on demand. - public CompletableFuture getRandomLocation(final Location center, final double minRange, final double maxRange) { - final int findAttempts = this.getFindAttempts(); - final Queue cachedLocations = this.getCachedLocations(); + // Get a named random teleport location; cached if possible, otherwise on demand. + public CompletableFuture getRandomLocation(final String name) { + final Queue cached = this.getCachedLocations(name); // Try to build up the cache if it is below the threshold - if (cachedLocations.size() < this.getCacheThreshold()) { - cacheRandomLocations(center, minRange, maxRange); + if (cached.size() < this.getCacheThreshold()) { + cacheRandomLocations(name); } final CompletableFuture future = new CompletableFuture<>(); // Return a random location immediately if one is available, otherwise try to find one now - if (cachedLocations.isEmpty()) { + if (cached.isEmpty()) { + final int findAttempts = this.getFindAttempts(); + final Location center = this.getCenter(name); + final double minRange = this.getMinRange(name); + final double maxRange = this.getMaxRange(name); attemptRandomLocation(findAttempts, center, minRange, maxRange).thenAccept(future::complete); } else { - future.complete(cachedLocations.poll()); + future.complete(cached.poll()); } return future; } - // Prompts caching random valid locations, up to a maximum number of attempts - public void cacheRandomLocations(final Location center, final double minRange, final double maxRange) { + // Get a random location with specific parameters (note: not cached). + public CompletableFuture getRandomLocation(final Location center, final double minRange, final double maxRange) { + return attemptRandomLocation(this.getFindAttempts(), center, minRange, maxRange); + } + + // Prompts caching random valid locations, up to a maximum number of attempts. + public void cacheRandomLocations(final String name) { ess.getServer().getScheduler().scheduleSyncDelayedTask(ess, () -> { for (int i = 0; i < this.getFindAttempts(); ++i) { - calculateRandomLocation(center, minRange, maxRange).thenAccept(location -> { + calculateRandomLocation(getCenter(name), getMinRange(name), getMaxRange(name)).thenAccept(location -> { if (isValidRandomLocation(location)) { - this.getCachedLocations().add(location); + this.getCachedLocations(name).add(location); } }); } @@ -188,14 +216,18 @@ private CompletableFuture calculateRandomLocation(final Location cente return future; } - // Returns an appropriate elevation for a given location in the nether, or -1 if none is found + // Returns an appropriate elevation for a given location in the nether, or MIN_VALUE if none is found private double getNetherYAt(final Location location) { - for (int y = 32; y < ess.getWorldInfoProvider().getMaxHeight(location.getWorld()); ++y) { - if (!LocationUtil.isBlockUnsafe(ess, location.getWorld(), location.getBlockX(), y, location.getBlockZ())) { + final World world = location.getWorld(); + for (int y = 32; y < ess.getWorldInfoProvider().getMaxHeight(world); ++y) { + if (Material.BEDROCK.equals(world.getBlockAt(location.getBlockX(), y, location.getBlockZ()).getType())) { + break; + } + if (!LocationUtil.isBlockUnsafe(ess, world, location.getBlockX(), y, location.getBlockZ())) { return y; } } - return -1; + return Double.MIN_VALUE; } private boolean isValidRandomLocation(final Location location) { @@ -226,6 +258,10 @@ private boolean isExcludedBiome(final Location location) { return excluded.contains(biomeKey); } + private String locationKey(final String name, final String key) { + return "locations." + name + "." + key; + } + public File getFile() { return config.getFile(); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/Settings.java b/Essentials/src/main/java/com/earth2me/essentials/Settings.java index 07ab7c3b2c4..15a4c6ef985 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Settings.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Settings.java @@ -163,6 +163,16 @@ public boolean getRespawnAtHome() { return config.getBoolean("respawn-at-home", false); } + @Override + public String getRandomSpawnLocation() { + return config.getString("random-spawn-location", "none"); + } + + @Override + public String getRandomRespawnLocation() { + return config.getString("random-respawn-location", "none"); + } + @Override public boolean isRespawnAtAnchor() { return config.getBoolean("respawn-at-anchor", false); diff --git a/Essentials/src/main/java/com/earth2me/essentials/Warps.java b/Essentials/src/main/java/com/earth2me/essentials/Warps.java index 84d5dc79f8f..37b8cc752c8 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Warps.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Warps.java @@ -5,7 +5,6 @@ import com.earth2me.essentials.utils.AdventureUtil; import com.earth2me.essentials.utils.StringUtil; import net.ess3.api.InvalidNameException; -import net.ess3.api.InvalidWorldException; import net.ess3.api.TranslatableException; import org.bukkit.Location; @@ -54,7 +53,7 @@ public Collection getList() { } @Override - public Location getWarp(final String warp) throws WarpNotFoundException, InvalidWorldException { + public Location getWarp(final String warp) throws WarpNotFoundException { final EssentialsConfiguration conf = warpPoints.get(new StringIgnoreCase(warp)); if (conf == null) { throw new WarpNotFoundException(); diff --git a/Essentials/src/main/java/com/earth2me/essentials/api/IWarps.java b/Essentials/src/main/java/com/earth2me/essentials/api/IWarps.java index d9af55ab6fd..93ed13f1a65 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/api/IWarps.java +++ b/Essentials/src/main/java/com/earth2me/essentials/api/IWarps.java @@ -22,9 +22,8 @@ public interface IWarps extends IConf { * @param warp - Warp name * @return - Location the warp is set to * @throws WarpNotFoundException When the warp is not found - * @throws net.ess3.api.InvalidWorldException When the world the warp is in is not found */ - Location getWarp(String warp) throws WarpNotFoundException, net.ess3.api.InvalidWorldException; + Location getWarp(String warp) throws WarpNotFoundException; /** * Checks if the provided name is a warp. diff --git a/Essentials/src/main/java/com/earth2me/essentials/api/InvalidWorldException.java b/Essentials/src/main/java/com/earth2me/essentials/api/InvalidWorldException.java deleted file mode 100644 index 670d229cc5f..00000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/api/InvalidWorldException.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.earth2me.essentials.api; - -import net.ess3.api.TranslatableException; - -/** - * @deprecated This exception is unused. Use {@link net.ess3.api.InvalidWorldException} instead. - */ -@Deprecated -public class InvalidWorldException extends TranslatableException { - private final String world; - - public InvalidWorldException(final String world) { - super("invalidWorld"); - this.world = world; - } - - public String getWorld() { - return this.world; - } -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsettpr.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsettpr.java index 18fe69663c5..4e4d0c21cb6 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsettpr.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsettpr.java @@ -3,10 +3,12 @@ import com.earth2me.essentials.RandomTeleport; import com.earth2me.essentials.User; import org.bukkit.Server; +import org.bukkit.World; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; public class Commandsettpr extends EssentialsCommand { public Commandsettpr() { @@ -15,22 +17,20 @@ public Commandsettpr() { @Override protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception { - if (args.length == 0) { + if (args.length < 2) { throw new NotEnoughArgumentsException(); } - final RandomTeleport randomTeleport = ess.getRandomTeleport(); - randomTeleport.getCachedLocations().clear(); - if ("center".equalsIgnoreCase(args[0])) { - randomTeleport.setCenter(user.getLocation()); + if ("center".equalsIgnoreCase(args[1])) { + randomTeleport.setCenter(args[0], user.getLocation()); user.sendTl("settpr"); - } else if (args.length > 1) { - if ("minrange".equalsIgnoreCase(args[0])) { - randomTeleport.setMinRange(Double.parseDouble(args[1])); - } else if ("maxrange".equalsIgnoreCase(args[0])) { - randomTeleport.setMaxRange(Double.parseDouble(args[1])); + } else if (args.length > 2) { + if ("minrange".equalsIgnoreCase(args[1])) { + randomTeleport.setMinRange(args[0], Double.parseDouble(args[2])); + } else if ("maxrange".equalsIgnoreCase(args[1])) { + randomTeleport.setMaxRange(args[0], Double.parseDouble(args[2])); } - user.sendTl("settprValue", args[0].toLowerCase(), args[1].toLowerCase()); + user.sendTl("settprValue", args[1].toLowerCase(), args[2].toLowerCase()); } else { throw new NotEnoughArgumentsException(); } @@ -39,6 +39,8 @@ protected void run(final Server server, final User user, final String commandLab @Override protected List getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) { if (args.length == 1) { + return user.getServer().getWorlds().stream().map(World::getName).collect(Collectors.toList()); + } else if (args.length == 2) { return Arrays.asList("center", "minrange", "maxrange"); } return Collections.emptyList(); diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsetwarp.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsetwarp.java index 8f5af697533..f5adff26d03 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsetwarp.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsetwarp.java @@ -4,7 +4,6 @@ import com.earth2me.essentials.api.IWarps; import com.earth2me.essentials.utils.NumberUtil; import com.earth2me.essentials.utils.StringUtil; -import net.ess3.api.InvalidWorldException; import net.ess3.api.TranslatableException; import net.essentialsx.api.v2.events.WarpModifyEvent; import org.bukkit.Bukkit; @@ -31,7 +30,7 @@ public void run(final Server server, final User user, final String commandLabel, try { warpLoc = warps.getWarp(args[0]); - } catch (final WarpNotFoundException | InvalidWorldException ignored) { + } catch (final WarpNotFoundException ignored) { } if (warpLoc == null) { final WarpModifyEvent event = new WarpModifyEvent(user, args[0], null, user.getLocation(), WarpModifyEvent.WarpModifyCause.CREATE); diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtpr.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtpr.java index 14ab13192f0..589a7f7c6f4 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtpr.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtpr.java @@ -1,8 +1,10 @@ package com.earth2me.essentials.commands; +import com.earth2me.essentials.CommandSource; import com.earth2me.essentials.RandomTeleport; import com.earth2me.essentials.Trade; import com.earth2me.essentials.User; +import net.ess3.api.TranslatableException; import net.ess3.api.events.UserRandomTeleportEvent; import org.bukkit.Server; import org.bukkit.event.player.PlayerTeleportEvent; @@ -10,6 +12,7 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; public class Commandtpr extends EssentialsCommand { @@ -22,25 +25,67 @@ protected void run(final Server server, final User user, final String commandLab final Trade charge = new Trade(this.getName(), ess); charge.isAffordableFor(user); final RandomTeleport randomTeleport = ess.getRandomTeleport(); - final UserRandomTeleportEvent event = new UserRandomTeleportEvent(user, randomTeleport.getCenter(), randomTeleport.getMinRange(), randomTeleport.getMaxRange()); + final String defaultLocation = randomTeleport.getDefaultLocation().replace("{world}", user.getLocation().getWorld().getName()); + final String name = args.length > 0 ? args[0] : defaultLocation; + final User userToTeleport = args.length > 1 && user.isAuthorized("essentials.tpr.others") ? getPlayer(server, user, args, 1) : user; + if (randomTeleport.isPerLocationPermission() && !user.isAuthorized("essentials.tpr.location." + name)) { + throw new TranslatableException("warpUsePermission"); + } + final UserRandomTeleportEvent event = new UserRandomTeleportEvent(userToTeleport, name, randomTeleport.getCenter(name), randomTeleport.getMinRange(name), randomTeleport.getMaxRange(name)); server.getPluginManager().callEvent(event); if (event.isCancelled()) { return; } - randomTeleport.getRandomLocation(event.getCenter(), event.getMinRange(), event.getMaxRange()).thenAccept(location -> { - final CompletableFuture future = getNewExceptionFuture(user.getSource(), commandLabel); - user.getAsyncTeleport().teleport(location, charge, PlayerTeleportEvent.TeleportCause.COMMAND, future); - future.thenAccept(success -> { - if (success) { - user.sendTl("tprSuccess"); - } - }); - }); + (event.isModified() ? randomTeleport.getRandomLocation(event.getCenter(), event.getMinRange(), event.getMaxRange()) : randomTeleport.getRandomLocation(name)) + .thenAccept(location -> { + final CompletableFuture future = getNewExceptionFuture(user.getSource(), commandLabel); + future.thenAccept(success -> { + if (success) { + userToTeleport.sendTl("tprSuccess"); + } + }); + userToTeleport.getAsyncTeleport().teleport(location, charge, PlayerTeleportEvent.TeleportCause.COMMAND, future); + }); throw new NoChargeException(); } @Override - protected List getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) { + protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception { + if (args.length < 2) { + throw new NotEnoughArgumentsException(); + } + final RandomTeleport randomTeleport = ess.getRandomTeleport(); + final User userToTeleport = getPlayer(server, sender, args, 1); + final String name = args[0]; + final UserRandomTeleportEvent event = new UserRandomTeleportEvent(userToTeleport, name, randomTeleport.getCenter(name), randomTeleport.getMinRange(name), randomTeleport.getMaxRange(name)); + server.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + (event.isModified() ? randomTeleport.getRandomLocation(event.getCenter(), event.getMinRange(), event.getMaxRange()) : randomTeleport.getRandomLocation(name)) + .thenAccept(location -> { + final CompletableFuture future = getNewExceptionFuture(sender, commandLabel); + future.thenAccept(success -> { + if (success) { + userToTeleport.sendTl("tprSuccess"); + } + }); + userToTeleport.getAsyncTeleport().now(location, false, PlayerTeleportEvent.TeleportCause.COMMAND, future); + }); + } + + @Override + protected List getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) { + final RandomTeleport randomTeleport = ess.getRandomTeleport(); + if (args.length == 1) { + if (randomTeleport.isPerLocationPermission()) { + return randomTeleport.listLocations().stream().filter(name -> sender.isAuthorized("essentials.tpr.location." + name)).collect(Collectors.toList()); + } else { + return randomTeleport.listLocations(); + } + } else if (args.length == 2 && sender.isAuthorized("essentials.tpr.others")) { + return getPlayers(server, sender); + } return Collections.emptyList(); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsConfiguration.java b/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsConfiguration.java index 2974a17c9e3..95d97ce9565 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsConfiguration.java +++ b/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsConfiguration.java @@ -13,7 +13,6 @@ import com.earth2me.essentials.config.serializers.MailMessageSerializer; import com.earth2me.essentials.config.serializers.MaterialTypeSerializer; import com.earth2me.essentials.utils.AdventureUtil; -import net.ess3.api.InvalidWorldException; import net.essentialsx.api.v2.services.mail.MailMessage; import org.bukkit.Location; import org.bukkit.Material; @@ -123,7 +122,7 @@ public void setProperty(String path, final Location location) { setInternal(path, LazyLocation.fromLocation(location)); } - public LazyLocation getLocation(final String path) throws InvalidWorldException { + public LazyLocation getLocation(final String path) { final CommentedConfigurationNode node = path == null ? getRootNode() : getSection(path); if (node == null) { return null; diff --git a/Essentials/src/main/java/com/earth2me/essentials/signs/SignRandomTeleport.java b/Essentials/src/main/java/com/earth2me/essentials/signs/SignRandomTeleport.java new file mode 100644 index 00000000000..8ffaf7bb2de --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/signs/SignRandomTeleport.java @@ -0,0 +1,32 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.ChargeException; +import com.earth2me.essentials.RandomTeleport; +import com.earth2me.essentials.User; +import net.ess3.api.IEssentials; +import net.ess3.api.MaxMoneyException; +import org.bukkit.event.player.PlayerTeleportEvent; + +import java.util.concurrent.CompletableFuture; + +public class SignRandomTeleport extends EssentialsSign { + public SignRandomTeleport() { + super("RandomTeleport"); + } + + @Override + protected boolean onSignInteract(ISign sign, User player, String username, IEssentials ess) throws SignException, ChargeException, MaxMoneyException { + final String name = sign.getLine(1); + final RandomTeleport randomTeleport = ess.getRandomTeleport(); + randomTeleport.getRandomLocation(name).thenAccept(location -> { + final CompletableFuture future = new CompletableFuture<>(); + future.thenAccept(success -> { + if (success) { + player.sendTl("tprSuccess"); + } + }); + player.getAsyncTeleport().now(location, false, PlayerTeleportEvent.TeleportCause.COMMAND, future); + }); + return true; + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/signs/Signs.java b/Essentials/src/main/java/com/earth2me/essentials/signs/Signs.java index 1d2fab98054..594e625b2b7 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/signs/Signs.java +++ b/Essentials/src/main/java/com/earth2me/essentials/signs/Signs.java @@ -25,7 +25,8 @@ public enum Signs { TRADE(new SignTrade()), WARP(new SignWarp()), WEATHER(new SignWeather()), - WORKBENCH(new SignWorkbench()); + WORKBENCH(new SignWorkbench()), + RANDOMTELEPORT(new SignRandomTeleport()); private final EssentialsSign sign; Signs(final EssentialsSign sign) { diff --git a/Essentials/src/main/java/net/ess3/api/InvalidWorldException.java b/Essentials/src/main/java/net/ess3/api/InvalidWorldException.java deleted file mode 100644 index 4a536fdda89..00000000000 --- a/Essentials/src/main/java/net/ess3/api/InvalidWorldException.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.ess3.api; - -/** - * Fired when trying to teleport a user to an invalid world. This usually only occurs if a world has been removed from - * the server and a player tries to teleport to a warp or home in that world. - */ -public class InvalidWorldException extends TranslatableException { - private final String world; - - public InvalidWorldException(final String world) { - super("invalidWorld"); - this.world = world; - } - - public String getWorld() { - return this.world; - } -} diff --git a/Essentials/src/main/java/net/ess3/api/events/UserRandomTeleportEvent.java b/Essentials/src/main/java/net/ess3/api/events/UserRandomTeleportEvent.java index d7dc4403da1..d31b2f03631 100644 --- a/Essentials/src/main/java/net/ess3/api/events/UserRandomTeleportEvent.java +++ b/Essentials/src/main/java/net/ess3/api/events/UserRandomTeleportEvent.java @@ -14,14 +14,17 @@ public class UserRandomTeleportEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final IUser user; + private String name; private Location center; private double minRange; private double maxRange; private boolean cancelled = false; + private boolean modified = false; - public UserRandomTeleportEvent(final IUser user, final Location center, final double minRange, final double maxRange) { + public UserRandomTeleportEvent(final IUser user, final String name, final Location center, final double minRange, final double maxRange) { super(!Bukkit.isPrimaryThread()); this.user = user; + this.name = name; this.center = center; this.minRange = minRange; this.maxRange = maxRange; @@ -35,11 +38,23 @@ public IUser getUser() { return user; } + public String getName() { + return name; + } + public Location getCenter() { return center; } + /** + * Sets the center location to teleport from. + * + * @param center Center location. + */ public void setCenter(final Location center) { + if (!this.center.equals(center)) { + modified = true; + } this.center = center; } @@ -47,7 +62,15 @@ public double getMinRange() { return minRange; } + /** + * Sets the minimum range for the teleport. + * + * @param minRange Minimum range. + */ public void setMinRange(final double minRange) { + if (this.minRange != minRange) { + modified = true; + } this.minRange = minRange; } @@ -55,7 +78,15 @@ public double getMaxRange() { return maxRange; } + /** + * Sets the maximum range for the teleport. + * + * @param maxRange Maximum range. + */ public void setMaxRange(final double maxRange) { + if (this.maxRange != maxRange) { + modified = true; + } this.maxRange = maxRange; } @@ -69,6 +100,10 @@ public void setCancelled(final boolean b) { cancelled = b; } + public boolean isModified() { + return modified; + } + @Override public HandlerList getHandlers() { return handlers; diff --git a/Essentials/src/main/resources/config.yml b/Essentials/src/main/resources/config.yml index e477f037b93..b796a51b2c9 100644 --- a/Essentials/src/main/resources/config.yml +++ b/Essentials/src/main/resources/config.yml @@ -387,6 +387,7 @@ enabledSigns: #- loom #- smithing #- workbench + #- randomteleport # How many times per second can Essentials signs be interacted with per player. # Values should be between 1-20, 20 being virtually no lag protection. @@ -935,7 +936,7 @@ chat: # If you are using group formats make sure to remove the '#' to allow the setting to be read. # Note: Group names are case-sensitive so you must match them up with your permission plugin. - + # You can use permissions to control whether players can use formatting codes in their chat messages. # See https://essentialsx.net/wiki/Color-Permissions.html for more information. @@ -1197,6 +1198,12 @@ respawn-at-home-bed: true # When users die, should EssentialsSpawn respect users' respawn anchors? respawn-at-anchor: false +# If configured, users will spawn at the random spawn location instead of the newbies spawnpoint. +random-spawn-location: "none" + +# If configured, when users die, they will respawn at the random respawn location. +random-respawn-location: "none" + # Teleport all joining players to the spawnpoint spawn-on-join: false # The following value of `guests` states that all players in group `guests` will be teleported to spawn when joining. diff --git a/Essentials/src/main/resources/tpr.yml b/Essentials/src/main/resources/tpr.yml index fcf721e7dd6..fdaf3c7209b 100644 --- a/Essentials/src/main/resources/tpr.yml +++ b/Essentials/src/main/resources/tpr.yml @@ -1,6 +1,6 @@ # Configuration for the random teleport command. # Some settings may be defaulted, and can be changed via the /settpr command in-game. -min-range: 0.0 +default-location: '{world}' excluded-biomes: - cold_ocean - deep_cold_ocean diff --git a/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/EssentialsSpawnPlayerListener.java b/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/EssentialsSpawnPlayerListener.java index c4f21315e92..3e1078f54a1 100644 --- a/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/EssentialsSpawnPlayerListener.java +++ b/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/EssentialsSpawnPlayerListener.java @@ -12,6 +12,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import java.util.List; @@ -64,6 +65,9 @@ void onPlayerRespawn(final PlayerRespawnEvent event) { return; } } + if (tryRandomTeleport(user, ess.getSettings().getRandomRespawnLocation())) { + return; + } final Location spawn = spawns.getSpawn(user.getGroup()); if (spawn != null) { event.setRespawnLocation(spawn); @@ -102,7 +106,9 @@ private void delayedJoin(final Player player) { final User user = ess.getUser(player); - if (!"none".equalsIgnoreCase(ess.getSettings().getNewbieSpawn())) { + final boolean spawnRandomly = tryRandomTeleport(user, ess.getSettings().getRandomSpawnLocation()); + + if (!spawnRandomly && !"none".equalsIgnoreCase(ess.getSettings().getNewbieSpawn())) { ess.scheduleSyncDelayedTask(new NewPlayerTeleport(user), 1L); } @@ -158,4 +164,15 @@ public void run() { } } } + + private boolean tryRandomTeleport(final User user, final String name) { + if (!ess.getRandomTeleport().hasLocation(name)) { + return false; + } + ess.getRandomTeleport().getRandomLocation(name).thenAccept(location -> { + final CompletableFuture future = new CompletableFuture<>(); + user.getAsyncTeleport().now(location, false, PlayerTeleportEvent.TeleportCause.PLUGIN, future); + }); + return true; + } }