mirror of
https://github.com/plexusorg/Module-HTTPD.git
synced 2026-06-04 00:56:54 +00:00
Port over to the new API
This commit is contained in:
+9
-4
@@ -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")
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user