Skip to content

Commit

Permalink
Improvements to Random Teleport (#4271)
Browse files Browse the repository at this point in the history
Co-authored-by: triagonal <[email protected]>
Co-authored-by: Josh Roy <[email protected]>
  • Loading branch information
3 people authored Nov 24, 2024
1 parent 1778bf5 commit 2418a6f
Show file tree
Hide file tree
Showing 20 changed files with 304 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
11 changes: 4 additions & 7 deletions Essentials/src/main/java/com/earth2me/essentials/Essentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1068,5 +1102,6 @@ public void afterSettings() {
convertStupidCamelCaseUserdataKeys();
convertMailList();
purgeBrokenNpcAccounts();
updateRandomTeleport();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ public interface ISettings extends IConf {

boolean getRespawnAtHome();

String getRandomSpawnLocation();

String getRandomRespawnLocation();

boolean isRespawnAtAnchor();

Set getMultipleHomes();
Expand Down
124 changes: 80 additions & 44 deletions Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<Location> cachedLocations = new ConcurrentLinkedQueue<>();
private final Map<String, ConcurrentLinkedQueue<Location>> 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<String> getExcludedBiomes() {
final Set<String> excludedBiomes = new HashSet<>();
for (final String key : config.getList("excluded-biomes", String.class)) {
Expand All @@ -91,39 +110,48 @@ public int getCacheThreshold() {
return config.getInt("cache-threshold", 10);
}

public boolean getPreCache() {
return config.getBoolean("pre-cache", false);
public List<String> listLocations() {
return new ArrayList<>(ConfigurateUtil.getKeys(config.getRootNode().node("locations")));
}

public Queue<Location> getCachedLocations() {
return cachedLocations;
public Queue<Location> 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<Location> getRandomLocation(final Location center, final double minRange, final double maxRange) {
final int findAttempts = this.getFindAttempts();
final Queue<Location> cachedLocations = this.getCachedLocations();
// Get a named random teleport location; cached if possible, otherwise on demand.
public CompletableFuture<Location> getRandomLocation(final String name) {
final Queue<Location> 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<Location> 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<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, () -> {
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);
}
});
}
Expand Down Expand Up @@ -188,14 +216,18 @@ private CompletableFuture<Location> 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) {
Expand Down Expand Up @@ -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();
}
Expand Down
10 changes: 10 additions & 0 deletions Essentials/src/main/java/com/earth2me/essentials/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 1 addition & 2 deletions Essentials/src/main/java/com/earth2me/essentials/Warps.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -54,7 +53,7 @@ public Collection<String> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

This file was deleted.

Loading

0 comments on commit 2418a6f

Please sign in to comment.