Port over to the new API

This commit is contained in:
2026-05-19 13:08:27 -04:00
parent 563b45010d
commit 5f4f91ddfe
18 changed files with 161 additions and 154 deletions
+9 -4
View File
@@ -2,7 +2,7 @@ plugins {
java
`maven-publish`
idea
id("dev.plex.module") version "1.0"
id("dev.plex.module") version "1.1"
}
group = "dev.plex"
@@ -20,21 +20,26 @@ repositories {
url = uri("https://nexus.telesphoreo.me/repository/plex/")
}
maven { url = uri("https://maven.enginehub.org/repo/") }
maven {
url = uri("https://maven.enginehub.org/repo/")
}
maven { url = uri("https://repo.codemc.io/repository/maven-public/") }
maven {
url = uri("https://repo.codemc.io/repository/maven-public/")
}
}
dependencies {
implementation("org.projectlombok:lombok:1.18.46")
annotationProcessor("org.projectlombok:lombok:1.18.46")
compileOnly("io.papermc.paper:paper-api:26.1.2.build.+")
implementation("dev.plex:server:2.0-SNAPSHOT")
implementation("dev.plex:api:2.0-SNAPSHOT")
implementation("org.json:json:20251224")
implementation("org.reflections:reflections:0.10.2")
plexLibrary("org.eclipse.jetty:jetty-server:12.1.9")
plexLibrary("org.eclipse.jetty.ee10:jetty-ee10-servlet:12.1.9")
plexLibrary("org.eclipse.jetty:jetty-proxy:12.1.9")
plexLibrary("de.tr7zw:item-nbt-api:2.15.7")
implementation(platform("com.intellectualsites.bom:bom-newest:1.56")) // Ref: https://github.com/IntellectualSites/bom
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Core")
implementation("commons-io:commons-io:2.22.0")
+12 -5
View File
@@ -3,6 +3,7 @@ package dev.plex;
import dev.plex.assets.MinecraftAssetsManager;
import dev.plex.authentication.AuthenticationManager;
import dev.plex.cache.FileCache;
import dev.plex.api.PlexApi;
import dev.plex.config.ModuleConfig;
import dev.plex.logging.Log;
import dev.plex.module.PlexModule;
@@ -15,7 +16,6 @@ import dev.plex.request.SchematicUploadServlet;
import dev.plex.request.StaffPlayersStreamServlet;
import dev.plex.request.StatsStreamServlet;
import dev.plex.request.impl.*;
import dev.plex.util.PlexLog;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.MultipartConfigElement;
import lombok.Getter;
@@ -38,6 +38,12 @@ public class HTTPDModule extends PlexModule
private AtomicReference<Server> atomicServer = new AtomicReference<>();
public static ModuleConfig moduleConfig;
private static PlexApi plexApi;
public static PlexApi plexApi()
{
return plexApi;
}
public static final FileCache fileCache = new FileCache();
@@ -55,6 +61,7 @@ public class HTTPDModule extends PlexModule
@Override
public void load()
{
plexApi = api();
// Move it from /httpd/config.yml to /plugins/Plex/modules/Plex-HTTPD/config.yml
moduleConfig = new ModuleConfig(this, "httpd/config.yml", "config.yml");
}
@@ -63,7 +70,7 @@ public class HTTPDModule extends PlexModule
public void enable()
{
moduleConfig.load();
PlexLog.debug("HTTPD Module Port: {0}", moduleConfig.getInt("server.port"));
HTTPDModule.plexApi().logging().debug("HTTPD Module Port: {0}", moduleConfig.getInt("server.port"));
accessLogFile = new File(getDataFolder(), moduleConfig.getString("server.logging.file-path", "httpd.log"));
@@ -73,7 +80,7 @@ public class HTTPDModule extends PlexModule
authenticationManager = new AuthenticationManager();
if (authenticationManager.provider() == null)
{
PlexLog.debug("Authentication is disabled or misconfigured");
HTTPDModule.plexApi().logging().debug("Authentication is disabled or misconfigured");
}
@@ -153,13 +160,13 @@ public class HTTPDModule extends PlexModule
}
}, "Jetty-Server");
serverThread.start();
PlexLog.log("Starting Jetty server on port " + moduleConfig.getInt("server.port"));
HTTPDModule.plexApi().logging().info("Starting Jetty server on port " + moduleConfig.getInt("server.port"));
}
@Override
public void disable()
{
PlexLog.debug("Stopping Jetty server");
HTTPDModule.plexApi().logging().debug("Stopping Jetty server");
try
{
StatsBroadcaster.get().shutdown();
@@ -1,6 +1,6 @@
package dev.plex.assets;
import dev.plex.util.PlexLog;
import dev.plex.HTTPDModule;
import org.bukkit.Bukkit;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -63,7 +63,7 @@ public class MinecraftAssetsManager
}
catch (Exception e)
{
PlexLog.log("Unable to download Minecraft assets for HTTPD inventory view: " + e.getMessage());
HTTPDModule.plexApi().logging().info("Unable to download Minecraft assets for HTTPD inventory view: " + e.getMessage());
e.printStackTrace();
}
});
@@ -90,13 +90,13 @@ public class MinecraftAssetsManager
String cachedVersion = Files.exists(versionFile) ? Files.readString(versionFile).trim() : "";
if (minecraftVersion.equals(cachedVersion) && hasAssets())
{
PlexLog.debug("HTTPD Minecraft assets are already cached for {0}", minecraftVersion);
HTTPDModule.plexApi().logging().debug("HTTPD Minecraft assets are already cached for {0}", minecraftVersion);
return;
}
if (!cachedVersion.isEmpty() && !minecraftVersion.equals(cachedVersion))
{
PlexLog.log("Minecraft version changed from " + cachedVersion + " to " + minecraftVersion + "; recreating HTTPD asset cache");
HTTPDModule.plexApi().logging().info("Minecraft version changed from " + cachedVersion + " to " + minecraftVersion + "; recreating HTTPD asset cache");
}
recreateCache();
}
@@ -114,7 +114,7 @@ public class MinecraftAssetsManager
deleteDirectory(root);
Files.createDirectories(root);
PlexLog.log("Downloading Minecraft " + minecraftVersion + " client assets for HTTPD inventory view");
HTTPDModule.plexApi().logging().info("Downloading Minecraft " + minecraftVersion + " client assets for HTTPD inventory view");
JSONObject version = findVersionJson();
String clientUrl = version.getJSONObject("downloads").getJSONObject("client").getString("url");
@@ -142,7 +142,7 @@ public class MinecraftAssetsManager
}
Files.writeString(versionFile, minecraftVersion + System.lineSeparator());
PlexLog.log("HTTPD Minecraft assets cached for " + minecraftVersion);
HTTPDModule.plexApi().logging().info("HTTPD Minecraft assets cached for " + minecraftVersion);
}
private JSONObject findVersionJson() throws IOException, InterruptedException
@@ -2,7 +2,6 @@ package dev.plex.authentication;
import dev.plex.HTTPDModule;
import dev.plex.authentication.impl.XenForoOAuth2Provider;
import dev.plex.util.PlexLog;
public class AuthenticationManager
{
@@ -17,7 +16,7 @@ public class AuthenticationManager
return;
}
PlexLog.log("[HTTPD] XenForo OAuth2 authentication is enabled");
HTTPDModule.plexApi().logging().info("[HTTPD] XenForo OAuth2 authentication is enabled");
provider = new XenForoOAuth2Provider();
}
@@ -5,7 +5,6 @@ import dev.plex.authentication.AuthenticatedUser;
import dev.plex.authentication.AuthenticationException;
import dev.plex.authentication.OAuth2Provider;
import dev.plex.authentication.UserType;
import dev.plex.util.PlexLog;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@@ -62,7 +61,7 @@ public class XenForoOAuth2Provider implements OAuth2Provider
if (domain.isEmpty() || clientId.isEmpty() || clientSecret.isEmpty() || redirectUri.isEmpty())
{
PlexLog.error("XenForo OAuth2 misconfigured: domain, clientId, clientSecret, redirectUri are all required.");
HTTPDModule.plexApi().logging().error("XenForo OAuth2 misconfigured: domain, clientId, clientSecret, redirectUri are all required.");
}
String base = "https://" + domain.replaceFirst("^https?://", "").replaceAll("/+$", "");
@@ -286,7 +285,7 @@ public class XenForoOAuth2Provider implements OAuth2Provider
}
catch (Exception e)
{
PlexLog.debug("Failed to revoke XenForo token: {0}", e.getMessage());
HTTPDModule.plexApi().logging().debug("Failed to revoke XenForo token: {0}", e.getMessage());
}
}
@@ -66,7 +66,7 @@ public class AbstractServlet extends HttpServlet
/*Enumeration<String> headerz = req.getHeaderNames();
while (headerz.hasMoreElements()) {
String header = headerz.nextElement();
PlexLog.debug("Header: {0} Value {1}", header, req.getHeader(header));
HTTPDModule.plexApi().logging().debug("Header: {0} Value {1}", header, req.getHeader(header));
}*/
GET_MAPPINGS.stream().filter(mapping -> endpointMatchesRequest(mapping.getMapping().endpoint(), requestPath)).forEach(mapping ->
{
@@ -1,14 +1,11 @@
package dev.plex.request;
import dev.plex.Plex;
import dev.plex.HTTPDModule;
import dev.plex.api.player.PlexPlayerView;
import dev.plex.api.punishment.PunishmentRequest;
import dev.plex.api.punishment.PunishmentType;
import dev.plex.authentication.AuthenticatedUser;
import dev.plex.cache.DataUtils;
import dev.plex.logging.Log;
import dev.plex.player.PlexPlayer;
import dev.plex.punishment.Punishment;
import dev.plex.punishment.PunishmentType;
import dev.plex.util.BungeeUtil;
import dev.plex.util.TimeUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
@@ -16,6 +13,7 @@ import jakarta.servlet.http.HttpServletResponse;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.PlayerInventory;
import net.kyori.adventure.text.Component;
import java.io.IOException;
import java.time.ZoneId;
@@ -73,7 +71,7 @@ public class PlayerActionServlet extends HttpServlet
return;
}
PlexPlayer target = DataUtils.getPlayer(uuid);
PlexPlayerView target = HTTPDModule.plexApi().players().byUuid(uuid).orElse(null);
if (target == null)
{
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
@@ -91,21 +89,25 @@ public class PlayerActionServlet extends HttpServlet
if (safeReason.length() > 500) safeReason = safeReason.substring(0, 500);
PunishmentType type = mapType(action);
ZonedDateTime now = ZonedDateTime.now(ZoneId.of(TimeUtils.TIMEZONE));
ZonedDateTime now = ZonedDateTime.now(ZoneId.systemDefault());
ZonedDateTime endDate = TEMP_ACTIONS.contains(action)
? now.plusSeconds(parseDurationSeconds(durationStr))
: now.plusDays(FAR_FUTURE_DAYS);
Punishment punishment = new Punishment(uuid, null);
punishment.setType(type);
punishment.setReason(safeReason);
punishment.setPunishedUsername(target.getName());
punishment.setPunisherName("xf:" + staff.username());
punishment.setEndDate(endDate);
punishment.setCustomTime(TEMP_ACTIONS.contains(action));
punishment.setActive(true);
List<String> ips = target.getIps();
if (ips != null && !ips.isEmpty()) punishment.setIp(ips.getLast());
List<String> ips = target.ips();
String ip = ips == null || ips.isEmpty() ? "" : ips.getLast();
PunishmentRequest punishment = new PunishmentRequest(
uuid,
null,
"xf:" + staff.username(),
ip,
target.name(),
type,
safeReason,
TEMP_ACTIONS.contains(action),
true,
endDate
);
String ipAddress = request.getRemoteAddr();
if ("127.0.0.1".equals(ipAddress))
@@ -113,15 +115,15 @@ public class PlayerActionServlet extends HttpServlet
String forwarded = request.getHeader("X-FORWARDED-FOR");
if (forwarded != null) ipAddress = forwarded;
}
Log.log(ipAddress + " (xf:" + staff.username() + ") issued " + action + " on " + target.getName() + " (" + uuid + ")");
Log.log(ipAddress + " (xf:" + staff.username() + ") issued " + action + " on " + target.name() + " (" + uuid + ")");
final boolean kick = action.equals("ban") || action.equals("tempban");
final Punishment toApply = punishment;
Bukkit.getScheduler().runTask(Plex.get(), () ->
final PunishmentRequest toApply = punishment;
HTTPDModule.plexApi().scheduler().runSync(() ->
{
try
{
Plex.get().getPunishmentManager().punish(target, toApply);
HTTPDModule.plexApi().punishments().punish(target, toApply);
}
catch (Throwable t)
{
@@ -133,7 +135,7 @@ public class PlayerActionServlet extends HttpServlet
Player online = Bukkit.getPlayer(uuid);
if (online != null)
{
try { BungeeUtil.kickPlayer(online, Punishment.generateBanMessage(toApply)); }
try { online.kick(Component.text("You have been banned: " + toApply.reason())); }
catch (Throwable t) { t.printStackTrace(); }
}
}
@@ -142,7 +144,7 @@ public class PlayerActionServlet extends HttpServlet
response.sendRedirect("/player/" + uuid);
}
private static void handleInventoryAction(HttpServletRequest request, HttpServletResponse response, AuthenticatedUser staff, UUID uuid, PlexPlayer target, String action, String slot)
private static void handleInventoryAction(HttpServletRequest request, HttpServletResponse response, AuthenticatedUser staff, UUID uuid, PlexPlayerView target, String action, String slot)
throws IOException
{
String ipAddress = request.getRemoteAddr();
@@ -152,9 +154,9 @@ public class PlayerActionServlet extends HttpServlet
if (forwarded != null) ipAddress = forwarded;
}
Log.log(ipAddress + " (xf:" + staff.username() + ") issued " + action + " on " + target.getName() + " (" + 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));
Bukkit.getScheduler().runTask(Plex.get(), () ->
HTTPDModule.plexApi().scheduler().runSync(() ->
{
Player online = Bukkit.getPlayer(uuid);
if (online == null) return;
@@ -5,7 +5,6 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import dev.plex.HTTPDModule;
import dev.plex.authentication.AuthenticatedUser;
import dev.plex.logging.Log;
import dev.plex.util.PlexLog;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
@@ -68,7 +67,7 @@ public class SchematicUploadServlet extends HttpServlet
ClipboardFormat schematicFormat = ClipboardFormats.findByFile(schematicFile);
if (schematicFormat == null)
{
PlexLog.log(user.username() + " FAILED to upload schematic with filename: " + filename);
HTTPDModule.plexApi().logging().info(user.username() + " FAILED to upload schematic with filename: " + filename);
Log.log("{0} (xf:{1}) FAILED to upload schematic {2}", user.username(), user.userId(), filename);
response.getWriter().println(schematicUploadBadHTML("Schematic is not a valid format."));
FileUtils.deleteQuietly(schematicFile);
@@ -80,7 +79,7 @@ public class SchematicUploadServlet extends HttpServlet
}
catch (IOException e)
{
PlexLog.log(user.username() + " FAILED to upload schematic with filename: " + filename);
HTTPDModule.plexApi().logging().info(user.username() + " FAILED to upload schematic with filename: " + filename);
Log.log("{0} (xf:{1}) FAILED to upload schematic {2}", user.username(), user.userId(), filename);
response.getWriter().println(schematicUploadBadHTML("Schematic is not a valid format."));
FileUtils.deleteQuietly(schematicFile);
@@ -88,7 +87,7 @@ public class SchematicUploadServlet extends HttpServlet
}
inputStream.close();
response.getWriter().println(schematicUploadGoodHTML("Successfully uploaded <b>" + filename + "</b>."));
PlexLog.log(user.username() + " uploaded schematic with filename: " + filename);
HTTPDModule.plexApi().logging().info(user.username() + " uploaded schematic with filename: " + filename);
Log.log("{0} (xf:{1}) uploaded schematic {2}", user.username(), user.userId(), filename);
}
@@ -7,7 +7,6 @@ import dev.plex.authentication.OAuth2Provider;
import dev.plex.request.AbstractServlet;
import dev.plex.request.GetMapping;
import dev.plex.request.MappingHeaders;
import dev.plex.util.PlexLog;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@@ -64,7 +63,7 @@ public class AuthenticationEndpoint extends AbstractServlet
}
catch (AuthenticationException e)
{
PlexLog.error("OAuth2 callback failed: " + e.getMessage());
HTTPDModule.plexApi().logging().error("OAuth2 callback failed: " + e.getMessage());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("text/html; charset=UTF-8");
return "<!doctype html><meta charset=utf-8><title>Sign-in failed</title>"
@@ -1,7 +1,7 @@
package dev.plex.request.impl;
import com.google.gson.GsonBuilder;
import dev.plex.Plex;
import dev.plex.HTTPDModule;
import dev.plex.authentication.AuthenticatedUser;
import dev.plex.request.AbstractServlet;
import dev.plex.request.GetMapping;
@@ -20,7 +20,7 @@ public class IndefBansEndpoint extends AbstractServlet
}
response.setHeader("content-type", "application/json");
return new GsonBuilder().setPrettyPrinting().create().toJson(Plex.get().getPunishmentManager().getIndefiniteBans().stream().toList());
return new GsonBuilder().setPrettyPrinting().create().toJson(HTTPDModule.plexApi().punishments().indefiniteBans());
}
private String indefbansHTML(String message)
@@ -1,8 +1,8 @@
package dev.plex.request.impl;
import dev.plex.Plex;
import dev.plex.HTTPDModule;
import dev.plex.authentication.AuthenticatedUser;
import dev.plex.punishment.PunishmentManager.IndefiniteBan;
import dev.plex.api.punishment.IndefiniteBanView;
import dev.plex.request.AbstractServlet;
import dev.plex.request.GetMapping;
import jakarta.servlet.http.HttpServletRequest;
@@ -22,19 +22,19 @@ public class IndefBansUIEndpoint extends AbstractServlet
return errorHTML(signInPrompt(request, "to view this page"));
}
List<IndefiniteBan> bans = Plex.get().getPunishmentManager().getIndefiniteBans();
List<? extends IndefiniteBanView> bans = HTTPDModule.plexApi().punishments().indefiniteBans();
return listHTML(bans);
}
private String listHTML(List<IndefiniteBan> bans)
private String listHTML(List<? extends IndefiniteBanView> bans)
{
StringBuilder cards = new StringBuilder();
int totalUsers = 0, totalUuids = 0, totalIps = 0;
for (IndefiniteBan ban : bans)
for (IndefiniteBanView ban : bans)
{
totalUsers += ban.getUsernames().size();
totalUuids += ban.getUuids().size();
totalIps += ban.getIps().size();
totalUsers += ban.usernames().size();
totalUuids += ban.uuids().size();
totalIps += ban.ips().size();
cards.append(renderCard(ban));
}
if (cards.length() == 0)
@@ -55,26 +55,26 @@ public class IndefBansUIEndpoint extends AbstractServlet
return file;
}
private static String renderCard(IndefiniteBan ban)
private static String renderCard(IndefiniteBanView ban)
{
String reason = (ban.getReason() == null || ban.getReason().isBlank())
String reason = (ban.reason() == null || ban.reason().isBlank())
? "<span class=\"italic text-muted-foreground/70\">No reason provided</span>"
: escapeHtml(ban.getReason());
: escapeHtml(ban.reason());
int total = ban.getUsernames().size() + ban.getUuids().size() + ban.getIps().size();
int total = ban.usernames().size() + ban.uuids().size() + ban.ips().size();
StringBuilder rows = new StringBuilder();
if (!ban.getUsernames().isEmpty())
if (!ban.usernames().isEmpty())
{
rows.append(renderRow("Users", "text-foreground/90 break-all", ban.getUsernames().stream().map(IndefBansUIEndpoint::escapeHtml).toList()));
rows.append(renderRow("Users", "text-foreground/90 break-all", ban.usernames().stream().map(IndefBansUIEndpoint::escapeHtml).toList()));
}
if (!ban.getUuids().isEmpty())
if (!ban.uuids().isEmpty())
{
rows.append(renderRow("UUIDs", "font-mono text-foreground/55 break-all", ban.getUuids().stream().map(UUID::toString).toList()));
rows.append(renderRow("UUIDs", "font-mono text-foreground/55 break-all", ban.uuids().stream().map(UUID::toString).toList()));
}
if (!ban.getIps().isEmpty())
if (!ban.ips().isEmpty())
{
rows.append(renderRow("IPs", "font-mono text-warning break-all", ban.getIps().stream().map(IndefBansUIEndpoint::escapeHtml).toList()));
rows.append(renderRow("IPs", "font-mono text-warning break-all", ban.ips().stream().map(IndefBansUIEndpoint::escapeHtml).toList()));
}
return """
@@ -1,8 +1,8 @@
package dev.plex.request.impl;
import dev.plex.HTTPDModule;
import dev.plex.api.player.PlexPlayerView;
import dev.plex.authentication.AuthenticatedUser;
import dev.plex.cache.DataUtils;
import dev.plex.player.PlexPlayer;
import dev.plex.request.AbstractServlet;
import dev.plex.request.GetMapping;
import jakarta.servlet.http.HttpServletRequest;
@@ -39,36 +39,36 @@ public class PlayerAdminEndpoint extends AbstractServlet
return errorPage("No player specified.");
}
PlexPlayer player = lookupPlayer(query);
PlexPlayerView player = lookupPlayer(query);
if (player == null)
{
return errorPage("No player found matching <span class=\"font-mono\">" + escapeHtml(query) + "</span>.");
}
String file = readFile(this.getClass().getResourceAsStream("/httpd/player.html"));
file = file.replace("${player_uuid}", player.getUuid().toString());
file = file.replace("${player_name}", escapeHtml(player.getName()));
file = file.replace("${player_uuid}", player.uuid().toString());
file = file.replace("${player_name}", escapeHtml(player.name()));
file = file.replace("${player_ip}", lastIp(player));
file = file.replace("${player_first_played}", firstPlayed(player.getUuid()));
file = file.replace("${player_namemc}", "https://namemc.com/profile/" + player.getUuid());
file = file.replace("${player_first_played}", firstPlayed(player.uuid()));
file = file.replace("${player_namemc}", "https://namemc.com/profile/" + player.uuid());
return file;
}
private static PlexPlayer lookupPlayer(String query)
private static PlexPlayerView lookupPlayer(String query)
{
try
{
return DataUtils.getPlayer(UUID.fromString(query));
return HTTPDModule.plexApi().players().byUuid(UUID.fromString(query)).orElse(null);
}
catch (IllegalArgumentException ignored)
{
return DataUtils.getPlayer(query);
return HTTPDModule.plexApi().players().byName(query).orElse(null);
}
}
private static String lastIp(PlexPlayer player)
private static String lastIp(PlexPlayerView player)
{
List<String> ips = player.getIps();
List<String> ips = player.ips();
if (ips == null || ips.isEmpty()) return "<span class=\"text-muted-foreground\">—</span>";
return escapeHtml(ips.getLast());
}
@@ -2,8 +2,6 @@ package dev.plex.request.impl;
import com.google.gson.GsonBuilder;
import dev.plex.HTTPDModule;
import dev.plex.Plex;
import dev.plex.util.PlexLog;
import jakarta.servlet.AsyncContext;
import org.bukkit.Bukkit;
import org.bukkit.enchantments.Enchantment;
@@ -29,7 +27,6 @@ import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import org.bukkit.plugin.Plugin;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.KeybindComponent;
import net.kyori.adventure.text.ScoreComponent;
@@ -87,12 +84,11 @@ public final class PlayerInventoryBroadcaster
try
{
refreshTask = Bukkit.getScheduler().runTaskTimer(
Plex.get(), this::tick, 0L, REFRESH_TICKS);
refreshTask = (BukkitTask)HTTPDModule.plexApi().scheduler().runTimer(this::tick, 0L, REFRESH_TICKS);
}
catch (Throwable t)
{
PlexLog.debug("PlayerInventoryBroadcaster: could not register refresh task: " + t.getMessage());
HTTPDModule.plexApi().logging().debug("PlayerInventoryBroadcaster: could not register refresh task: " + t.getMessage());
}
try
@@ -101,7 +97,7 @@ public final class PlayerInventoryBroadcaster
}
catch (Throwable t)
{
PlexLog.debug("PlayerInventoryBroadcaster: NBT-API preload failed: " + t.getMessage());
HTTPDModule.plexApi().logging().debug("PlayerInventoryBroadcaster: NBT-API preload failed: " + t.getMessage());
}
}
@@ -468,12 +464,7 @@ public final class PlayerInventoryBroadcaster
private static Class<?> nbtClass() throws ClassNotFoundException
{
Plugin plugin = Bukkit.getPluginManager().getPlugin("NBTAPI");
if (plugin == null || !plugin.isEnabled())
{
throw new ClassNotFoundException("NBTAPI plugin is not enabled");
}
return Class.forName("de.tr7zw.changeme.nbtapi.NBT", true, plugin.getClass().getClassLoader());
return Class.forName("de.tr7zw.changeme.nbtapi.NBT", true, PlayerInventoryBroadcaster.class.getClassLoader());
}
}
@@ -2,8 +2,6 @@ package dev.plex.request.impl;
import com.google.gson.GsonBuilder;
import dev.plex.HTTPDModule;
import dev.plex.Plex;
import dev.plex.util.PlexLog;
import jakarta.servlet.AsyncContext;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -76,21 +74,20 @@ public final class PlayersBroadcaster
listener = new PlayersListener();
try
{
Bukkit.getPluginManager().registerEvents(listener, Plex.get());
HTTPDModule.plexApi().listeners().register(listener);
}
catch (Throwable t)
{
PlexLog.debug("PlayersBroadcaster: could not register Bukkit listener: " + t.getMessage());
HTTPDModule.plexApi().logging().debug("PlayersBroadcaster: could not register Bukkit listener: " + t.getMessage());
}
try
{
refreshTask = Bukkit.getScheduler().runTaskTimer(
Plex.get(), this::refreshAndBroadcast, 0L, REFRESH_TICKS);
refreshTask = (BukkitTask)HTTPDModule.plexApi().scheduler().runTimer(this::refreshAndBroadcast, 0L, REFRESH_TICKS);
}
catch (Throwable t)
{
PlexLog.debug("PlayersBroadcaster: could not register refresh task: " + t.getMessage());
HTTPDModule.plexApi().logging().debug("PlayersBroadcaster: could not register refresh task: " + t.getMessage());
}
}
@@ -216,7 +213,7 @@ public final class PlayersBroadcaster
if (!refreshScheduled.compareAndSet(false, true)) return;
try
{
Bukkit.getScheduler().runTaskLater(Plex.get(), () ->
HTTPDModule.plexApi().scheduler().runLater(() ->
{
refreshScheduled.set(false);
refreshAndBroadcast();
@@ -1,9 +1,10 @@
package dev.plex.request.impl;
import com.google.gson.GsonBuilder;
import dev.plex.HTTPDModule;
import dev.plex.api.player.PlexPlayerView;
import dev.plex.api.punishment.PunishmentView;
import dev.plex.authentication.AuthenticatedUser;
import dev.plex.cache.DataUtils;
import dev.plex.player.PlexPlayer;
import dev.plex.request.AbstractServlet;
import dev.plex.request.GetMapping;
import dev.plex.util.adapter.ZonedDateTimeAdapter;
@@ -23,22 +24,22 @@ public class PunishmentsEndpoint extends AbstractServlet
return readFile(this.getClass().getResourceAsStream("/httpd/punishments.html"));
}
PlexPlayer punishedPlayer;
PlexPlayerView punishedPlayer;
try
{
UUID pathUUID = UUID.fromString(request.getPathInfo().replace("/", ""));
punishedPlayer = DataUtils.getPlayer(pathUUID);
punishedPlayer = HTTPDModule.plexApi().players().byUuid(pathUUID).orElse(null);
}
catch (IllegalArgumentException ignored)
{
punishedPlayer = DataUtils.getPlayer(request.getPathInfo().replace("/", ""));
punishedPlayer = HTTPDModule.plexApi().players().byName(request.getPathInfo().replace("/", "")).orElse(null);
}
if (punishedPlayer == null)
{
return punishmentsHTML("This player has never joined the server before.");
}
if (punishedPlayer.getPunishments().isEmpty())
if (punishedPlayer.punishments().isEmpty())
{
return punishmentsGoodHTML("This player has been a good boy. They have no punishments!");
}
@@ -47,9 +48,27 @@ public class PunishmentsEndpoint extends AbstractServlet
response.setHeader("content-type", "application/json");
if (viewer == null)
{
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeAdapter()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().peek(punishment -> punishment.setIp("")).toList());
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeAdapter()).setPrettyPrinting().create().toJson(punishedPlayer.punishments().stream().map(PunishmentsEndpoint::hideIp).toList());
}
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeAdapter()).setPrettyPrinting().create().toJson(punishedPlayer.getPunishments().stream().toList());
return new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeAdapter()).setPrettyPrinting().create().toJson(punishedPlayer.punishments().stream().toList());
}
private static Object hideIp(PunishmentView punishment)
{
return new Object()
{
public final UUID punished = punishment.punished();
public final UUID punisher = punishment.punisher();
public final String punisherName = punishment.punisherName();
public final String ip = "";
public final String punishedUsername = punishment.punishedUsername();
public final Object type = punishment.type();
public final String reason = punishment.reason();
public final boolean customTime = punishment.customTime();
public final boolean active = punishment.active();
public final ZonedDateTime issueDate = punishment.issueDate();
public final ZonedDateTime endDate = punishment.endDate();
};
}
private String punishmentsHTML(String message)
@@ -1,9 +1,9 @@
package dev.plex.request.impl;
import dev.plex.cache.DataUtils;
import dev.plex.player.PlexPlayer;
import dev.plex.punishment.Punishment;
import dev.plex.punishment.PunishmentType;
import dev.plex.HTTPDModule;
import dev.plex.api.player.PlexPlayerView;
import dev.plex.api.punishment.PunishmentType;
import dev.plex.api.punishment.PunishmentView;
import dev.plex.request.AbstractServlet;
import dev.plex.request.GetMapping;
import jakarta.servlet.http.HttpServletRequest;
@@ -33,67 +33,67 @@ public class PunishmentsUIEndpoint extends AbstractServlet
return readFile(this.getClass().getResourceAsStream("/httpd/punishments.html"));
}
PlexPlayer punished = lookupPlayer(query);
PlexPlayerView punished = lookupPlayer(query);
if (punished == null)
{
return errorHTML("No player found matching <span class=\"font-mono text-foreground\">" + escapeHtml(query) + "</span>.");
}
List<Punishment> punishments = punished.getPunishments();
List<? extends PunishmentView> punishments = punished.punishments();
if (punishments == null || punishments.isEmpty())
{
return goodHTML(escapeHtml(punished.getName()) + " has no punishments on record.");
return goodHTML(escapeHtml(punished.name()) + " has no punishments on record.");
}
boolean showIps = currentStaff(request) != null;
return resultsHTML(punished, punishments, showIps);
}
private static PlexPlayer lookupPlayer(String query)
private static PlexPlayerView lookupPlayer(String query)
{
try
{
return DataUtils.getPlayer(UUID.fromString(query));
return HTTPDModule.plexApi().players().byUuid(UUID.fromString(query)).orElse(null);
}
catch (IllegalArgumentException ignored)
{
return DataUtils.getPlayer(query);
return HTTPDModule.plexApi().players().byName(query).orElse(null);
}
}
private String resultsHTML(PlexPlayer player, List<Punishment> punishments, boolean showIps)
private String resultsHTML(PlexPlayerView player, List<? extends PunishmentView> punishments, boolean showIps)
{
StringBuilder cards = new StringBuilder();
for (Punishment p : punishments)
for (PunishmentView p : punishments)
{
cards.append(renderCard(p, showIps));
}
String file = readFile(this.getClass().getResourceAsStream("/httpd/punishments_results.html"));
file = file.replace("${player_name}", escapeHtml(player.getName()));
file = file.replace("${player_uuid}", player.getUuid().toString());
file = file.replace("${player_name}", escapeHtml(player.name()));
file = file.replace("${player_uuid}", player.uuid().toString());
file = file.replace("${punishment_count}", String.valueOf(punishments.size()));
file = file.replace("${punishment_label}", punishments.size() == 1 ? "punishment" : "punishments");
file = file.replace("${punishments}", cards.toString());
return file;
}
private static String renderCard(Punishment p, boolean showIps)
private static String renderCard(PunishmentView p, boolean showIps)
{
PunishmentType type = p.getType();
PunishmentType type = p.type();
String typeName = type == null ? "UNKNOWN" : type.name();
String accent = accentFor(type);
String rawReason = (p.getReason() == null || p.getReason().isBlank()) ? "" : p.getReason();
String rawReason = (p.reason() == null || p.reason().isBlank()) ? "" : p.reason();
String reason = rawReason.isEmpty() ? "<span class=\"italic text-muted-foreground/70\">No reason provided</span>" : escapeHtml(rawReason);
String punisher = resolvePunisher(p);
String endDate = p.getEndDate() == null ? "permanent" : escapeHtml(formatDate(p.getEndDate()));
String endDate = p.endDate() == null ? "permanent" : escapeHtml(formatDate(p.endDate()));
boolean isBan = type == PunishmentType.BAN || type == PunishmentType.TEMPBAN;
String status = "";
String statusChip = "";
if (isBan)
{
if (p.isActive())
if (p.active())
{
status = "active";
statusChip = "<span class=\"inline-flex h-5 items-center rounded-full bg-destructive/10 px-2 text-xs text-destructive\">Active</span>";
@@ -107,13 +107,13 @@ public class PunishmentsUIEndpoint extends AbstractServlet
String ipRow = "";
String ipBlob = "";
if (showIps && p.getIp() != null && !p.getIp().isBlank())
if (showIps && p.ip() != null && !p.ip().isBlank())
{
ipBlob = p.getIp();
ipBlob = p.ip();
ipRow = """
<dt class="text-muted-foreground">IP</dt>
<dd class="font-mono text-foreground/80 break-all">%s</dd>
""".formatted(escapeHtml(p.getIp()));
""".formatted(escapeHtml(p.ip()));
}
String searchBlob = escapeHtml((typeName + " " + rawReason + " " + punisher + " " + status + " " + ipBlob).toLowerCase());
@@ -148,17 +148,10 @@ public class PunishmentsUIEndpoint extends AbstractServlet
};
}
private static String resolvePunisher(Punishment p)
private static String resolvePunisher(PunishmentView p)
{
try
{
String name = Punishment.punisherDisplayName(p);
if (name != null && !name.isBlank()) return name;
}
catch (Throwable ignored)
{
}
UUID uuid = p.getPunisher();
if (p.punisherName() != null && !p.punisherName().isBlank()) return p.punisherName();
UUID uuid = p.punisher();
return uuid == null ? "CONSOLE" : uuid.toString();
}
@@ -5,7 +5,6 @@ import dev.plex.authentication.AuthenticatedUser;
import dev.plex.logging.Log;
import dev.plex.request.AbstractServlet;
import dev.plex.request.GetMapping;
import dev.plex.util.PlexLog;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@@ -76,7 +75,7 @@ public class SchematicDownloadEndpoint extends AbstractServlet
{
AuthenticatedUser user = currentUser(request);
String who = user != null ? user.username() + " (xf:" + user.userId() + ")" : request.getRemoteAddr();
PlexLog.log("{0} downloaded schematic {1}", who, schemFile.getName());
HTTPDModule.plexApi().logging().info("{0} downloaded schematic {1}", who, schemFile.getName());
Log.log("{0} downloaded schematic {1}", who, schemFile.getName());
}
@@ -119,7 +118,7 @@ public class SchematicDownloadEndpoint extends AbstractServlet
{
if (fileEntry.isDirectory())
{
PlexLog.debug("Found directory");
HTTPDModule.plexApi().logging().debug("Found directory");
listFilesForFolder(fileEntry);
}
else
@@ -2,8 +2,6 @@ package dev.plex.request.impl;
import com.google.gson.GsonBuilder;
import dev.plex.HTTPDModule;
import dev.plex.Plex;
import dev.plex.util.PlexLog;
import jakarta.servlet.AsyncContext;
import org.bukkit.Bukkit;
import org.bukkit.World;
@@ -79,11 +77,11 @@ public final class StatsBroadcaster
try
{
bukkitTask = Bukkit.getScheduler().runTaskTimer(Plex.get(), this::sampleBukkit, 0L, 40L);
bukkitTask = (BukkitTask)HTTPDModule.plexApi().scheduler().runTimer(this::sampleBukkit, 0L, 40L);
}
catch (Throwable t)
{
PlexLog.debug("StatsBroadcaster: could not register Bukkit sampling task: " + t.getMessage());
HTTPDModule.plexApi().logging().debug("StatsBroadcaster: could not register Bukkit sampling task: " + t.getMessage());
}
broadcastTask = executor.scheduleAtFixedRate(