Configurable essentials: home tiers by permission, cooldowns, warp cap, RTP radii; rewards config
This commit is contained in:
11 files changed
+276
-16
No files matched your search
+45
-6
@@ -133,7 +133,9 @@ public final class EssentialsHandler implements CommandExecutor, Listener {
|
||||
Map<String, Location> playerHomes = homes.get(player.getUniqueId());
|
||||
if (playerHomes != null && playerHomes.containsKey(homeName)) {
|
||||
player.closeInventory();
|
||||
if (coolingDown(player, "home")) return;
|
||||
player.teleport(playerHomes.get(homeName));
|
||||
startCooldown(player, "home");
|
||||
player.sendMessage(ChatColor.GREEN + "Teleported to home: " + ChatColor.YELLOW + homeName);
|
||||
}
|
||||
} else if (title.equals(GUI_WARPS_TITLE)) {
|
||||
@@ -143,7 +145,9 @@ public final class EssentialsHandler implements CommandExecutor, Listener {
|
||||
String warpName = ChatColor.stripColor(item.getItemMeta().getDisplayName()).replace("Warp: ", "").trim().toLowerCase();
|
||||
if (warps.containsKey(warpName)) {
|
||||
player.closeInventory();
|
||||
if (coolingDown(player, "warp")) return;
|
||||
player.teleport(warps.get(warpName));
|
||||
startCooldown(player, "warp");
|
||||
player.sendMessage(ChatColor.GREEN + "Teleported to warp: " + ChatColor.YELLOW + warpName);
|
||||
}
|
||||
}
|
||||
@@ -158,6 +162,9 @@ public final class EssentialsHandler implements CommandExecutor, Listener {
|
||||
|
||||
if (!plugin.getConfig().getBoolean("essentials.enabled", true)) { player.sendMessage(ChatColor.RED + "Essentials are disabled."); return true; }
|
||||
String cmd = command.getName().toLowerCase();
|
||||
boolean cooled = cooldownSeconds(cmd) > 0 && !player.hasPermission("scopenet.cooldown.bypass");
|
||||
if (cooled && coolingDown(player, cmd)) return true;
|
||||
Location before = player.getLocation();
|
||||
switch (cmd) {
|
||||
case "spawn" -> handleSpawn(player);
|
||||
case "home" -> handleHome(player, args);
|
||||
@@ -178,6 +185,7 @@ public final class EssentialsHandler implements CommandExecutor, Listener {
|
||||
case "playtime" -> handlePlaytime(player, args);
|
||||
default -> { return false; }
|
||||
}
|
||||
if (cooled && ((cmd.equals("tpa") && args.length > 0) || cmd.equals("rtp") || !before.equals(player.getLocation()))) startCooldown(player, cmd);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -263,13 +271,36 @@ public final class EssentialsHandler implements CommandExecutor, Listener {
|
||||
player.openInventory(inv);
|
||||
}
|
||||
|
||||
// ---- limits and cooldowns (the same rules as the Fabric mod; see config.yml) ----
|
||||
|
||||
private final net.scopenet.core.Limits.Cooldowns cooldowns = new net.scopenet.core.Limits.Cooldowns();
|
||||
|
||||
private int tpaTimeoutSeconds() { return Math.max(5, plugin.getConfig().getInt("essentials.tpa-timeout-seconds", 60)); }
|
||||
|
||||
private int cooldownSeconds(String cmd) { return Math.max(0, plugin.getConfig().getInt("essentials.cooldowns." + cmd, 0)); }
|
||||
|
||||
/** True (and tells the player) if they must still wait before using this command. */
|
||||
private boolean coolingDown(Player player, String cmd) {
|
||||
if (cooldownSeconds(cmd) <= 0 || player.hasPermission("scopenet.cooldown.bypass")) return false;
|
||||
long wait = cooldowns.remainingMs(player.getUniqueId(), cmd, System.currentTimeMillis());
|
||||
if (wait <= 0) return false;
|
||||
player.sendMessage(ChatColor.RED + "Please wait " + net.scopenet.core.Limits.Cooldowns.waitText(wait) + " before using /" + cmd + " again.");
|
||||
return true;
|
||||
}
|
||||
|
||||
private void startCooldown(Player player, String cmd) {
|
||||
if (!player.hasPermission("scopenet.cooldown.bypass")) cooldowns.start(player.getUniqueId(), cmd, System.currentTimeMillis(), cooldownSeconds(cmd));
|
||||
}
|
||||
|
||||
private void handleSetHome(Player player, String[] args) {
|
||||
String homeName = args.length > 0 ? args[0].toLowerCase() : "home";
|
||||
int maxHomes = plugin.getConfig().getInt("essentials.max-homes", 5);
|
||||
int nameMax = Math.max(1, plugin.getConfig().getInt("essentials.home-name-max-length", 32));
|
||||
if (homeName.length() > nameMax) { player.sendMessage(ChatColor.RED + "Home names can be at most " + nameMax + " characters."); return; }
|
||||
int maxHomes = net.scopenet.core.Limits.tier(player::hasPermission, "scopenet.homes.", plugin.getConfig().getInt("essentials.max-homes", 5), 500);
|
||||
Map<String, Location> playerHomes = homes.computeIfAbsent(player.getUniqueId(), k -> new HashMap<>());
|
||||
|
||||
if (!playerHomes.containsKey(homeName) && playerHomes.size() >= maxHomes) {
|
||||
player.sendMessage(ChatColor.RED + "You have reached your limit of " + maxHomes + " homes.");
|
||||
player.sendMessage(ChatColor.RED + "You have reached your limit of " + net.scopenet.core.Limits.show(maxHomes) + " homes.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -324,13 +355,13 @@ public final class EssentialsHandler implements CommandExecutor, Listener {
|
||||
|
||||
player.sendMessage(ChatColor.GREEN + "Teleport request sent to " + ChatColor.YELLOW + target.getName() + ChatColor.GREEN + ".");
|
||||
target.sendMessage(ChatColor.YELLOW + player.getName() + ChatColor.GREEN + " has sent you a teleport request.");
|
||||
target.sendMessage(ChatColor.GRAY + "Type " + ChatColor.YELLOW + "/tpaccept" + ChatColor.GRAY + " to accept or " + ChatColor.RED + "/tpdeny" + ChatColor.GRAY + " to deny (expires in 60s).");
|
||||
target.sendMessage(ChatColor.GRAY + "Type " + ChatColor.YELLOW + "/tpaccept" + ChatColor.GRAY + " to accept or " + ChatColor.RED + "/tpdeny" + ChatColor.GRAY + " to deny (expires in " + tpaTimeoutSeconds() + "s).");
|
||||
}
|
||||
|
||||
private void handleTpAccept(Player player) {
|
||||
UUID requesterId = pendingTpa.get(player.getUniqueId());
|
||||
Long time = tpaTimestamp.get(player.getUniqueId());
|
||||
if (requesterId == null || time == null || System.currentTimeMillis() - time > 60_000) {
|
||||
if (requesterId == null || time == null || System.currentTimeMillis() - time > tpaTimeoutSeconds() * 1000L) {
|
||||
pendingTpa.remove(player.getUniqueId());
|
||||
tpaTimestamp.remove(player.getUniqueId());
|
||||
player.sendMessage(ChatColor.RED + "You have no active teleport requests.");
|
||||
@@ -366,15 +397,18 @@ public final class EssentialsHandler implements CommandExecutor, Listener {
|
||||
}
|
||||
|
||||
private void handleRtp(Player player) {
|
||||
int radius = plugin.getConfig().getInt("essentials.rtp-radius", 2500);
|
||||
int radius = Math.max(10, plugin.getConfig().getInt("essentials.rtp-radius", 2500));
|
||||
int minRadius = Math.min(plugin.getConfig().getInt("essentials.rtp-min-radius", 0), radius - 1);
|
||||
int attempts = Math.max(1, plugin.getConfig().getInt("essentials.rtp-attempts", 15));
|
||||
World world = player.getWorld();
|
||||
Random rng = new Random();
|
||||
|
||||
player.sendMessage(ChatColor.GRAY + "Searching for a safe wilderness destination...");
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
for (int i = 0; i < 15; i++) {
|
||||
for (int i = 0; i < attempts; i++) {
|
||||
int x = rng.nextInt(radius * 2) - radius;
|
||||
int z = rng.nextInt(radius * 2) - radius;
|
||||
if (Math.max(Math.abs(x), Math.abs(z)) < minRadius) continue;
|
||||
int y = world.getHighestBlockYAt(x, z);
|
||||
Block block = world.getBlockAt(x, y - 1, z);
|
||||
if (block.getType().isSolid() && block.getType() != Material.LAVA && block.getType() != Material.WATER) {
|
||||
@@ -471,6 +505,11 @@ public final class EssentialsHandler implements CommandExecutor, Listener {
|
||||
if (!warpAdmin(player)) return;
|
||||
String name = warpName(player, args, "/setwarp <name>");
|
||||
if (name == null) return;
|
||||
int maxWarps = plugin.getConfig().getInt("essentials.max-warps", 0);
|
||||
if (maxWarps > 0 && !warps.containsKey(name) && warps.size() >= maxWarps) {
|
||||
player.sendMessage(ChatColor.RED + "The server already has " + maxWarps + " warps. Delete one first.");
|
||||
return;
|
||||
}
|
||||
warps.put(name, player.getLocation());
|
||||
saveWarps();
|
||||
player.sendMessage(ChatColor.GREEN + "Warp set: " + name);
|
||||
|
||||
@@ -46,10 +46,30 @@ social:
|
||||
essentials:
|
||||
# Essentials commands (/spawn, /home, /sethome, /delhome, /back, /tpa, /tpaccept, /tpdeny, /rtp, /warp, /playtime)
|
||||
enabled: true
|
||||
# Maximum homes per player
|
||||
# Homes every player can set. Raise it for a rank with a permission node: scopenet.homes.10 gives 10 homes,
|
||||
# scopenet.homes.25 gives 25 (the highest one a player has wins), scopenet.homes.unlimited removes the limit.
|
||||
# Operators and anyone with "*" get the top tier.
|
||||
max-homes: 5
|
||||
# RTP search radius
|
||||
# Longest allowed home name.
|
||||
home-name-max-length: 32
|
||||
# Most warps the server may have (0 = no limit).
|
||||
max-warps: 0
|
||||
# How long a /tpa request stays open.
|
||||
tpa-timeout-seconds: 60
|
||||
# /rtp picks a random spot between rtp-min-radius and rtp-radius blocks from the centre (0,0).
|
||||
rtp-radius: 2500
|
||||
rtp-min-radius: 0
|
||||
# How many random spots /rtp tries before giving up.
|
||||
rtp-attempts: 15
|
||||
# Seconds a player must wait between uses (0 = no cooldown). The wait starts when the command actually
|
||||
# teleports, so a typo costs nothing. Players with scopenet.cooldown.bypass skip all of these.
|
||||
cooldowns:
|
||||
spawn: 0
|
||||
home: 0
|
||||
back: 0
|
||||
tpa: 0
|
||||
rtp: 0
|
||||
warp: 0
|
||||
|
||||
map:
|
||||
# The SCOPENET Map: this server renders its world to map tiles in the background and sends only what changed,
|
||||
@@ -96,6 +116,23 @@ integrations:
|
||||
enabled: true
|
||||
report-interval-seconds: 30
|
||||
|
||||
# ==============================================================================
|
||||
# Rewards
|
||||
# Quests, achievements and rank milestones can give more than XP: money, items, permissions, groups, claim
|
||||
# chunks, badges and messages (set them in the admin panel). The panel hands items, permissions and commands
|
||||
# to this server when the player is online. Permissions and groups are applied with console commands, so any
|
||||
# permissions plugin works; the defaults are LuckPerms'. Placeholders: {player} {uuid} {node} {value} {duration} {group}.
|
||||
# ==============================================================================
|
||||
rewards:
|
||||
enabled: true
|
||||
# Let the panel run its own console commands as rewards. Off by default: anyone who can edit rewards in the panel
|
||||
# could otherwise run commands on this server. Only switch it on if you trust everyone with panel admin access.
|
||||
allow-commands: false
|
||||
permission-command: "lp user {player} permission set {node} true"
|
||||
permission-deny-command: "lp user {player} permission set {node} false"
|
||||
permission-temp-command: "lp user {player} permission settemp {node} {value} {duration}"
|
||||
group-command: "lp user {player} parent add {group}"
|
||||
|
||||
# ==============================================================================
|
||||
# Client mod link
|
||||
# Sends balance, level, guild and claim info to players who have the optional SCOPENET
|
||||
|
||||
Reference in new issue
Block a user