Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to Random Teleport #4271

Merged
merged 20 commits into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -305,6 +305,10 @@ public void onEnable() {
upgrade.convertKits();
execTimer.mark("Kits");

randomTeleport = new RandomTeleport(this);
confList.add(randomTeleport);
execTimer.mark("Init(RandomTeleport)");

upgrade.afterSettings();
execTimer.mark("Upgrade2");

Expand All @@ -320,13 +324,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 @@ -155,6 +155,10 @@ public static void uuidFileConvert(final IEssentials ess, final Boolean ignoreUF
ess.getLogger().info("To rerun the conversion type /essentials uuidconvert");
}

public void updateRandomTeleport() {
ess.getRandomTeleport().updateConfig();
JRoy marked this conversation as resolved.
Show resolved Hide resolved
}

public void convertMailList() {
if (doneFile.getBoolean("updateUsersMailList", false)) {
return;
Expand Down Expand Up @@ -969,7 +973,7 @@ private void repairUserMap() {

if (index % 1000 == 0) {
ess.getLogger().info("Reading: " + format.format((100d * (double) index) / files.length)
+ "%");
+ "%");
}
} catch (final IOException e) {
ess.getLogger().log(Level.SEVERE, "Error while reading file: ", e);
Expand Down Expand Up @@ -1008,5 +1012,6 @@ public void afterSettings() {
convertStupidCamelCaseUserdataKeys();
convertMailList();
purgeBrokenNpcAccounts();
updateRandomTeleport();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ public interface ISettings extends IConf {

boolean getRespawnAtHome();

boolean isRandomRespawn();

String getRandomRespawnLocation();

boolean isRespawnAtAnchor();

Set getMultipleHomes();
Expand Down
110 changes: 78 additions & 32 deletions Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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;
Expand All @@ -11,8 +12,11 @@
import org.bukkit.block.Biome;

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 @@ -24,12 +28,12 @@ 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();
}

Expand All @@ -39,43 +43,72 @@ public void reloadConfig() {
cachedLocations.clear();
}

public Location getCenter() {
public void updateConfig() {
try {
final LazyLocation center = config.getLocation("center");
if (center != null && center.location() != null) {
final double minRange = config.getDouble("min-range", Double.MIN_VALUE);
final double maxRange = config.getDouble("max-range", Double.MIN_VALUE);
for (World world : ess.getServer().getWorlds()) {
setCenter(world.getName(), center.location());
if (minRange != Double.MIN_VALUE) {
setMinRange(world.getName(), minRange);
}
if (maxRange != Double.MIN_VALUE) {
setMaxRange(world.getName(), maxRange);
}
}
}
config.removeProperty("center");
} catch (InvalidWorldException ignored) {
}
}

public Location getCenter(final String name) {
try {
final LazyLocation center = config.getLocation(locationKey(name, "center"));
if (center != null && center.location() != null) {
return center.location();
}
} catch (final InvalidWorldException ignored) {
}
final Location center = ess.getServer().getWorlds().get(0).getWorldBorder().getCenter();
center.setY(center.getWorld().getHighestBlockYAt(center) + HIGHEST_BLOCK_Y_OFFSET);
setCenter(center);
setCenter(name, center);
return center;
}

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<Biome> getExcludedBiomes() {
final List<String> biomeNames = config.getList("excluded-biomes", String.class);
final Set<Biome> excludedBiomes = new HashSet<>();
Expand All @@ -96,39 +129,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 @@ -193,20 +235,24 @@ 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())) {
return y;
}
}
return -1;
return Double.MIN_VALUE;
}

private boolean isValidRandomLocation(final Location location) {
return location.getBlockY() > ess.getWorldInfoProvider().getMinHeight(location.getWorld()) && !this.getExcludedBiomes().contains(location.getBlock().getBiome());
}

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 @@ -155,6 +155,16 @@ public boolean getRespawnAtHome() {
return config.getBoolean("respawn-at-home", false);
}

@Override
public boolean isRandomRespawn() {
return config.getBoolean("random-respawn", false);
}

@Override
public String getRandomRespawnLocation() {
return config.getString("random-respawn-location", "world");
}

@Override
public boolean isRespawnAtAnchor() {
return config.getBoolean("respawn-at-anchor", false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

import static com.earth2me.essentials.I18n.tl;

Expand All @@ -17,22 +19,21 @@ 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());
randomTeleport.reloadConfig();
JRoy marked this conversation as resolved.
Show resolved Hide resolved
if ("center".equalsIgnoreCase(args[1])) {
randomTeleport.setCenter(args[0], user.getLocation());
user.sendMessage(tl("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.sendMessage(tl("settprValue", args[0].toLowerCase(), args[1].toLowerCase()));
user.sendMessage(tl("settprValue", args[1].toLowerCase(), args[2].toLowerCase()));
} else {
throw new NotEnoughArgumentsException();
}
Expand All @@ -41,6 +42,8 @@ protected void run(final Server server, final User user, final String commandLab
@Override
protected List<String> 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();
Expand Down
Loading