compiles again

This commit is contained in:
2026-05-19 14:13:29 -04:00
parent 5f4f91ddfe
commit 5763ba27cf
6 changed files with 185 additions and 101 deletions
+7 -2
View File
@@ -2,11 +2,11 @@ plugins {
java java
`maven-publish` `maven-publish`
idea idea
id("dev.plex.module") version "1.1" id("dev.plex.module") version "1.2"
} }
group = "dev.plex" group = "dev.plex"
version = "1.7" version = "2.0"
description = "Module-HTTPD" description = "Module-HTTPD"
repositories { repositories {
@@ -25,10 +25,15 @@ repositories {
} }
maven { maven {
name = "codemc"
url = uri("https://repo.codemc.io/repository/maven-public/") url = uri("https://repo.codemc.io/repository/maven-public/")
} }
} }
plexModule {
includeRepository("codemc")
}
dependencies { dependencies {
implementation("org.projectlombok:lombok:1.18.46") implementation("org.projectlombok:lombok:1.18.46")
annotationProcessor("org.projectlombok:lombok:1.18.46") annotationProcessor("org.projectlombok:lombok:1.18.46")
@@ -119,7 +119,7 @@ public class PlayerActionServlet extends HttpServlet
final boolean kick = action.equals("ban") || action.equals("tempban"); final boolean kick = action.equals("ban") || action.equals("tempban");
final PunishmentRequest toApply = punishment; final PunishmentRequest toApply = punishment;
HTTPDModule.plexApi().scheduler().runSync(() -> HTTPDModule.plexApi().scheduler().runGlobal(() ->
{ {
try try
{ {
@@ -134,9 +134,12 @@ public class PlayerActionServlet extends HttpServlet
{ {
Player online = Bukkit.getPlayer(uuid); Player online = Bukkit.getPlayer(uuid);
if (online != null) if (online != null)
{
HTTPDModule.plexApi().scheduler().runEntity(online, () ->
{ {
try { online.kick(Component.text("You have been banned: " + toApply.reason())); } try { online.kick(Component.text("You have been banned: " + toApply.reason())); }
catch (Throwable t) { t.printStackTrace(); } catch (Throwable t) { t.printStackTrace(); }
});
} }
} }
}); });
@@ -156,10 +159,12 @@ public class PlayerActionServlet extends HttpServlet
Log.log(ipAddress + " (xf:" + staff.username() + ") issued " + action + " on " + target.name() + " (" + uuid + ")" + (slot == null || slot.isBlank() ? "" : " slot " + slot)); Log.log(ipAddress + " (xf:" + staff.username() + ") issued " + action + " on " + target.name() + " (" + uuid + ")" + (slot == null || slot.isBlank() ? "" : " slot " + slot));
HTTPDModule.plexApi().scheduler().runSync(() -> HTTPDModule.plexApi().scheduler().runGlobal(() ->
{ {
Player online = Bukkit.getPlayer(uuid); Player online = Bukkit.getPlayer(uuid);
if (online == null) return; if (online == null) return;
HTTPDModule.plexApi().scheduler().runEntity(online, () ->
{
PlayerInventory inv = online.getInventory(); PlayerInventory inv = online.getInventory();
if ("clear-inventory".equals(action)) if ("clear-inventory".equals(action))
{ {
@@ -175,6 +180,7 @@ public class PlayerActionServlet extends HttpServlet
online.updateInventory(); online.updateInventory();
} }
}); });
});
response.sendRedirect("/player/" + uuid); response.sendRedirect("/player/" + uuid);
} }
@@ -3,6 +3,7 @@ package dev.plex.request.impl;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import dev.plex.HTTPDModule; import dev.plex.HTTPDModule;
import jakarta.servlet.AsyncContext; import jakarta.servlet.AsyncContext;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -10,7 +11,6 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.scheduler.BukkitTask;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
@@ -60,10 +60,11 @@ public final class PlayerInventoryBroadcaster
} }
private final Map<UUID, Set<Subscriber>> subscribers = new ConcurrentHashMap<>(); private final Map<UUID, Set<Subscriber>> subscribers = new ConcurrentHashMap<>();
private final Map<UUID, String> cachedPayloads = new ConcurrentHashMap<>();
private final AtomicInteger subscriberCount = new AtomicInteger(); private final AtomicInteger subscriberCount = new AtomicInteger();
private ScheduledExecutorService executor; private ScheduledExecutorService executor;
private BukkitTask refreshTask; private ScheduledTask refreshTask;
private int maxConnections = 32; private int maxConnections = 32;
private PlayerInventoryBroadcaster() {} private PlayerInventoryBroadcaster() {}
@@ -84,7 +85,7 @@ public final class PlayerInventoryBroadcaster
try try
{ {
refreshTask = (BukkitTask)HTTPDModule.plexApi().scheduler().runTimer(this::tick, 0L, REFRESH_TICKS); refreshTask = HTTPDModule.plexApi().scheduler().runGlobalTimer(this::tick, 1L, REFRESH_TICKS);
} }
catch (Throwable t) catch (Throwable t)
{ {
@@ -121,6 +122,7 @@ public final class PlayerInventoryBroadcaster
} }
} }
subscribers.clear(); subscribers.clear();
cachedPayloads.clear();
subscriberCount.set(0); subscriberCount.set(0);
} }
@@ -160,12 +162,10 @@ public final class PlayerInventoryBroadcaster
public String currentPayload(UUID uuid) public String currentPayload(UUID uuid)
{ {
Player p = Bukkit.getPlayer(uuid); return cachedPayloads.getOrDefault(uuid, "{\"online\":false}");
if (p == null) return "{\"online\":false}";
return buildPayload(p);
} }
// Runs on the Bukkit main thread. // Runs on the global region and schedules per-player snapshots on entity schedulers.
private void tick() private void tick()
{ {
if (subscribers.isEmpty()) return; if (subscribers.isEmpty()) return;
@@ -174,16 +174,42 @@ public final class PlayerInventoryBroadcaster
Set<Subscriber> set = entry.getValue(); Set<Subscriber> set = entry.getValue();
if (set.isEmpty()) continue; if (set.isEmpty()) continue;
UUID uuid = entry.getKey(); UUID uuid = entry.getKey();
Player player = Bukkit.getPlayer(uuid);
if (player == null)
{
publish(uuid, set, "{\"online\":false}");
continue;
}
try
{
ScheduledTask task = HTTPDModule.plexApi().scheduler().runEntity(player, () ->
{
String json; String json;
try try
{ {
Player p = Bukkit.getPlayer(uuid); json = buildPayload(player);
json = (p == null) ? "{\"online\":false}" : buildPayload(p);
} }
catch (Throwable t) catch (Throwable t)
{ {
json = "{\"online\":false}"; json = "{\"online\":false}";
} }
publish(uuid, set, json);
});
if (task == null)
{
publish(uuid, set, "{\"online\":false}");
}
}
catch (Throwable t)
{
publish(uuid, set, "{\"online\":false}");
}
}
}
private void publish(UUID uuid, Set<Subscriber> set, String json)
{
cachedPayloads.put(uuid, json);
final String frame = "data: " + json + "\n\n"; final String frame = "data: " + json + "\n\n";
ScheduledExecutorService exec = executor; ScheduledExecutorService exec = executor;
if (exec == null) return; if (exec == null) return;
@@ -199,7 +225,6 @@ public final class PlayerInventoryBroadcaster
} }
} }
} }
}
private void writeFrame(UUID uuid, Subscriber sub, String frame) private void writeFrame(UUID uuid, Subscriber sub, String frame)
{ {
@@ -3,6 +3,7 @@ package dev.plex.request.impl;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import dev.plex.HTTPDModule; import dev.plex.HTTPDModule;
import jakarta.servlet.AsyncContext; import jakarta.servlet.AsyncContext;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@@ -11,7 +12,6 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.scheduler.BukkitTask;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
@@ -22,6 +22,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@@ -51,7 +52,7 @@ public final class PlayersBroadcaster
private volatile String cachedStaffFrame = "{\"players\":[],\"max\":0}"; private volatile String cachedStaffFrame = "{\"players\":[],\"max\":0}";
private ScheduledExecutorService executor; private ScheduledExecutorService executor;
private BukkitTask refreshTask; private ScheduledTask refreshTask;
private Listener listener; private Listener listener;
private int maxConnections = 32; private int maxConnections = 32;
@@ -83,7 +84,7 @@ public final class PlayersBroadcaster
try try
{ {
refreshTask = (BukkitTask)HTTPDModule.plexApi().scheduler().runTimer(this::refreshAndBroadcast, 0L, REFRESH_TICKS); refreshTask = HTTPDModule.plexApi().scheduler().runGlobalTimer(this::refreshAndBroadcast, 1L, REFRESH_TICKS);
} }
catch (Throwable t) catch (Throwable t)
{ {
@@ -157,8 +158,58 @@ public final class PlayersBroadcaster
{ {
List<Player> online = new ArrayList<>(Bukkit.getOnlinePlayers()); List<Player> online = new ArrayList<>(Bukkit.getOnlinePlayers());
int max = Bukkit.getMaxPlayers(); int max = Bukkit.getMaxPlayers();
String publicJson = buildPublicPayload(online, max); if (online.isEmpty())
String staffJson = buildStaffPayload(online, max); {
publish(List.of(), List.of(), max);
return;
}
AtomicReferenceArray<Map<String, Object>> publicPlayers = new AtomicReferenceArray<>(online.size());
AtomicReferenceArray<Map<String, Object>> staffPlayers = new AtomicReferenceArray<>(online.size());
AtomicInteger remaining = new AtomicInteger(online.size());
for (int i = 0; i < online.size(); i++)
{
final int index = i;
Player player = online.get(i);
try
{
ScheduledTask task = HTTPDModule.plexApi().scheduler().runEntity(player, () ->
{
try
{
publicPlayers.set(index, buildPublicPlayer(player));
staffPlayers.set(index, buildStaffPlayer(player));
}
catch (Throwable ignored) {}
finally
{
if (remaining.decrementAndGet() == 0)
{
publish(compact(publicPlayers), compact(staffPlayers), max);
}
}
});
if (task == null && remaining.decrementAndGet() == 0)
{
publish(compact(publicPlayers), compact(staffPlayers), max);
}
}
catch (Throwable ignored)
{
if (remaining.decrementAndGet() == 0)
{
publish(compact(publicPlayers), compact(staffPlayers), max);
}
}
}
}
catch (Throwable ignored) {}
}
private void publish(List<Map<String, Object>> publicPlayers, List<Map<String, Object>> staffPlayers, int max)
{
String publicJson = buildPayload(publicPlayers, max);
String staffJson = buildPayload(staffPlayers, max);
cachedPublicFrame = publicJson; cachedPublicFrame = publicJson;
cachedStaffFrame = staffJson; cachedStaffFrame = staffJson;
@@ -180,7 +231,19 @@ public final class PlayersBroadcaster
} }
} }
} }
catch (Throwable ignored) {}
private static List<Map<String, Object>> compact(AtomicReferenceArray<Map<String, Object>> players)
{
List<Map<String, Object>> result = new ArrayList<>(players.length());
for (int i = 0; i < players.length(); i++)
{
Map<String, Object> player = players.get(i);
if (player != null)
{
result.add(player);
}
}
return result;
} }
private void writeFrame(Subscriber sub, String frame) private void writeFrame(Subscriber sub, String frame)
@@ -213,7 +276,7 @@ public final class PlayersBroadcaster
if (!refreshScheduled.compareAndSet(false, true)) return; if (!refreshScheduled.compareAndSet(false, true)) return;
try try
{ {
HTTPDModule.plexApi().scheduler().runLater(() -> HTTPDModule.plexApi().scheduler().runGlobalLater(() ->
{ {
refreshScheduled.set(false); refreshScheduled.set(false);
refreshAndBroadcast(); refreshAndBroadcast();
@@ -225,49 +288,34 @@ public final class PlayersBroadcaster
} }
} }
private String buildPublicPayload(List<Player> online, int max) private String buildPayload(List<Map<String, Object>> players, int max)
{ {
List<Map<String, Object>> players = new ArrayList<>();
for (Player p : online)
{
Map<String, Object> m = new LinkedHashMap<>();
m.put("uuid", p.getUniqueId().toString());
m.put("name", p.getName());
try { m.put("world", p.getWorld() != null ? p.getWorld().getName() : ""); }
catch (Throwable ignored) { m.put("world", ""); }
int ping = 0;
try { ping = p.getPing(); } catch (Throwable ignored) {}
m.put("ping", ping);
players.add(m);
}
Map<String, Object> root = new LinkedHashMap<>(); Map<String, Object> root = new LinkedHashMap<>();
root.put("players", players); root.put("players", players);
root.put("max", max); root.put("max", max);
return new GsonBuilder().serializeNulls().create().toJson(root); return new GsonBuilder().serializeNulls().create().toJson(root);
} }
private String buildStaffPayload(List<Player> online, int max) private Map<String, Object> buildPublicPlayer(Player p)
{
List<Map<String, Object>> players = new ArrayList<>();
for (Player p : online)
{ {
Map<String, Object> m = new LinkedHashMap<>(); Map<String, Object> m = new LinkedHashMap<>();
m.put("uuid", p.getUniqueId().toString()); m.put("uuid", p.getUniqueId().toString());
m.put("name", p.getName()); m.put("name", p.getName());
try { m.put("world", p.getWorld() != null ? p.getWorld().getName() : ""); } try { m.put("world", p.getWorld() != null ? p.getWorld().getName() : ""); }
catch (Throwable ignored) { m.put("world", ""); } catch (Throwable ignored) { m.put("world", ""); }
try { m.put("op", p.isOp()); } catch (Throwable ignored) { m.put("op", false); }
try { m.put("gamemode", p.getGameMode().name()); }
catch (Throwable ignored) { m.put("gamemode", ""); }
int ping = 0; int ping = 0;
try { ping = p.getPing(); } catch (Throwable ignored) {} try { ping = p.getPing(); } catch (Throwable ignored) {}
m.put("ping", ping); m.put("ping", ping);
players.add(m); return m;
} }
Map<String, Object> root = new LinkedHashMap<>();
root.put("players", players); private Map<String, Object> buildStaffPlayer(Player p)
root.put("max", max); {
return new GsonBuilder().serializeNulls().create().toJson(root); Map<String, Object> m = buildPublicPlayer(p);
try { m.put("op", p.isOp()); } catch (Throwable ignored) { m.put("op", false); }
try { m.put("gamemode", p.getGameMode().name()); }
catch (Throwable ignored) { m.put("gamemode", ""); }
return m;
} }
private final class PlayersListener implements Listener private final class PlayersListener implements Listener
@@ -3,9 +3,9 @@ package dev.plex.request.impl;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import dev.plex.HTTPDModule; import dev.plex.HTTPDModule;
import jakarta.servlet.AsyncContext; import jakarta.servlet.AsyncContext;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.scheduler.BukkitTask;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
@@ -52,7 +52,7 @@ public final class StatsBroadcaster
System.currentTimeMillis() - ManagementFactory.getRuntimeMXBean().getUptime(); System.currentTimeMillis() - ManagementFactory.getRuntimeMXBean().getUptime();
private ScheduledExecutorService executor; private ScheduledExecutorService executor;
private BukkitTask bukkitTask; private ScheduledTask bukkitTask;
private ScheduledFuture<?> broadcastTask; private ScheduledFuture<?> broadcastTask;
private int maxConnections = 32; private int maxConnections = 32;
@@ -77,7 +77,7 @@ public final class StatsBroadcaster
try try
{ {
bukkitTask = (BukkitTask)HTTPDModule.plexApi().scheduler().runTimer(this::sampleBukkit, 0L, 40L); bukkitTask = HTTPDModule.plexApi().scheduler().runGlobalTimer(this::sampleBukkit, 1L, 40L);
} }
catch (Throwable t) catch (Throwable t)
{ {
+1 -1
View File
@@ -1,5 +1,5 @@
name: Module-HTTPD name: Module-HTTPD
version: 1.7 version: 2.0
description: HTTPD server for Plex description: HTTPD server for Plex
main: dev.plex.HTTPDModule main: dev.plex.HTTPDModule
apiCompatibility: 1 apiCompatibility: 1