Improvements to Random Teleport (#4271)

Co-authored-by: triagonal <10545540+triagonal@users.noreply.github.com>
Co-authored-by: Josh Roy <10731363+JRoy@users.noreply.github.com>
This commit is contained in:
pop4959 2024-11-24 15:07:18 -08:00 committed by GitHub
parent 1778bf5ada
commit 2418a6fb78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 304 additions and 126 deletions

View File

@ -7,7 +7,6 @@ import com.earth2me.essentials.utils.LocationUtil;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import net.ess3.api.IEssentials; import net.ess3.api.IEssentials;
import net.ess3.api.IUser; import net.ess3.api.IUser;
import net.ess3.api.InvalidWorldException;
import net.ess3.api.TranslatableException; import net.ess3.api.TranslatableException;
import net.ess3.api.events.UserWarpEvent; import net.ess3.api.events.UserWarpEvent;
import net.ess3.api.events.teleport.PreTeleportEvent; import net.ess3.api.events.teleport.PreTeleportEvent;
@ -424,7 +423,7 @@ public class AsyncTeleport implements IAsyncTeleport {
final Location loc; final Location loc;
try { try {
loc = ess.getWarps().getWarp(warp); loc = ess.getWarps().getWarp(warp);
} catch (final WarpNotFoundException | InvalidWorldException e) { } catch (final WarpNotFoundException e) {
future.completeExceptionally(e); future.completeExceptionally(e);
return; return;
} }

View File

@ -358,6 +358,10 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
upgrade.convertKits(); upgrade.convertKits();
execTimer.mark("Kits"); execTimer.mark("Kits");
randomTeleport = new RandomTeleport(this);
confList.add(randomTeleport);
execTimer.mark("Init(RandomTeleport)");
upgrade.afterSettings(); upgrade.afterSettings();
execTimer.mark("Upgrade3"); execTimer.mark("Upgrade3");
@ -373,13 +377,6 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
confList.add(itemDb); confList.add(itemDb);
execTimer.mark("Init(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); customItemResolver = new CustomItemResolver(this);
try { try {
itemDb.registerResolver(this, "custom_items", customItemResolver); itemDb.registerResolver(this, "custom_items", customItemResolver);

View File

@ -3,6 +3,7 @@ package com.earth2me.essentials;
import com.earth2me.essentials.config.ConfigurateUtil; import com.earth2me.essentials.config.ConfigurateUtil;
import com.earth2me.essentials.config.EssentialsConfiguration; import com.earth2me.essentials.config.EssentialsConfiguration;
import com.earth2me.essentials.config.EssentialsUserConfiguration; import com.earth2me.essentials.config.EssentialsUserConfiguration;
import com.earth2me.essentials.config.entities.LazyLocation;
import com.earth2me.essentials.craftbukkit.BanLookup; import com.earth2me.essentials.craftbukkit.BanLookup;
import com.earth2me.essentials.userstorage.ModernUUIDCache; import com.earth2me.essentials.userstorage.ModernUUIDCache;
import com.earth2me.essentials.utils.AdventureUtil; import com.earth2me.essentials.utils.AdventureUtil;
@ -156,6 +157,39 @@ public class EssentialsUpgrade {
ess.getLogger().info("To rerun the conversion type /essentials uuidconvert"); 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() { public void convertMailList() {
if (doneFile.getBoolean("updateUsersMailList", false)) { if (doneFile.getBoolean("updateUsersMailList", false)) {
return; return;
@ -1068,5 +1102,6 @@ public class EssentialsUpgrade {
convertStupidCamelCaseUserdataKeys(); convertStupidCamelCaseUserdataKeys();
convertMailList(); convertMailList();
purgeBrokenNpcAccounts(); purgeBrokenNpcAccounts();
updateRandomTeleport();
} }
} }

View File

@ -106,6 +106,10 @@ public interface ISettings extends IConf {
boolean getRespawnAtHome(); boolean getRespawnAtHome();
String getRandomSpawnLocation();
String getRandomRespawnLocation();
boolean isRespawnAtAnchor(); boolean isRespawnAtAnchor();
Set getMultipleHomes(); Set getMultipleHomes();

View File

@ -1,17 +1,22 @@
package com.earth2me.essentials; package com.earth2me.essentials;
import com.earth2me.essentials.config.ConfigurateUtil;
import com.earth2me.essentials.config.EssentialsConfiguration; import com.earth2me.essentials.config.EssentialsConfiguration;
import com.earth2me.essentials.config.entities.LazyLocation; import com.earth2me.essentials.config.entities.LazyLocation;
import com.earth2me.essentials.utils.LocationUtil; import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.VersionUtil; import com.earth2me.essentials.utils.VersionUtil;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import net.ess3.api.InvalidWorldException;
import net.ess3.provider.BiomeKeyProvider; import net.ess3.provider.BiomeKeyProvider;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.Random; import java.util.Random;
import java.util.Set; 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 static final int HIGHEST_BLOCK_Y_OFFSET = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_R01) ? 1 : 0;
private final IEssentials ess; private final IEssentials ess;
private final EssentialsConfiguration config; private final EssentialsConfiguration config;
private final ConcurrentLinkedQueue<Location> cachedLocations = new ConcurrentLinkedQueue<>(); private final Map<String, ConcurrentLinkedQueue<Location>> cachedLocations = new HashMap<>();
public RandomTeleport(final IEssentials essentials) { public RandomTeleport(final IEssentials essentials) {
this.ess = essentials; this.ess = essentials;
config = new EssentialsConfiguration(new File(essentials.getDataFolder(), "tpr.yml"), "/tpr.yml", 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(); reloadConfig();
} }
public EssentialsConfiguration getConfig() {
return config;
}
@Override @Override
public void reloadConfig() { public void reloadConfig() {
config.load(); config.load();
cachedLocations.clear(); cachedLocations.clear();
} }
public Location getCenter() { public boolean hasLocation(final String name) {
try { return config.hasProperty("locations." + name);
final LazyLocation center = config.getLocation("center"); }
public Location getCenter(final String name) {
final LazyLocation center = config.getLocation(locationKey(name, "center"));
if (center != null && center.location() != null) { if (center != null && center.location() != null) {
return center.location(); return center.location();
} }
} catch (final InvalidWorldException ignored) {
} final Location worldCenter = ess.getServer().getWorlds().get(0).getWorldBorder().getCenter();
final Location center = ess.getServer().getWorlds().get(0).getWorldBorder().getCenter(); worldCenter.setY(worldCenter.getWorld().getHighestBlockYAt(worldCenter) + HIGHEST_BLOCK_Y_OFFSET);
center.setY(center.getWorld().getHighestBlockYAt(center) + HIGHEST_BLOCK_Y_OFFSET); setCenter(name, worldCenter);
setCenter(center); return worldCenter;
return center;
} }
public void setCenter(final Location center) { public void setCenter(final String name, final Location center) {
config.setProperty("center", center); config.setProperty(locationKey(name, "center"), center);
config.save(); config.save();
} }
public double getMinRange() { public double getMinRange(final String name) {
return config.getDouble("min-range", 0d); return config.getDouble(locationKey(name, "min-range"), 0d);
} }
public void setMinRange(final double minRange) { public void setMinRange(final String name, final double minRange) {
config.setProperty("min-range", minRange); config.setProperty(locationKey(name, "min-range"), minRange);
config.save(); config.save();
} }
public double getMaxRange() { public double getMaxRange(final String name) {
return config.getDouble("max-range", getCenter().getWorld().getWorldBorder().getSize() / 2); return config.getDouble(locationKey(name, "max-range"), getCenter(name).getWorld().getWorldBorder().getSize() / 2);
} }
public void setMaxRange(final double maxRange) { public void setMaxRange(final String name, final double maxRange) {
config.setProperty("max-range", maxRange); config.setProperty(locationKey(name, "max-range"), maxRange);
config.save(); config.save();
} }
public String getDefaultLocation() {
return config.getString("default-location", "{world}");
}
public boolean isPerLocationPermission() {
return config.getBoolean("per-location-permission", false);
}
public Set<String> getExcludedBiomes() { public Set<String> getExcludedBiomes() {
final Set<String> excludedBiomes = new HashSet<>(); final Set<String> excludedBiomes = new HashSet<>();
for (final String key : config.getList("excluded-biomes", String.class)) { for (final String key : config.getList("excluded-biomes", String.class)) {
@ -91,39 +110,48 @@ public class RandomTeleport implements IConf {
return config.getInt("cache-threshold", 10); return config.getInt("cache-threshold", 10);
} }
public boolean getPreCache() { public List<String> listLocations() {
return config.getBoolean("pre-cache", false); return new ArrayList<>(ConfigurateUtil.getKeys(config.getRootNode().node("locations")));
} }
public Queue<Location> getCachedLocations() { public Queue<Location> getCachedLocations(final String name) {
return cachedLocations; this.cachedLocations.computeIfAbsent(name, x -> new ConcurrentLinkedQueue<>());
return cachedLocations.get(name);
} }
// Get a random location; cached if possible. Otherwise on demand. // Get a named random teleport location; cached if possible, otherwise on demand.
public CompletableFuture<Location> getRandomLocation(final Location center, final double minRange, final double maxRange) { public CompletableFuture<Location> getRandomLocation(final String name) {
final int findAttempts = this.getFindAttempts(); final Queue<Location> cached = this.getCachedLocations(name);
final Queue<Location> cachedLocations = this.getCachedLocations();
// Try to build up the cache if it is below the threshold // Try to build up the cache if it is below the threshold
if (cachedLocations.size() < this.getCacheThreshold()) { if (cached.size() < this.getCacheThreshold()) {
cacheRandomLocations(center, minRange, maxRange); cacheRandomLocations(name);
} }
final CompletableFuture<Location> future = new CompletableFuture<>(); final CompletableFuture<Location> future = new CompletableFuture<>();
// Return a random location immediately if one is available, otherwise try to find one now // 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); attemptRandomLocation(findAttempts, center, minRange, maxRange).thenAccept(future::complete);
} else { } else {
future.complete(cachedLocations.poll()); future.complete(cached.poll());
} }
return future; return future;
} }
// Prompts caching random valid locations, up to a maximum number of attempts // Get a random location with specific parameters (note: not cached).
public void cacheRandomLocations(final Location center, final double minRange, final double maxRange) { public CompletableFuture<Location> 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, () -> { ess.getServer().getScheduler().scheduleSyncDelayedTask(ess, () -> {
for (int i = 0; i < this.getFindAttempts(); ++i) { 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)) { if (isValidRandomLocation(location)) {
this.getCachedLocations().add(location); this.getCachedLocations(name).add(location);
} }
}); });
} }
@ -188,14 +216,18 @@ public class RandomTeleport implements IConf {
return future; 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) { private double getNetherYAt(final Location location) {
for (int y = 32; y < ess.getWorldInfoProvider().getMaxHeight(location.getWorld()); ++y) { final World world = location.getWorld();
if (!LocationUtil.isBlockUnsafe(ess, location.getWorld(), location.getBlockX(), y, location.getBlockZ())) { 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 y;
} }
} }
return -1; return Double.MIN_VALUE;
} }
private boolean isValidRandomLocation(final Location location) { private boolean isValidRandomLocation(final Location location) {
@ -226,6 +258,10 @@ public class RandomTeleport implements IConf {
return excluded.contains(biomeKey); return excluded.contains(biomeKey);
} }
private String locationKey(final String name, final String key) {
return "locations." + name + "." + key;
}
public File getFile() { public File getFile() {
return config.getFile(); return config.getFile();
} }

View File

@ -163,6 +163,16 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("respawn-at-home", false); 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 @Override
public boolean isRespawnAtAnchor() { public boolean isRespawnAtAnchor() {
return config.getBoolean("respawn-at-anchor", false); return config.getBoolean("respawn-at-anchor", false);

View File

@ -5,7 +5,6 @@ import com.earth2me.essentials.config.EssentialsConfiguration;
import com.earth2me.essentials.utils.AdventureUtil; import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.StringUtil; import com.earth2me.essentials.utils.StringUtil;
import net.ess3.api.InvalidNameException; import net.ess3.api.InvalidNameException;
import net.ess3.api.InvalidWorldException;
import net.ess3.api.TranslatableException; import net.ess3.api.TranslatableException;
import org.bukkit.Location; import org.bukkit.Location;
@ -54,7 +53,7 @@ public class Warps implements IConf, net.ess3.api.IWarps {
} }
@Override @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)); final EssentialsConfiguration conf = warpPoints.get(new StringIgnoreCase(warp));
if (conf == null) { if (conf == null) {
throw new WarpNotFoundException(); throw new WarpNotFoundException();

View File

@ -22,9 +22,8 @@ public interface IWarps extends IConf {
* @param warp - Warp name * @param warp - Warp name
* @return - Location the warp is set to * @return - Location the warp is set to
* @throws WarpNotFoundException When the warp is not found * @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. * Checks if the provided name is a warp.

View File

@ -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;
}
}

View File

@ -3,10 +3,12 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.RandomTeleport; import com.earth2me.essentials.RandomTeleport;
import com.earth2me.essentials.User; import com.earth2me.essentials.User;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.World;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
public class Commandsettpr extends EssentialsCommand { public class Commandsettpr extends EssentialsCommand {
public Commandsettpr() { public Commandsettpr() {
@ -15,22 +17,20 @@ public class Commandsettpr extends EssentialsCommand {
@Override @Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception { 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(); throw new NotEnoughArgumentsException();
} }
final RandomTeleport randomTeleport = ess.getRandomTeleport(); final RandomTeleport randomTeleport = ess.getRandomTeleport();
randomTeleport.getCachedLocations().clear(); if ("center".equalsIgnoreCase(args[1])) {
if ("center".equalsIgnoreCase(args[0])) { randomTeleport.setCenter(args[0], user.getLocation());
randomTeleport.setCenter(user.getLocation());
user.sendTl("settpr"); user.sendTl("settpr");
} else if (args.length > 1) { } else if (args.length > 2) {
if ("minrange".equalsIgnoreCase(args[0])) { if ("minrange".equalsIgnoreCase(args[1])) {
randomTeleport.setMinRange(Double.parseDouble(args[1])); randomTeleport.setMinRange(args[0], Double.parseDouble(args[2]));
} else if ("maxrange".equalsIgnoreCase(args[0])) { } else if ("maxrange".equalsIgnoreCase(args[1])) {
randomTeleport.setMaxRange(Double.parseDouble(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 { } else {
throw new NotEnoughArgumentsException(); throw new NotEnoughArgumentsException();
} }
@ -39,6 +39,8 @@ public class Commandsettpr extends EssentialsCommand {
@Override @Override
protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) { protected List<String> getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) {
if (args.length == 1) { 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 Arrays.asList("center", "minrange", "maxrange");
} }
return Collections.emptyList(); return Collections.emptyList();

View File

@ -4,7 +4,6 @@ import com.earth2me.essentials.User;
import com.earth2me.essentials.api.IWarps; import com.earth2me.essentials.api.IWarps;
import com.earth2me.essentials.utils.NumberUtil; import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil; import com.earth2me.essentials.utils.StringUtil;
import net.ess3.api.InvalidWorldException;
import net.ess3.api.TranslatableException; import net.ess3.api.TranslatableException;
import net.essentialsx.api.v2.events.WarpModifyEvent; import net.essentialsx.api.v2.events.WarpModifyEvent;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -31,7 +30,7 @@ public class Commandsetwarp extends EssentialsCommand {
try { try {
warpLoc = warps.getWarp(args[0]); warpLoc = warps.getWarp(args[0]);
} catch (final WarpNotFoundException | InvalidWorldException ignored) { } catch (final WarpNotFoundException ignored) {
} }
if (warpLoc == null) { if (warpLoc == null) {
final WarpModifyEvent event = new WarpModifyEvent(user, args[0], null, user.getLocation(), WarpModifyEvent.WarpModifyCause.CREATE); final WarpModifyEvent event = new WarpModifyEvent(user, args[0], null, user.getLocation(), WarpModifyEvent.WarpModifyCause.CREATE);

View File

@ -1,8 +1,10 @@
package com.earth2me.essentials.commands; package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.RandomTeleport; import com.earth2me.essentials.RandomTeleport;
import com.earth2me.essentials.Trade; import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User; import com.earth2me.essentials.User;
import net.ess3.api.TranslatableException;
import net.ess3.api.events.UserRandomTeleportEvent; import net.ess3.api.events.UserRandomTeleportEvent;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent;
@ -10,6 +12,7 @@ import org.bukkit.event.player.PlayerTeleportEvent;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public class Commandtpr extends EssentialsCommand { public class Commandtpr extends EssentialsCommand {
@ -22,25 +25,67 @@ public class Commandtpr extends EssentialsCommand {
final Trade charge = new Trade(this.getName(), ess); final Trade charge = new Trade(this.getName(), ess);
charge.isAffordableFor(user); charge.isAffordableFor(user);
final RandomTeleport randomTeleport = ess.getRandomTeleport(); 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); server.getPluginManager().callEvent(event);
if (event.isCancelled()) { if (event.isCancelled()) {
return; return;
} }
randomTeleport.getRandomLocation(event.getCenter(), event.getMinRange(), event.getMaxRange()).thenAccept(location -> { (event.isModified() ? randomTeleport.getRandomLocation(event.getCenter(), event.getMinRange(), event.getMaxRange()) : randomTeleport.getRandomLocation(name))
.thenAccept(location -> {
final CompletableFuture<Boolean> future = getNewExceptionFuture(user.getSource(), commandLabel); final CompletableFuture<Boolean> future = getNewExceptionFuture(user.getSource(), commandLabel);
user.getAsyncTeleport().teleport(location, charge, PlayerTeleportEvent.TeleportCause.COMMAND, future);
future.thenAccept(success -> { future.thenAccept(success -> {
if (success) { if (success) {
user.sendTl("tprSuccess"); userToTeleport.sendTl("tprSuccess");
} }
}); });
userToTeleport.getAsyncTeleport().teleport(location, charge, PlayerTeleportEvent.TeleportCause.COMMAND, future);
}); });
throw new NoChargeException(); throw new NoChargeException();
} }
@Override @Override
protected List<String> 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<Boolean> future = getNewExceptionFuture(sender, commandLabel);
future.thenAccept(success -> {
if (success) {
userToTeleport.sendTl("tprSuccess");
}
});
userToTeleport.getAsyncTeleport().now(location, false, PlayerTeleportEvent.TeleportCause.COMMAND, future);
});
}
@Override
protected List<String> 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(); return Collections.emptyList();
} }
} }

View File

@ -13,7 +13,6 @@ import com.earth2me.essentials.config.serializers.LocationTypeSerializer;
import com.earth2me.essentials.config.serializers.MailMessageSerializer; import com.earth2me.essentials.config.serializers.MailMessageSerializer;
import com.earth2me.essentials.config.serializers.MaterialTypeSerializer; import com.earth2me.essentials.config.serializers.MaterialTypeSerializer;
import com.earth2me.essentials.utils.AdventureUtil; import com.earth2me.essentials.utils.AdventureUtil;
import net.ess3.api.InvalidWorldException;
import net.essentialsx.api.v2.services.mail.MailMessage; import net.essentialsx.api.v2.services.mail.MailMessage;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@ -123,7 +122,7 @@ public class EssentialsConfiguration {
setInternal(path, LazyLocation.fromLocation(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); final CommentedConfigurationNode node = path == null ? getRootNode() : getSection(path);
if (node == null) { if (node == null) {
return null; return null;

View File

@ -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<Boolean> future = new CompletableFuture<>();
future.thenAccept(success -> {
if (success) {
player.sendTl("tprSuccess");
}
});
player.getAsyncTeleport().now(location, false, PlayerTeleportEvent.TeleportCause.COMMAND, future);
});
return true;
}
}

View File

@ -25,7 +25,8 @@ public enum Signs {
TRADE(new SignTrade()), TRADE(new SignTrade()),
WARP(new SignWarp()), WARP(new SignWarp()),
WEATHER(new SignWeather()), WEATHER(new SignWeather()),
WORKBENCH(new SignWorkbench()); WORKBENCH(new SignWorkbench()),
RANDOMTELEPORT(new SignRandomTeleport());
private final EssentialsSign sign; private final EssentialsSign sign;
Signs(final EssentialsSign sign) { Signs(final EssentialsSign sign) {

View File

@ -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;
}
}

View File

@ -14,14 +14,17 @@ public class UserRandomTeleportEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private final IUser user; private final IUser user;
private String name;
private Location center; private Location center;
private double minRange; private double minRange;
private double maxRange; private double maxRange;
private boolean cancelled = false; 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()); super(!Bukkit.isPrimaryThread());
this.user = user; this.user = user;
this.name = name;
this.center = center; this.center = center;
this.minRange = minRange; this.minRange = minRange;
this.maxRange = maxRange; this.maxRange = maxRange;
@ -35,11 +38,23 @@ public class UserRandomTeleportEvent extends Event implements Cancellable {
return user; return user;
} }
public String getName() {
return name;
}
public Location getCenter() { public Location getCenter() {
return center; return center;
} }
/**
* Sets the center location to teleport from.
*
* @param center Center location.
*/
public void setCenter(final Location center) { public void setCenter(final Location center) {
if (!this.center.equals(center)) {
modified = true;
}
this.center = center; this.center = center;
} }
@ -47,7 +62,15 @@ public class UserRandomTeleportEvent extends Event implements Cancellable {
return minRange; return minRange;
} }
/**
* Sets the minimum range for the teleport.
*
* @param minRange Minimum range.
*/
public void setMinRange(final double minRange) { public void setMinRange(final double minRange) {
if (this.minRange != minRange) {
modified = true;
}
this.minRange = minRange; this.minRange = minRange;
} }
@ -55,7 +78,15 @@ public class UserRandomTeleportEvent extends Event implements Cancellable {
return maxRange; return maxRange;
} }
/**
* Sets the maximum range for the teleport.
*
* @param maxRange Maximum range.
*/
public void setMaxRange(final double maxRange) { public void setMaxRange(final double maxRange) {
if (this.maxRange != maxRange) {
modified = true;
}
this.maxRange = maxRange; this.maxRange = maxRange;
} }
@ -69,6 +100,10 @@ public class UserRandomTeleportEvent extends Event implements Cancellable {
cancelled = b; cancelled = b;
} }
public boolean isModified() {
return modified;
}
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;

View File

@ -387,6 +387,7 @@ enabledSigns:
#- loom #- loom
#- smithing #- smithing
#- workbench #- workbench
#- randomteleport
# How many times per second can Essentials signs be interacted with per player. # 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. # Values should be between 1-20, 20 being virtually no lag protection.
@ -1197,6 +1198,12 @@ respawn-at-home-bed: true
# When users die, should EssentialsSpawn respect users' respawn anchors? # When users die, should EssentialsSpawn respect users' respawn anchors?
respawn-at-anchor: false 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 # Teleport all joining players to the spawnpoint
spawn-on-join: false spawn-on-join: false
# The following value of `guests` states that all players in group `guests` will be teleported to spawn when joining. # The following value of `guests` states that all players in group `guests` will be teleported to spawn when joining.

View File

@ -1,6 +1,6 @@
# Configuration for the random teleport command. # Configuration for the random teleport command.
# Some settings may be defaulted, and can be changed via the /settpr command in-game. # Some settings may be defaulted, and can be changed via the /settpr command in-game.
min-range: 0.0 default-location: '{world}'
excluded-biomes: excluded-biomes:
- cold_ocean - cold_ocean
- deep_cold_ocean - deep_cold_ocean

View File

@ -12,6 +12,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.List; import java.util.List;
@ -64,6 +65,9 @@ class EssentialsSpawnPlayerListener implements Listener {
return; return;
} }
} }
if (tryRandomTeleport(user, ess.getSettings().getRandomRespawnLocation())) {
return;
}
final Location spawn = spawns.getSpawn(user.getGroup()); final Location spawn = spawns.getSpawn(user.getGroup());
if (spawn != null) { if (spawn != null) {
event.setRespawnLocation(spawn); event.setRespawnLocation(spawn);
@ -102,7 +106,9 @@ class EssentialsSpawnPlayerListener implements Listener {
final User user = ess.getUser(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); ess.scheduleSyncDelayedTask(new NewPlayerTeleport(user), 1L);
} }
@ -158,4 +164,15 @@ class EssentialsSpawnPlayerListener implements Listener {
} }
} }
} }
private boolean tryRandomTeleport(final User user, final String name) {
if (!ess.getRandomTeleport().hasLocation(name)) {
return false;
}
ess.getRandomTeleport().getRandomLocation(name).thenAccept(location -> {
final CompletableFuture<Boolean> future = new CompletableFuture<>();
user.getAsyncTeleport().now(location, false, PlayerTeleportEvent.TeleportCause.PLUGIN, future);
});
return true;
}
} }