Add account connections, guild wallets and admin fixes [skip ci]
This commit is contained in:
1 parent
7076e847ea
commit
004862ea88
38 files changed
+1696
-458
No files matched your search
@@ -132,6 +132,10 @@ public final class Integration implements AutoCloseable {
|
||||
return client.checkChunk(dimension, chunkX, chunkZ, uuid);
|
||||
}
|
||||
|
||||
public void prefetchClaims(String dimension, int chunkX, int chunkZ, UUID uuid) {
|
||||
client.prefetchClaims(dimension, chunkX, chunkZ, uuid);
|
||||
}
|
||||
|
||||
@Override public void close() {
|
||||
closed = true;
|
||||
client.close();
|
||||
|
||||
@@ -12,6 +12,7 @@ public final class PanelClient {
|
||||
private record Cached(ChunkCheckResult result, long expires) {}
|
||||
private final java.util.Map<ChunkKey, Cached> claims = new java.util.concurrent.ConcurrentHashMap<>();
|
||||
private final java.util.Set<ChunkKey> pendingClaims = java.util.concurrent.ConcurrentHashMap.newKeySet();
|
||||
private final java.util.Set<ChunkKey> pendingSnapshots = java.util.concurrent.ConcurrentHashMap.newKeySet();
|
||||
private final java.util.concurrent.ThreadPoolExecutor claimWorker = new java.util.concurrent.ThreadPoolExecutor(
|
||||
2, 2, 0, java.util.concurrent.TimeUnit.SECONDS, new java.util.concurrent.ArrayBlockingQueue<>(64),
|
||||
task -> { Thread t = new Thread(task, "scopenet-claims"); t.setDaemon(true); return t; });
|
||||
@@ -86,6 +87,43 @@ public final class PanelClient {
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/** Warm a 5x5 area when a player changes chunks, including environmental protection. */
|
||||
public void prefetchClaims(String dimension, int chunkX, int chunkZ, java.util.UUID uuid) {
|
||||
if (!settings.guildsEnabled() || !settings.landClaimingEnabled()) return;
|
||||
ChunkKey center = new ChunkKey(dimension, chunkX, chunkZ, uuid);
|
||||
Cached cached = claims.get(center);
|
||||
if (cached != null && cached.expires() > System.nanoTime()) return;
|
||||
if (!pendingSnapshots.add(center)) return;
|
||||
long generation = claimGeneration.get();
|
||||
try { claimWorker.execute(() -> {
|
||||
try {
|
||||
JsonObject req = new JsonObject();
|
||||
req.addProperty("uuid", uuid.toString());
|
||||
req.addProperty("dimension", dimension);
|
||||
req.addProperty("chunk_x", chunkX);
|
||||
req.addProperty("chunk_z", chunkZ);
|
||||
JsonObject snapshot = post("guilds/claim-snapshot", req);
|
||||
java.util.Map<String, ChunkCheckResult> found = new java.util.HashMap<>();
|
||||
for (JsonElement el : snapshot.getAsJsonArray("claims")) {
|
||||
JsonObject c = el.getAsJsonObject();
|
||||
String coord = c.get("chunk_x").getAsInt() + ":" + c.get("chunk_z").getAsInt();
|
||||
found.put(coord, new ChunkCheckResult(true, c.get("allowed").getAsBoolean(),
|
||||
c.get("guild_name").getAsString(), c.get("guild_tag").getAsString()));
|
||||
}
|
||||
long expiry = System.nanoTime() + java.util.concurrent.TimeUnit.SECONDS.toNanos(15);
|
||||
if (generation != claimGeneration.get()) return;
|
||||
if (claims.size() > 4096) claims.clear();
|
||||
for (int x = chunkX - 2; x <= chunkX + 2; x++) for (int z = chunkZ - 2; z <= chunkZ + 2; z++) {
|
||||
ChunkCheckResult value = found.getOrDefault(x + ":" + z, new ChunkCheckResult(false, true, null, null));
|
||||
claims.put(new ChunkKey(dimension, x, z, uuid), new Cached(value, expiry));
|
||||
claims.put(new ChunkKey(dimension, x, z, new java.util.UUID(0, 0)),
|
||||
new Cached(new ChunkCheckResult(value.claimed(), !value.claimed(), value.guildName(), value.guildTag()), expiry));
|
||||
}
|
||||
} catch (Exception ignored) { /* cold checks remain fail closed */ }
|
||||
finally { pendingSnapshots.remove(center); }
|
||||
}); } catch (java.util.concurrent.RejectedExecutionException e) { pendingSnapshots.remove(center); }
|
||||
}
|
||||
|
||||
private ChunkCheckResult checkChunkRemote(String dimension, int chunkX, int chunkZ, java.util.UUID uuid) {
|
||||
if (!settings.guildsEnabled() || !settings.landClaimingEnabled()) {
|
||||
return new ChunkCheckResult(false, true, null, null);
|
||||
@@ -226,4 +264,3 @@ public final class PanelClient {
|
||||
return el.isJsonArray() ? el.getAsJsonArray() : new JsonArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,20 @@ public final class ScopenetPlugin extends JavaPlugin implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void join(PlayerJoinEvent event) {
|
||||
if (integration != null) integration.activity.join(event.getPlayer().getUniqueId(), event.getPlayer().getName());
|
||||
if (integration != null) {
|
||||
integration.activity.join(event.getPlayer().getUniqueId(), event.getPlayer().getName());
|
||||
Chunk chunk = event.getPlayer().getLocation().getChunk();
|
||||
integration.prefetchClaims(dimension(chunk.getWorld()), chunk.getX(), chunk.getZ(), event.getPlayer().getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void move(PlayerMoveEvent event) {
|
||||
if (integration == null || event.getTo() == null) return;
|
||||
org.bukkit.Location from = event.getFrom(), to = event.getTo();
|
||||
if (from.getWorld() == to.getWorld() && (from.getBlockX() >> 4) == (to.getBlockX() >> 4)
|
||||
&& (from.getBlockZ() >> 4) == (to.getBlockZ() >> 4)) return;
|
||||
integration.prefetchClaims(dimension(to.getWorld()), to.getBlockX() >> 4, to.getBlockZ() >> 4, event.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
|
||||
@@ -89,6 +89,12 @@ public final class GuildHandler implements CommandExecutor, Listener {
|
||||
}
|
||||
|
||||
String sub = args[0].toLowerCase();
|
||||
String permission = sub.equals("c") ? "chat" : sub;
|
||||
if (java.util.Set.of("create", "leave", "claim", "unclaim", "map", "chat", "sethome", "home", "members").contains(permission)
|
||||
&& !player.hasPermission("scopenet.command.guild." + permission)) {
|
||||
player.sendMessage(ChatColor.RED + "You do not have permission to use /guild " + permission + ".");
|
||||
return true;
|
||||
}
|
||||
switch (sub) {
|
||||
case "create" -> handleCreate(player, args);
|
||||
case "leave" -> handleLeave(player);
|
||||
|
||||
+2
-2
@@ -90,7 +90,7 @@ public final class ScopenetCommandHandler implements CommandExecutor {
|
||||
}
|
||||
|
||||
private void sendStatus(CommandSender sender) {
|
||||
if (!sender.hasPermission("scopenet.admin")) {
|
||||
if (!sender.hasPermission("scopenet.command.scopenet.status")) {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission to view SCOPENET status.");
|
||||
return;
|
||||
}
|
||||
@@ -119,7 +119,7 @@ public final class ScopenetCommandHandler implements CommandExecutor {
|
||||
}
|
||||
|
||||
private void handleReload(CommandSender sender) {
|
||||
if (!sender.hasPermission("scopenet.admin")) {
|
||||
if (!sender.hasPermission("scopenet.command.scopenet.reload")) {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission to reload SCOPENET.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,67 +7,200 @@ load: STARTUP
|
||||
|
||||
commands:
|
||||
scopenet:
|
||||
permission: scopenet.command.scopenet
|
||||
description: SCOPENET server commands, status, and help
|
||||
aliases: [sn]
|
||||
permission: scopenet.use
|
||||
spawn:
|
||||
permission: scopenet.command.spawn
|
||||
description: Teleport to the server spawn point
|
||||
aliases: [hub, lobby]
|
||||
home:
|
||||
permission: scopenet.command.home
|
||||
description: Teleport to one of your homes or open the homes GUI
|
||||
aliases: [homes]
|
||||
sethome:
|
||||
permission: scopenet.command.sethome
|
||||
description: Set a new home location
|
||||
aliases: [createshome]
|
||||
delhome:
|
||||
permission: scopenet.command.delhome
|
||||
description: Delete an existing home
|
||||
aliases: [rmhome]
|
||||
back:
|
||||
permission: scopenet.command.back
|
||||
description: Return to your previous location or death point
|
||||
aliases: [return]
|
||||
tpa:
|
||||
permission: scopenet.command.tpa
|
||||
description: Request to teleport to another player
|
||||
tpaccept:
|
||||
permission: scopenet.command.tpaccept
|
||||
description: Accept an incoming teleport request
|
||||
aliases: [tpyes]
|
||||
tpdeny:
|
||||
permission: scopenet.command.tpdeny
|
||||
description: Deny an incoming teleport request
|
||||
aliases: [tpno]
|
||||
rtp:
|
||||
permission: scopenet.command.rtp
|
||||
description: Teleport to a random safe location in the wilderness
|
||||
aliases: [wild, randomtp]
|
||||
warp:
|
||||
permission: scopenet.command.warp
|
||||
description: Teleport to a server warp or open the warps GUI
|
||||
aliases: [warps]
|
||||
playtime:
|
||||
permission: scopenet.command.playtime
|
||||
description: Check total and session playtime
|
||||
aliases: [ontime]
|
||||
balance:
|
||||
permission: scopenet.command.balance
|
||||
description: Check your server economy balance
|
||||
aliases: [bal, money]
|
||||
pay:
|
||||
permission: scopenet.command.pay
|
||||
description: Send money to another player
|
||||
baltop:
|
||||
permission: scopenet.command.baltop
|
||||
description: View the richest players on the server
|
||||
aliases: [richest]
|
||||
shop:
|
||||
permission: scopenet.command.shop
|
||||
description: Open the interactive server shop GUI
|
||||
sell:
|
||||
permission: scopenet.command.sell
|
||||
description: Open the item selling GUI
|
||||
market:
|
||||
permission: scopenet.command.market
|
||||
description: Open the player marketplace GUI
|
||||
aliases: [ah, auction]
|
||||
orders:
|
||||
permission: scopenet.command.orders
|
||||
description: View active marketplace orders
|
||||
trade:
|
||||
permission: scopenet.command.trade
|
||||
description: Request a secure trade with another player
|
||||
transactions:
|
||||
permission: scopenet.command.transactions
|
||||
description: View recent economy transactions
|
||||
guild:
|
||||
permission: scopenet.command.guild
|
||||
description: Guild management, members, claims, and relations
|
||||
aliases: [g, clan]
|
||||
claim:
|
||||
permission: scopenet.command.claim
|
||||
description: Claim the current chunk for your guild
|
||||
unclaim:
|
||||
permission: scopenet.command.unclaim
|
||||
description: Unclaim the current chunk
|
||||
|
||||
|
||||
permissions:
|
||||
scopenet.admin:
|
||||
description: Legacy administrator permission
|
||||
default: op
|
||||
scopenet.command.scopenet:
|
||||
description: Use /scopenet
|
||||
default: true
|
||||
scopenet.command.spawn:
|
||||
description: Use /spawn
|
||||
default: true
|
||||
scopenet.command.home:
|
||||
description: Use /home
|
||||
default: true
|
||||
scopenet.command.sethome:
|
||||
description: Use /sethome
|
||||
default: true
|
||||
scopenet.command.delhome:
|
||||
description: Use /delhome
|
||||
default: true
|
||||
scopenet.command.back:
|
||||
description: Use /back
|
||||
default: true
|
||||
scopenet.command.tpa:
|
||||
description: Use /tpa
|
||||
default: true
|
||||
scopenet.command.tpaccept:
|
||||
description: Use /tpaccept
|
||||
default: true
|
||||
scopenet.command.tpdeny:
|
||||
description: Use /tpdeny
|
||||
default: true
|
||||
scopenet.command.rtp:
|
||||
description: Use /rtp
|
||||
default: true
|
||||
scopenet.command.warp:
|
||||
description: Use /warp
|
||||
default: true
|
||||
scopenet.command.playtime:
|
||||
description: Use /playtime
|
||||
default: true
|
||||
scopenet.command.balance:
|
||||
description: Use /balance
|
||||
default: true
|
||||
scopenet.command.pay:
|
||||
description: Use /pay
|
||||
default: true
|
||||
scopenet.command.baltop:
|
||||
description: Use /baltop
|
||||
default: true
|
||||
scopenet.command.shop:
|
||||
description: Use /shop
|
||||
default: true
|
||||
scopenet.command.sell:
|
||||
description: Use /sell
|
||||
default: true
|
||||
scopenet.command.market:
|
||||
description: Use /market
|
||||
default: true
|
||||
scopenet.command.orders:
|
||||
description: Use /orders
|
||||
default: true
|
||||
scopenet.command.trade:
|
||||
description: Use /trade
|
||||
default: true
|
||||
scopenet.command.transactions:
|
||||
description: Use /transactions
|
||||
default: true
|
||||
scopenet.command.guild:
|
||||
description: Use /guild
|
||||
default: true
|
||||
scopenet.command.claim:
|
||||
description: Use /claim
|
||||
default: true
|
||||
scopenet.command.unclaim:
|
||||
description: Use /unclaim
|
||||
default: true
|
||||
scopenet.command.scopenet.status:
|
||||
description: Use /scopenet status
|
||||
default: op
|
||||
scopenet.command.scopenet.reload:
|
||||
description: Use /scopenet reload
|
||||
default: op
|
||||
scopenet.command.guild.create:
|
||||
description: Use /guild create
|
||||
default: true
|
||||
scopenet.command.guild.leave:
|
||||
description: Use /guild leave
|
||||
default: true
|
||||
scopenet.command.guild.claim:
|
||||
description: Use /guild claim
|
||||
default: true
|
||||
scopenet.command.guild.unclaim:
|
||||
description: Use /guild unclaim
|
||||
default: true
|
||||
scopenet.command.guild.map:
|
||||
description: Use /guild map
|
||||
default: true
|
||||
scopenet.command.guild.chat:
|
||||
description: Use /guild chat
|
||||
default: true
|
||||
scopenet.command.guild.sethome:
|
||||
description: Use /guild sethome
|
||||
default: true
|
||||
scopenet.command.guild.home:
|
||||
description: Use /guild home
|
||||
default: true
|
||||
scopenet.command.guild.members:
|
||||
description: Use /guild members
|
||||
default: true
|
||||
Reference in new issue
Block a user