Upload folder via GUI - src
This commit is contained in:
@@ -53,6 +53,14 @@ public class StatusAPI extends Plugin implements Runnable {
|
|||||||
// Kontostand pro Spieler (UUID -> Balance), wird von StatusAPIBridge gepusht
|
// Kontostand pro Spieler (UUID -> Balance), wird von StatusAPIBridge gepusht
|
||||||
public static final ConcurrentHashMap<UUID, Double> playerBalances = new ConcurrentHashMap<>();
|
public static final ConcurrentHashMap<UUID, Double> playerBalances = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// Debug-Modus (aus verify.properties)
|
||||||
|
public static boolean DEBUG = false;
|
||||||
|
|
||||||
|
/** Gibt eine Info-Meldung nur im Debug-Modus aus */
|
||||||
|
public static void debugLog(Plugin plugin, String message) {
|
||||||
|
if (DEBUG) plugin.getLogger().info(message);
|
||||||
|
}
|
||||||
|
|
||||||
private volatile Thread thread;
|
private volatile Thread thread;
|
||||||
private volatile ServerSocket serverSocket;
|
private volatile ServerSocket serverSocket;
|
||||||
private volatile boolean shuttingDown = false;
|
private volatile boolean shuttingDown = false;
|
||||||
@@ -83,6 +91,9 @@ public class StatusAPI extends Plugin implements Runnable {
|
|||||||
port = 9191;
|
port = 9191;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug-Modus
|
||||||
|
DEBUG = verifyProperties != null && Boolean.parseBoolean(verifyProperties.getProperty("debug", "false"));
|
||||||
|
|
||||||
moduleManager = new ModuleManager();
|
moduleManager = new ModuleManager();
|
||||||
|
|
||||||
// Module in korrekter Reihenfolge registrieren
|
// Module in korrekter Reihenfolge registrieren
|
||||||
@@ -192,8 +203,9 @@ public class StatusAPI extends Plugin implements Runnable {
|
|||||||
File file = new File(getDataFolder(), "verify.properties");
|
File file = new File(getDataFolder(), "verify.properties");
|
||||||
verifyProperties = new Properties();
|
verifyProperties = new Properties();
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
try (FileInputStream fis = new FileInputStream(file)) {
|
try (java.io.InputStreamReader reader = new java.io.InputStreamReader(
|
||||||
verifyProperties.load(fis);
|
new FileInputStream(file), StandardCharsets.UTF_8)) {
|
||||||
|
verifyProperties.load(reader);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getLogger().warning("verify.properties nicht gefunden.");
|
getLogger().warning("verify.properties nicht gefunden.");
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ public class AntiBotModule implements Module, Listener {
|
|||||||
ensureSecurityLogFile();
|
ensureSecurityLogFile();
|
||||||
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
this.plugin.getLogger().info("[AntiBotModule] deaktiviert via " + CONFIG_FILE_NAME);
|
StatusAPI.debugLog(this.plugin, "[AntiBotModule] deaktiviert via " + CONFIG_FILE_NAME);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ public class AntiBotModule implements Module, Listener {
|
|||||||
ProxyServer.getInstance().getPluginManager().registerCommand(this.plugin, new AntiBotCommand());
|
ProxyServer.getInstance().getPluginManager().registerCommand(this.plugin, new AntiBotCommand());
|
||||||
ProxyServer.getInstance().getScheduler().schedule(this.plugin, this::tick, 1, 1, TimeUnit.SECONDS);
|
ProxyServer.getInstance().getScheduler().schedule(this.plugin, this::tick, 1, 1, TimeUnit.SECONDS);
|
||||||
|
|
||||||
this.plugin.getLogger().info("[AntiBotModule] aktiviert. maxCps=" + maxCps
|
this.plugin.getLogger().fine("[AntiBotModule] aktiviert. maxCps=" + maxCps
|
||||||
+ ", attackStartCps=" + attackStartCps + ", ip/min=" + ipConnectionsPerMinute);
|
+ ", attackStartCps=" + attackStartCps + ", ip/min=" + ipConnectionsPerMinute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
package net.viper.status.modules.broadcast;
|
package net.viper.status.modules.broadcast;
|
||||||
|
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Listener;
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
import net.viper.status.module.Module;
|
import net.viper.status.module.Module;
|
||||||
|
|
||||||
@@ -57,7 +65,7 @@ public class BroadcastModule implements Module, Listener {
|
|||||||
loadConfig();
|
loadConfig();
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
try { plugin.getProxy().getPluginManager().registerListener(plugin, this); } catch (Throwable ignored) {}
|
try { plugin.getProxy().getPluginManager().registerListener(plugin, this); } catch (Throwable ignored) {}
|
||||||
plugin.getLogger().info("[BroadcastModule] aktiviert. Format: " + format);
|
plugin.getLogger().fine("[BroadcastModule] aktiviert. Format: " + format);
|
||||||
loadSchedules();
|
loadSchedules();
|
||||||
plugin.getProxy().getScheduler().schedule(plugin, this::processScheduled, 1, 1, TimeUnit.SECONDS);
|
plugin.getProxy().getScheduler().schedule(plugin, this::processScheduled, 1, 1, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
@@ -142,7 +150,7 @@ public class BroadcastModule implements Module, Listener {
|
|||||||
for (ProxiedPlayer p : plugin.getProxy().getPlayers()) {
|
for (ProxiedPlayer p : plugin.getProxy().getPlayers()) {
|
||||||
try { p.sendMessage(components); sent++; } catch (Throwable ignored) {}
|
try { p.sendMessage(components); sent++; } catch (Throwable ignored) {}
|
||||||
}
|
}
|
||||||
plugin.getLogger().info("[BroadcastModule] Broadcast gesendet (Empfänger=" + sent + "): " + message);
|
StatusAPI.debugLog(plugin, "[BroadcastModule] Broadcast gesendet (Empfänger=" + sent + "): " + message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +287,7 @@ public class BroadcastModule implements Module, Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
scheduledByClientId.putAll(loaded);
|
scheduledByClientId.putAll(loaded);
|
||||||
plugin.getLogger().info("[BroadcastModule] " + loaded.size() + " geplante Broadcasts aus Datei wiederhergestellt.");
|
plugin.getLogger().fine("[BroadcastModule] geplante Broadcasts wiederhergestellt.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean scheduleBroadcast(long timestampMillis, String sourceName, String message, String type,
|
public boolean scheduleBroadcast(long timestampMillis, String sourceName, String message, String type,
|
||||||
@@ -311,7 +319,7 @@ public class BroadcastModule implements Module, Listener {
|
|||||||
prefix, prefixColor, bracketColor, messageColor, recur);
|
prefix, prefixColor, bracketColor, messageColor, recur);
|
||||||
scheduledByClientId.put(id, sb);
|
scheduledByClientId.put(id, sb);
|
||||||
saveSchedules();
|
saveSchedules();
|
||||||
plugin.getLogger().info("[BroadcastModule] Neue geplante Nachricht registriert: " + id
|
StatusAPI.debugLog(plugin, "[BroadcastModule] Neue geplante Nachricht registriert: " + id
|
||||||
+ " @ " + dateFormat.format(new Date(timestampMillis)));
|
+ " @ " + dateFormat.format(new Date(timestampMillis)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -319,7 +327,7 @@ public class BroadcastModule implements Module, Listener {
|
|||||||
public boolean cancelScheduled(String clientScheduleId) {
|
public boolean cancelScheduled(String clientScheduleId) {
|
||||||
if (clientScheduleId == null || clientScheduleId.trim().isEmpty()) return false;
|
if (clientScheduleId == null || clientScheduleId.trim().isEmpty()) return false;
|
||||||
ScheduledBroadcast removed = scheduledByClientId.remove(clientScheduleId);
|
ScheduledBroadcast removed = scheduledByClientId.remove(clientScheduleId);
|
||||||
if (removed != null) { plugin.getLogger().info("[BroadcastModule] Schedule abgebrochen: " + clientScheduleId); saveSchedules(); return true; }
|
if (removed != null) { StatusAPI.debugLog(plugin, "[BroadcastModule] Schedule abgebrochen: " + clientScheduleId); saveSchedules(); return true; }
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +340,7 @@ public class BroadcastModule implements Module, Listener {
|
|||||||
for (Map.Entry<String, ScheduledBroadcast> entry : scheduledByClientId.entrySet()) {
|
for (Map.Entry<String, ScheduledBroadcast> entry : scheduledByClientId.entrySet()) {
|
||||||
ScheduledBroadcast sb = entry.getValue();
|
ScheduledBroadcast sb = entry.getValue();
|
||||||
if (sb.nextRunMillis <= now) {
|
if (sb.nextRunMillis <= now) {
|
||||||
plugin.getLogger().info("[BroadcastModule] ⏰ Sende geplante Nachricht (ID: " + entry.getKey() + ")");
|
StatusAPI.debugLog(plugin, "[BroadcastModule] ⏰ Sende geplante Nachricht (ID: " + entry.getKey() + ")");
|
||||||
handleBroadcast(sb.sourceName, sb.message, sb.type, "", sb.prefix, sb.prefixColor, sb.bracketColor, sb.messageColor);
|
handleBroadcast(sb.sourceName, sb.message, sb.type, "", sb.prefix, sb.prefixColor, sb.bracketColor, sb.messageColor);
|
||||||
if (!"none".equalsIgnoreCase(sb.recur)) {
|
if (!"none".equalsIgnoreCase(sb.recur)) {
|
||||||
long next = computeNextMillis(sb.nextRunMillis, sb.recur);
|
long next = computeNextMillis(sb.nextRunMillis, sb.recur);
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public class ChatConfig {
|
|||||||
config = new Configuration();
|
config = new Configuration();
|
||||||
}
|
}
|
||||||
parseConfig();
|
parseConfig();
|
||||||
plugin.getLogger().info("[ChatModule] " + channels.size() + " Kanäle geladen.");
|
plugin.getLogger().fine("[ChatModule] " + channels.size() + " Kanäle geladen.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseConfig() {
|
private void parseConfig() {
|
||||||
@@ -392,7 +392,7 @@ public class ChatConfig {
|
|||||||
try (java.io.FileWriter fw = new java.io.FileWriter(filterFile)) {
|
try (java.io.FileWriter fw = new java.io.FileWriter(filterFile)) {
|
||||||
fw.write("# StatusAPI - Wort-Blacklist\n# words:\n# - beispielwort\nwords:\n");
|
fw.write("# StatusAPI - Wort-Blacklist\n# words:\n# - beispielwort\nwords:\n");
|
||||||
}
|
}
|
||||||
plugin.getLogger().info("[ChatModule] filter.yml erstellt.");
|
plugin.getLogger().fine("[ChatModule] filter.yml erstellt.");
|
||||||
} catch (IOException e) { plugin.getLogger().warning("[ChatModule] Konnte filter.yml nicht erstellen: " + e.getMessage()); }
|
} catch (IOException e) { plugin.getLogger().warning("[ChatModule] Konnte filter.yml nicht erstellen: " + e.getMessage()); }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class ChatModule implements Module, Listener {
|
|||||||
// ChatLogger
|
// ChatLogger
|
||||||
if (config.isChatlogEnabled()) {
|
if (config.isChatlogEnabled()) {
|
||||||
chatLogger = new ChatLogger(plugin.getDataFolder(), logger, config.getChatlogRetentionDays());
|
chatLogger = new ChatLogger(plugin.getDataFolder(), logger, config.getChatlogRetentionDays());
|
||||||
logger.info("[ChatModule] Chat-Log aktiviert (" + config.getChatlogRetentionDays() + " Tage Aufbewahrung).");
|
logger.fine("[ChatModule] Chat-Log aktiviert (" + config.getChatlogRetentionDays() + " Tage Aufbewahrung).");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReportManager
|
// ReportManager
|
||||||
@@ -144,7 +144,7 @@ public class ChatModule implements Module, Listener {
|
|||||||
ProxyServer.getInstance().getPluginManager().registerListener(plugin, this);
|
ProxyServer.getInstance().getPluginManager().registerListener(plugin, this);
|
||||||
registerCommands();
|
registerCommands();
|
||||||
|
|
||||||
logger.info("[ChatModule] Aktiviert – " + config.getChannels().size() + " Kanäle geladen.");
|
logger.fine("[ChatModule] Aktiviert – " + config.getChannels().size() + " Kanäle geladen.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class CommandBlockerModule implements Module, Listener {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.plugin.getLogger().info("[CommandBlocker] aktiviert (" + blocked.size() + " Commands).");
|
this.plugin.getLogger().fine("[CommandBlocker] aktiviert (" + blocked.size() + " Commands).");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class CustomCommandModule implements Module, Listener {
|
|||||||
// Hier casten wir 'Plugin' zu 'StatusAPI', da wir wissen, dass es das ist
|
// Hier casten wir 'Plugin' zu 'StatusAPI', da wir wissen, dass es das ist
|
||||||
this.plugin = (StatusAPI) plugin;
|
this.plugin = (StatusAPI) plugin;
|
||||||
|
|
||||||
this.plugin.getLogger().info("Lade CustomCommandModule...");
|
this.plugin.getLogger().fine("Lade CustomCommandModule...");
|
||||||
reloadConfig();
|
reloadConfig();
|
||||||
if (this.config == null) {
|
if (this.config == null) {
|
||||||
this.config = new Configuration();
|
this.config = new Configuration();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.viper.status.modules.economy;
|
|||||||
|
|
||||||
import com.zaxxer.hikari.HikariConfig;
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
@@ -23,6 +24,9 @@ public class EconomyDatabase {
|
|||||||
this.log = plugin.getLogger();
|
this.log = plugin.getLogger();
|
||||||
|
|
||||||
HikariConfig cfg = new HikariConfig();
|
HikariConfig cfg = new HikariConfig();
|
||||||
|
// HikariCP Startup-Logs unterdrücken
|
||||||
|
java.util.logging.Logger.getLogger("com.zaxxer.hikari").setLevel(java.util.logging.Level.WARNING);
|
||||||
|
java.util.logging.Logger.getLogger("com.zaxxer.hikari.HikariDataSource").setLevel(java.util.logging.Level.WARNING);
|
||||||
cfg.setJdbcUrl("jdbc:mysql://" + host + ":" + port + "/" + database
|
cfg.setJdbcUrl("jdbc:mysql://" + host + ":" + port + "/" + database
|
||||||
+ "?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&useUnicode=true");
|
+ "?useSSL=false&autoReconnect=true&characterEncoding=UTF-8&useUnicode=true");
|
||||||
cfg.setUsername(user);
|
cfg.setUsername(user);
|
||||||
@@ -67,7 +71,7 @@ public class EconomyDatabase {
|
|||||||
" `updated` BIGINT NOT NULL" +
|
" `updated` BIGINT NOT NULL" +
|
||||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;")) {
|
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;")) {
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
log.info("[Economy] MySQL verbunden – Tabellen bereit.");
|
if (StatusAPI.DEBUG) log.info("[Economy] MySQL verbunden – Tabellen bereit.");
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
log.severe("[Economy] Tabellen-Setup (bc_player_names) fehlgeschlagen: " + e.getMessage());
|
log.severe("[Economy] Tabellen-Setup (bc_player_names) fehlgeschlagen: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.viper.status.modules.economy;
|
package net.viper.status.modules.economy;
|
||||||
|
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -64,7 +65,7 @@ public class EconomyManager {
|
|||||||
UUID uuid = UUID.fromString(formatted);
|
UUID uuid = UUID.fromString(formatted);
|
||||||
// Für künftige Lookups speichern
|
// Für künftige Lookups speichern
|
||||||
db.saveNameMapping(uuid, name);
|
db.saveNameMapping(uuid, name);
|
||||||
plugin.getLogger().info("[Economy] Mojang-Lookup: " + name + " → " + uuid);
|
StatusAPI.debugLog(plugin, "[Economy] Mojang-Lookup: " + name + " → " + uuid);
|
||||||
return uuid;
|
return uuid;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
plugin.getLogger().warning("[Economy] Mojang-Lookup fehlgeschlagen für " + name + ": " + e.getMessage());
|
plugin.getLogger().warning("[Economy] Mojang-Lookup fehlgeschlagen für " + name + ": " + e.getMessage());
|
||||||
|
|||||||
@@ -57,14 +57,14 @@ public class EconomyModule implements Module {
|
|||||||
plugin.getProxy().getPluginManager().registerCommand(plugin, new PayCommand(plugin, manager));
|
plugin.getProxy().getPluginManager().registerCommand(plugin, new PayCommand(plugin, manager));
|
||||||
plugin.getProxy().getPluginManager().registerCommand(plugin, new EcoAdminCommand(plugin, manager));
|
plugin.getProxy().getPluginManager().registerCommand(plugin, new EcoAdminCommand(plugin, manager));
|
||||||
|
|
||||||
plugin.getLogger().info("[Economy] EconomyModule aktiviert (start-balance: " + startBal + ").");
|
StatusAPI.debugLog(plugin, "[Economy] EconomyModule aktiviert (start-balance: " + startBal + ").");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable(Plugin plugin) {
|
public void onDisable(Plugin plugin) {
|
||||||
if (database != null) {
|
if (database != null) {
|
||||||
database.close();
|
database.close();
|
||||||
plugin.getLogger().info("[Economy] MySQL-Verbindung geschlossen.");
|
StatusAPI.debugLog(plugin, "[Economy] MySQL-Verbindung geschlossen.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,30 @@
|
|||||||
package net.viper.status.modules.forum;
|
package net.viper.status.modules.forum;
|
||||||
|
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.HoverEvent;
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Command;
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Listener;
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.event.EventHandler;
|
import net.md_5.bungee.event.EventHandler;
|
||||||
import net.viper.status.module.Module;
|
import net.viper.status.module.Module;
|
||||||
|
|
||||||
@@ -46,7 +59,7 @@ public class ForumBridgeModule implements Module, Listener {
|
|||||||
public void onEnable(Plugin plugin) {
|
public void onEnable(Plugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
loadConfig(plugin);
|
loadConfig(plugin);
|
||||||
if (!enabled) { plugin.getLogger().info("ForumBridgeModule ist deaktiviert."); return; }
|
if (!enabled) { StatusAPI.debugLog(plugin, "ForumBridgeModule ist deaktiviert."); return; }
|
||||||
|
|
||||||
storage = new ForumNotifStorage(plugin.getDataFolder(), plugin.getLogger());
|
storage = new ForumNotifStorage(plugin.getDataFolder(), plugin.getLogger());
|
||||||
storage.load();
|
storage.load();
|
||||||
@@ -60,12 +73,12 @@ public class ForumBridgeModule implements Module, Listener {
|
|||||||
}, 10, 10, TimeUnit.MINUTES);
|
}, 10, 10, TimeUnit.MINUTES);
|
||||||
|
|
||||||
plugin.getProxy().getScheduler().schedule(plugin, () -> storage.purgeOld(30), 1, 24, TimeUnit.HOURS);
|
plugin.getProxy().getScheduler().schedule(plugin, () -> storage.purgeOld(30), 1, 24, TimeUnit.HOURS);
|
||||||
plugin.getLogger().info("ForumBridgeModule aktiviert.");
|
plugin.getLogger().fine("ForumBridgeModule aktiviert.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable(Plugin plugin) {
|
public void onDisable(Plugin plugin) {
|
||||||
if (storage != null) { storage.save(); plugin.getLogger().info("Forum-Benachrichtigungen gespeichert."); }
|
if (storage != null) { storage.save(); StatusAPI.debugLog(plugin, "Forum-Benachrichtigungen gespeichert."); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadConfig(Plugin plugin) {
|
private void loadConfig(Plugin plugin) {
|
||||||
|
|||||||
@@ -1,18 +1,32 @@
|
|||||||
package net.viper.status.modules.serverswitcher;
|
package net.viper.status.modules.serverswitcher;
|
||||||
|
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.HoverEvent;
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.event.TabCompleteEvent;
|
import net.md_5.bungee.api.event.TabCompleteEvent;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Command;
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Listener;
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.event.EventHandler;
|
import net.md_5.bungee.event.EventHandler;
|
||||||
import net.viper.status.module.Module;
|
import net.viper.status.module.Module;
|
||||||
|
|
||||||
@@ -57,7 +71,7 @@ public class ServerSwitcherModule implements Module {
|
|||||||
loadConfig();
|
loadConfig();
|
||||||
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
plugin.getLogger().info("[ServerSwitcherModule] Deaktiviert.");
|
StatusAPI.debugLog(plugin, "[ServerSwitcherModule] Deaktiviert.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +81,7 @@ public class ServerSwitcherModule implements Module {
|
|||||||
ProxyServer.getInstance().getPluginManager().registerListener(plugin,
|
ProxyServer.getInstance().getPluginManager().registerListener(plugin,
|
||||||
new GoTabListener());
|
new GoTabListener());
|
||||||
|
|
||||||
plugin.getLogger().info("[ServerSwitcherModule] Aktiviert. Command: /" + commandName
|
plugin.getLogger().fine("[ServerSwitcherModule] Aktiviert. Command: /" + commandName
|
||||||
+ " | Aliases: " + aliases + " | Permission: " + permission);
|
+ " | Aliases: " + aliases + " | Permission: " + permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,29 +18,19 @@ import net.md_5.bungee.protocol.packet.PlayerListItem.Item;
|
|||||||
import net.md_5.bungee.protocol.packet.PlayerListItemUpdate;
|
import net.md_5.bungee.protocol.packet.PlayerListItemUpdate;
|
||||||
import net.viper.status.module.Module;
|
import net.viper.status.module.Module;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Date;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class TablistModule implements Module, Listener {
|
public class TablistModule implements Module, Listener {
|
||||||
|
|
||||||
private static final String CONFIG_FILE = "tablist.properties";
|
private static final String CONFIG_FILE = "tablist.properties";
|
||||||
|
|
||||||
// Leerer Skin (grauer Kopf) fuer Platzhalter-Slots – selber Skin wie TAB-Plugin
|
// Leerer Skin (grauer Kopf) für Platzhalter-Slots
|
||||||
private static final net.md_5.bungee.protocol.data.Property[] EMPTY_SKIN = {
|
private static final net.md_5.bungee.protocol.data.Property[] EMPTY_SKIN = {
|
||||||
new net.md_5.bungee.protocol.data.Property(
|
new net.md_5.bungee.protocol.data.Property(
|
||||||
"textures",
|
"textures",
|
||||||
@@ -49,16 +39,19 @@ public class TablistModule implements Module, Listener {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
private int rows = 20;
|
// Grid – rows ist IMMER 20 (Minecraft-Client-Layout: N Slots → ceil(N/20) Spalten à 20 Zeilen)
|
||||||
private int columns = 4;
|
private static final int ROWS = 20;
|
||||||
private int total = rows * columns;
|
private int rows = ROWS, columns = 3, total = 60, tabSizeMax = 60;
|
||||||
private int tabSizeMax = 80;
|
private int configuredTabSize = 0; // 0 = auto-detect aus BungeeCord
|
||||||
|
|
||||||
private UUID[] fakeUuids;
|
private UUID[] fakeUuids;
|
||||||
|
|
||||||
// ── Config ─────────────────────────────────────────────────────────────────
|
// Skin-Cache (pro Spieler)
|
||||||
|
private final ConcurrentHashMap<UUID, net.md_5.bungee.protocol.data.Property[]> skinCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// Config
|
||||||
private boolean enabled = true;
|
private boolean enabled = true;
|
||||||
private int updateInterval = 5;
|
private int updateInterval = 5;
|
||||||
|
private String layoutMode = "compact";
|
||||||
|
|
||||||
private String headerLine1 = "&8&m" + rep('\u2501', 53);
|
private String headerLine1 = "&8&m" + rep('\u2501', 53);
|
||||||
private String headerLine2 = " &6&lViper Network";
|
private String headerLine2 = " &6&lViper Network";
|
||||||
@@ -67,12 +60,6 @@ public class TablistModule implements Module, Listener {
|
|||||||
private String footerLine2 = " &7Discord: &ediscord.viper-network.de &8| &7Shop: &eviper-network.de/shop";
|
private String footerLine2 = " &7Discord: &ediscord.viper-network.de &8| &7Shop: &eviper-network.de/shop";
|
||||||
private String footerLine3 = "&8&m" + rep('\u2501', 53);
|
private String footerLine3 = "&8&m" + rep('\u2501', 53);
|
||||||
|
|
||||||
private String colorSrvHeader = "&6&l";
|
|
||||||
|
|
||||||
// Header/Footer Layout-Modus: "classic" oder "compact"
|
|
||||||
private String layoutMode = "classic";
|
|
||||||
|
|
||||||
// Compact-Layout Header/Footer
|
|
||||||
private String compactHeader1 = "&6&lViper Network &8• &7%online% Spieler online";
|
private String compactHeader1 = "&6&lViper Network &8• &7%online% Spieler online";
|
||||||
private String compactHeader2 = "";
|
private String compactHeader2 = "";
|
||||||
private String compactHeader3 = "";
|
private String compactHeader3 = "";
|
||||||
@@ -85,70 +72,61 @@ public class TablistModule implements Module, Listener {
|
|||||||
private boolean compactFooter1Spacer = false;
|
private boolean compactFooter1Spacer = false;
|
||||||
private boolean compactFooter4Spacer = false;
|
private boolean compactFooter4Spacer = false;
|
||||||
|
|
||||||
// Konfigurierbare Info-Eintraege (Reihenfolge aus Config)
|
private String colorSrvHeader = "&6&l";
|
||||||
private static class InfoEntry {
|
|
||||||
String label;
|
|
||||||
String type; // website, name, rank, server, world, time, teamspeak, custom
|
|
||||||
String value; // fuer custom und statische Werte
|
|
||||||
boolean enabled;
|
|
||||||
InfoEntry(String label, String type, String value, boolean enabled) {
|
|
||||||
this.label = label; this.type = type; this.value = value; this.enabled = enabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private List<InfoEntry> infoEntries = new ArrayList<>();
|
|
||||||
|
|
||||||
private String timeFormat = "HH:mm:ss / h:mm a";
|
private String timeFormat = "HH:mm:ss / h:mm a";
|
||||||
private String timeZone = "Europe/Berlin";
|
private String timeZone = "Europe/Berlin";
|
||||||
private SimpleDateFormat sdf;
|
private SimpleDateFormat sdf;
|
||||||
private List<String> serverOrder = new ArrayList<>();
|
private List<String> serverOrder = new ArrayList<>();
|
||||||
private Set<String> hiddenServers = new HashSet<>();
|
private Set<String> hiddenServers = new HashSet<>();
|
||||||
// Rang-Reihenfolge fuer Spieler-Sortierung (hoechster Rang zuerst)
|
|
||||||
private List<String> rankOrder = new ArrayList<>();
|
private List<String> rankOrder = new ArrayList<>();
|
||||||
|
|
||||||
// ── State ──────────────────────────────────────────────────────────────────
|
// Info-Spalte
|
||||||
|
private static class InfoEntry {
|
||||||
|
String label, type, value; boolean enabled;
|
||||||
|
InfoEntry(String l, String t, String v, boolean e) { label=l; type=t; value=v; enabled=e; }
|
||||||
|
}
|
||||||
|
private List<InfoEntry> infoEntries = new ArrayList<>();
|
||||||
|
|
||||||
|
// State
|
||||||
private Plugin plugin;
|
private Plugin plugin;
|
||||||
private ScheduledTask updateTask;
|
private ScheduledTask updateTask;
|
||||||
private Method sendPacketQueuedMethod;
|
private Method sendPacketQueuedMethod;
|
||||||
// Spieler die bereits ADD_PLAYER erhalten haben – nur noch UPDATE nötig
|
|
||||||
private final Set<UUID> initializedViewers = new HashSet<>();
|
|
||||||
|
|
||||||
// ══════════════════════════════════════════════════════════════════════════
|
|
||||||
|
|
||||||
@Override public String getName() { return "TablistModule"; }
|
@Override public String getName() { return "TablistModule"; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable(Plugin plugin) {
|
public void onEnable(Plugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
plugin.getLogger().info("[TablistModule] Starte...");
|
||||||
ensureConfigExists();
|
ensureConfigExists();
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
plugin.getLogger().info("[TablistModule] Config geladen. Layout=" + layoutMode + " enabled=" + enabled);
|
||||||
if (!enabled) { plugin.getLogger().info("[TablistModule] Deaktiviert."); return; }
|
if (!enabled) { plugin.getLogger().info("[TablistModule] Deaktiviert."); return; }
|
||||||
|
try {
|
||||||
initGridSize();
|
initGridSize();
|
||||||
|
} catch (Exception e) {
|
||||||
fakeUuids = new UUID[total];
|
plugin.getLogger().warning("[TablistModule] initGridSize Fehler: " + e.getMessage() + " – nutze Fallback 3x20");
|
||||||
for (int i = 0; i < total; i++)
|
int fbSize = configuredTabSize > 0 ? configuredTabSize : 60;
|
||||||
fakeUuids[i] = new UUID(0xFFFEDEAD00000000L, (long) i);
|
tabSizeMax = fbSize; rows = ROWS; columns = Math.min(Math.max(3, fbSize / ROWS), 8); total = ROWS * columns;
|
||||||
|
}
|
||||||
|
initUuids();
|
||||||
try {
|
try {
|
||||||
Class<?> uc = Class.forName("net.md_5.bungee.UserConnection");
|
Class<?> uc = Class.forName("net.md_5.bungee.UserConnection");
|
||||||
sendPacketQueuedMethod = uc.getMethod("sendPacketQueued", net.md_5.bungee.protocol.DefinedPacket.class);
|
sendPacketQueuedMethod = uc.getMethod("sendPacketQueued", net.md_5.bungee.protocol.DefinedPacket.class);
|
||||||
sendPacketQueuedMethod.setAccessible(true);
|
sendPacketQueuedMethod.setAccessible(true);
|
||||||
|
plugin.getLogger().info("[TablistModule] sendPacketQueued gefunden.");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
plugin.getLogger().severe("[TablistModule] sendPacketQueued nicht gefunden: " + e.getMessage());
|
plugin.getLogger().severe("[TablistModule] sendPacketQueued NICHT gefunden: " + e.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProxyServer.getInstance().getPluginManager().registerListener(plugin, this);
|
ProxyServer.getInstance().getPluginManager().registerListener(plugin, this);
|
||||||
updateTask = ProxyServer.getInstance().getScheduler().schedule(
|
updateTask = ProxyServer.getInstance().getScheduler().schedule(plugin, this::updateAll, 2L, Math.max(1, updateInterval), TimeUnit.SECONDS);
|
||||||
plugin, this::updateAll, 2L, Math.max(1, updateInterval), TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
ProxyServer.getInstance().getScheduler().schedule(plugin, () -> {
|
ProxyServer.getInstance().getScheduler().schedule(plugin, () -> {
|
||||||
List<String> all = new ArrayList<>(ProxyServer.getInstance().getServers().keySet());
|
plugin.getLogger().info("[TablistModule] Alle BungeeCord-Server: " + new ArrayList<>(ProxyServer.getInstance().getServers().keySet()));
|
||||||
plugin.getLogger().info("[TablistModule] Alle BungeeCord-Server: " + all);
|
plugin.getLogger().info("[TablistModule] Tablist-Spalten: " + getServerOrder());
|
||||||
plugin.getLogger().info("[TablistModule] Tablist-Spalten (" + columns + "x" + rows + "): " + getServerOrder());
|
recalculateGrid();
|
||||||
}, 3L, TimeUnit.SECONDS);
|
}, 3L, TimeUnit.SECONDS);
|
||||||
|
plugin.getLogger().info("[TablistModule] Aktiviert. Grid=" + columns + "x" + rows + " layout=" + layoutMode);
|
||||||
plugin.getLogger().info("[TablistModule] Aktiviert. Grid=" + columns + "x" + rows + ", Interval=" + updateInterval + "s");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -161,73 +139,132 @@ public class TablistModule implements Module, Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initGridSize() {
|
private void initGridSize() {
|
||||||
int tabSize = 80;
|
int tabSize = 60;
|
||||||
try {
|
try {
|
||||||
for (ListenerInfo li : ProxyServer.getInstance().getConfig().getListeners()) {
|
for (ListenerInfo li : ProxyServer.getInstance().getConfig().getListeners()) {
|
||||||
try {
|
try { Object v = li.getClass().getMethod("getTabSize").invoke(li);
|
||||||
Object val = li.getClass().getMethod("getTabSize").invoke(li);
|
if (v instanceof Number && ((Number)v).intValue() > 0) { tabSize = ((Number)v).intValue(); break; }
|
||||||
if (val instanceof Number && ((Number) val).intValue() > 0) {
|
|
||||||
tabSize = ((Number) val).intValue(); break;
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
|
if (configuredTabSize > 0) tabSize = configuredTabSize; // manuell gesetzt in tablist.properties
|
||||||
tabSizeMax = tabSize;
|
tabSizeMax = tabSize;
|
||||||
rows = 20;
|
rows = ROWS; // immer 20 – Minecraft-Client-Pflicht
|
||||||
|
boolean hasInfo = !"compact".equalsIgnoreCase(layoutMode);
|
||||||
int serverCount = getServerOrder().size();
|
int serverCount = getServerOrder().size();
|
||||||
// +1 fuer Info-Spalte
|
int needed = (hasInfo ? 1 : 0) + Math.max(1, serverCount);
|
||||||
int needed = 1 + serverCount;
|
// Spalten = benötigte Spalten, aber max was tab-size erlaubt (tab-size/20)
|
||||||
columns = Math.max(2, Math.min(needed, tabSize / rows));
|
columns = Math.max(hasInfo ? 2 : 1, Math.min(needed, tabSize / ROWS));
|
||||||
total = rows * columns;
|
total = ROWS * columns;
|
||||||
plugin.getLogger().info("[TablistModule] tab_size=" + tabSize + " -> " + columns + "x" + rows + "=" + total);
|
if (needed > tabSize / ROWS) {
|
||||||
|
plugin.getLogger().warning("[TablistModule] Nicht alle Server passen in die Tablist! "
|
||||||
|
+ "Erhöhe tab-size in der BungeeCord config.yml auf mindestens " + (needed * ROWS)
|
||||||
|
+ " (aktuell: " + tabSize + ")");
|
||||||
|
}
|
||||||
|
plugin.getLogger().info("[TablistModule] tab_size=" + tabSize + " -> " + columns + "x" + ROWS + "=" + total + " (" + serverCount + " Server)");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initUuids() {
|
||||||
|
fakeUuids = new UUID[total];
|
||||||
|
for (int i = 0; i < total; i++) fakeUuids[i] = new UUID(0xFFFEDEAD00000000L, (long) i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Events ─────────────────────────────────────────────────────────────────
|
// ── Events ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@EventHandler public void onLogin(PostLoginEvent e) {
|
@EventHandler
|
||||||
|
public void onLogin(PostLoginEvent e) {
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
ProxyServer.getInstance().getScheduler().schedule(plugin,
|
ProxiedPlayer p = e.getPlayer();
|
||||||
() -> updateTablist(e.getPlayer()), 3L, TimeUnit.SECONDS);
|
net.md_5.bungee.protocol.data.Property[] skin = fetchSkin(p);
|
||||||
|
if (skin != null && skin.length > 0) skinCache.put(p.getUniqueId(), skin);
|
||||||
|
ProxyServer.getInstance().getScheduler().schedule(plugin, () -> {
|
||||||
|
updateTablist(p);
|
||||||
|
// Nach 2s nochmals für alle damit der neue Spieler mit Kopf erscheint
|
||||||
|
ProxyServer.getInstance().getScheduler().schedule(plugin, this::updateAll, 2L, TimeUnit.SECONDS);
|
||||||
|
}, 2L, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler public void onSwitch(ServerSwitchEvent e) {
|
@EventHandler
|
||||||
|
public void onSwitch(ServerSwitchEvent e) {
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
initializedViewers.remove(e.getPlayer().getUniqueId());
|
ProxiedPlayer switched = e.getPlayer();
|
||||||
ProxyServer.getInstance().getScheduler().schedule(plugin,
|
|
||||||
() -> updateTablist(e.getPlayer()), 1L, TimeUnit.SECONDS);
|
// Skin sofort cachen (noch auf dem alten Server, LoginProfile noch verfügbar)
|
||||||
|
net.md_5.bungee.protocol.data.Property[] skin = fetchSkin(switched);
|
||||||
|
if (skin != null && skin.length > 0) skinCache.put(switched.getUniqueId(), skin);
|
||||||
|
|
||||||
|
// Nach 1s: alle Fake-Slots bei allen Viewern entfernen → erzwingt frisches ADD_PLAYER mit neuem Skin
|
||||||
|
ProxyServer.getInstance().getScheduler().schedule(plugin, () -> {
|
||||||
|
// Skin nochmals versuchen (jetzt auf neuem Server)
|
||||||
|
net.md_5.bungee.protocol.data.Property[] freshSkin = fetchSkin(switched);
|
||||||
|
if (freshSkin != null && freshSkin.length > 0) skinCache.put(switched.getUniqueId(), freshSkin);
|
||||||
|
|
||||||
|
// Alle Slots bei allen Viewern entfernen
|
||||||
|
for (ProxiedPlayer viewer : ProxyServer.getInstance().getPlayers()) {
|
||||||
|
try { removeFakeSlots(viewer); } catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler public void onDisconnect(PlayerDisconnectEvent e) {
|
// Sofort neu aufbauen (kein weiterer Delay nötig da removeFakeSlots synchron ist)
|
||||||
|
updateAll();
|
||||||
|
|
||||||
|
// Nochmal nach 2s als Sicherheit
|
||||||
|
ProxyServer.getInstance().getScheduler().schedule(plugin, () -> {
|
||||||
|
net.md_5.bungee.protocol.data.Property[] s2 = fetchSkin(switched);
|
||||||
|
if (s2 != null && s2.length > 0) skinCache.put(switched.getUniqueId(), s2);
|
||||||
|
for (ProxiedPlayer viewer : ProxyServer.getInstance().getPlayers()) {
|
||||||
|
try { removeFakeSlots(viewer); } catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
updateAll();
|
||||||
|
}, 2L, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
}, 1L, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onDisconnect(PlayerDisconnectEvent e) {
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
initializedViewers.remove(e.getPlayer().getUniqueId());
|
skinCache.remove(e.getPlayer().getUniqueId());
|
||||||
ProxyServer.getInstance().getScheduler().schedule(plugin, this::updateAll, 1L, TimeUnit.SECONDS);
|
// Erst alle Fake-Slots entfernen, dann nach kurzer Pause neu aufbauen
|
||||||
|
// So verschwindet der Kopf des Spielers zuverlässig
|
||||||
|
ProxyServer.getInstance().getScheduler().schedule(plugin, () -> {
|
||||||
|
for (ProxiedPlayer viewer : ProxyServer.getInstance().getPlayers()) {
|
||||||
|
try { removeFakeSlots(viewer); } catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
ProxyServer.getInstance().getScheduler().schedule(plugin,
|
||||||
|
this::updateAll, 1L, TimeUnit.SECONDS);
|
||||||
|
}, 1L, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Core ───────────────────────────────────────────────────────────────────
|
// ── Core ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private void updateAll() {
|
private void updateAll() {
|
||||||
recalculateGrid();
|
recalculateGrid();
|
||||||
|
// Fehlende Skins nachladen
|
||||||
|
for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) {
|
||||||
|
if (!skinCache.containsKey(p.getUniqueId())) {
|
||||||
|
net.md_5.bungee.protocol.data.Property[] skin = fetchSkin(p);
|
||||||
|
if (skin != null && skin.length > 0) skinCache.put(p.getUniqueId(), skin);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) updateTablist(p);
|
for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) updateTablist(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void recalculateGrid() {
|
private void recalculateGrid() {
|
||||||
|
boolean hasInfo = !"compact".equalsIgnoreCase(layoutMode);
|
||||||
int serverCount = getServerOrder().size();
|
int serverCount = getServerOrder().size();
|
||||||
// Im compact-Modus keine Info-Spalte, alle Spalten fuer Server
|
int needed = (hasInfo ? 1 : 0) + Math.max(1, serverCount);
|
||||||
boolean hasInfoCol = !"compact".equalsIgnoreCase(layoutMode);
|
// Spalten = benötigte Spalten, aber max was tab-size erlaubt (tab-size/20)
|
||||||
int needed = (hasInfoCol ? 1 : 0) + serverCount;
|
int newColumns = Math.max(hasInfo ? 2 : 1, Math.min(needed, tabSizeMax / ROWS));
|
||||||
int newColumns = Math.max(hasInfoCol ? 2 : 1, Math.min(needed, tabSizeMax / rows));
|
int newTotal = ROWS * newColumns;
|
||||||
int newTotal = rows * newColumns;
|
|
||||||
if (newColumns == columns && newTotal == total) return;
|
if (newColumns == columns && newTotal == total) return;
|
||||||
for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) {
|
for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) {
|
||||||
try { removeFakeSlots(p); } catch (Exception ignored) {}
|
try { removeFakeSlots(p); } catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
initializedViewers.clear();
|
rows = ROWS;
|
||||||
columns = newColumns;
|
columns = newColumns;
|
||||||
total = newTotal;
|
total = newTotal;
|
||||||
fakeUuids = new UUID[total];
|
initUuids();
|
||||||
for (int i = 0; i < total; i++)
|
plugin.getLogger().info("[TablistModule] Grid: " + columns + "x" + rows + "=" + total + " (" + serverCount + " Server)");
|
||||||
fakeUuids[i] = new UUID(0xFFFEDEAD00000000L, (long) i);
|
|
||||||
plugin.getLogger().info("[TablistModule] Grid: " + columns + "x" + rows + "=" + total + " (" + serverCount + " Server, layout=" + layoutMode + ")");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTablist(ProxiedPlayer viewer) {
|
private void updateTablist(ProxiedPlayer viewer) {
|
||||||
@@ -248,17 +285,17 @@ public class TablistModule implements Module, Listener {
|
|||||||
header = c(headerLine1) + "\n" + c(headerLine2) + "\n" + c(headerLine3);
|
header = c(headerLine1) + "\n" + c(headerLine2) + "\n" + c(headerLine3);
|
||||||
footer = c(footerLine1) + "\n" + c(footerLine2) + "\n" + c(footerLine3);
|
footer = c(footerLine1) + "\n" + c(footerLine2) + "\n" + c(footerLine3);
|
||||||
}
|
}
|
||||||
|
|
||||||
viewer.setTabHeader(new TextComponent(header), new TextComponent(footer));
|
viewer.setTabHeader(new TextComponent(header), new TextComponent(footer));
|
||||||
hideRealPlayers(viewer);
|
hideRealPlayers(viewer);
|
||||||
sendSlots(viewer, buildItems(viewer));
|
sendSlots(viewer, buildItems(viewer));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
plugin.getLogger().warning("[TablistModule] Fehler fuer " + viewer.getName() + ": " + ex.getMessage());
|
plugin.getLogger().warning("[TablistModule] " + viewer.getName() + ": " + ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildCompactHeader(ProxiedPlayer viewer, String srv, String world,
|
// ── Header / Footer ────────────────────────────────────────────────────────
|
||||||
String rank, String time, String balance, int online) {
|
|
||||||
|
private String buildCompactHeader(ProxiedPlayer viewer, String srv, String world, String rank, String time, String balance, int online) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
appendLine(sb, compactHeader1, false, viewer, srv, world, rank, time, balance, online);
|
appendLine(sb, compactHeader1, false, viewer, srv, world, rank, time, balance, online);
|
||||||
appendLine(sb, compactHeader2, compactHeader2Spacer, viewer, srv, world, rank, time, balance, online);
|
appendLine(sb, compactHeader2, compactHeader2Spacer, viewer, srv, world, rank, time, balance, online);
|
||||||
@@ -266,23 +303,20 @@ public class TablistModule implements Module, Listener {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildCompactFooter(ProxiedPlayer viewer, String srv, String world,
|
private String buildCompactFooter(ProxiedPlayer viewer, String srv, String world, String rank, String time, String balance, int online) {
|
||||||
String rank, String time, String balance, int online) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
appendLine(sb, compactFooter1, compactFooter1Spacer, viewer, srv, world, rank, time, balance, online);
|
appendLine(sb, compactFooter1, compactFooter1Spacer, viewer, srv, world, rank, time, balance, online);
|
||||||
// Automatische Server-Übersicht
|
|
||||||
List<String> servers = getServerOrder();
|
List<String> servers = getServerOrder();
|
||||||
if (!servers.isEmpty()) {
|
if (!servers.isEmpty()) {
|
||||||
StringBuilder serverLine = new StringBuilder();
|
StringBuilder sLine = new StringBuilder();
|
||||||
for (String sName : servers) {
|
for (String sName : servers) {
|
||||||
ServerInfo info = ProxyServer.getInstance().getServerInfo(sName);
|
ServerInfo si = ProxyServer.getInstance().getServerInfo(sName);
|
||||||
int count = info != null ? info.getPlayers().size() : 0;
|
int cnt = si != null ? si.getPlayers().size() : 0;
|
||||||
if (serverLine.length() > 0) serverLine.append(" &8| ");
|
if (sLine.length() > 0) sLine.append(" &8| ");
|
||||||
serverLine.append(c(colorSrvHeader)).append(capitalize(sName))
|
sLine.append(c(colorSrvHeader)).append(capitalize(sName)).append(" &8\u25cf &7").append(cnt);
|
||||||
.append(" &8\u25cf &7").append(count);
|
|
||||||
}
|
}
|
||||||
if (sb.length() > 0) sb.append("\n");
|
if (sb.length() > 0) sb.append("\n");
|
||||||
sb.append(c(serverLine.toString()));
|
sb.append(c(sLine.toString()));
|
||||||
}
|
}
|
||||||
appendLine(sb, compactFooter2, false, viewer, srv, world, rank, time, balance, online);
|
appendLine(sb, compactFooter2, false, viewer, srv, world, rank, time, balance, online);
|
||||||
appendLine(sb, compactFooter3, false, viewer, srv, world, rank, time, balance, online);
|
appendLine(sb, compactFooter3, false, viewer, srv, world, rank, time, balance, online);
|
||||||
@@ -290,53 +324,34 @@ public class TablistModule implements Module, Listener {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void appendLine(StringBuilder sb, String line, boolean spacer, ProxiedPlayer viewer, String srv, String world, String rank, String time, String balance, int online) {
|
||||||
* Hängt eine Zeile an:
|
boolean empty = line == null || line.trim().isEmpty();
|
||||||
* - spacer=true + leer → fügt eine leere Abstandszeile ein
|
if (empty && !spacer) return;
|
||||||
* - spacer=false + leer → Zeile wird komplett übersprungen
|
|
||||||
* - Text vorhanden → wird immer angezeigt
|
|
||||||
*/
|
|
||||||
private void appendLine(StringBuilder sb, String line, boolean spacer,
|
|
||||||
ProxiedPlayer viewer, String srv, String world, String rank,
|
|
||||||
String time, String balance, int online) {
|
|
||||||
boolean isEmpty = line == null || line.trim().isEmpty();
|
|
||||||
if (isEmpty && !spacer) return; // überspringen
|
|
||||||
if (sb.length() > 0) sb.append("\n");
|
if (sb.length() > 0) sb.append("\n");
|
||||||
if (isEmpty) {
|
sb.append(empty ? " " : c(replacePlaceholders(line, viewer, srv, world, rank, time, balance, online)));
|
||||||
sb.append(" "); // Abstandszeile
|
|
||||||
} else {
|
|
||||||
sb.append(c(replacePlaceholders(line, viewer, srv, world, rank, time, balance, online)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Items ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private Item[] buildItems(ProxiedPlayer viewer) {
|
private Item[] buildItems(ProxiedPlayer viewer) {
|
||||||
String[] texts = new String[total];
|
String[] texts = new String[total];
|
||||||
net.md_5.bungee.protocol.data.Property[][] skins = new net.md_5.bungee.protocol.data.Property[total][];
|
net.md_5.bungee.protocol.data.Property[][] skins = new net.md_5.bungee.protocol.data.Property[total][];
|
||||||
int[] pings = new int[total];
|
int[] pings = new int[total];
|
||||||
for (int i = 0; i < total; i++) {
|
for (int i = 0; i < total; i++) { texts[i] = " "; skins[i] = EMPTY_SKIN; pings[i] = 0; }
|
||||||
texts[i] = " ";
|
|
||||||
skins[i] = EMPTY_SKIN;
|
|
||||||
pings[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Spalte 0: Info (nur im classic Layout) ───────────────────────────
|
boolean compact = "compact".equalsIgnoreCase(layoutMode);
|
||||||
|
|
||||||
|
// Info-Spalte (nur classic)
|
||||||
|
if (!compact) {
|
||||||
int base = 0, row = 0;
|
int base = 0, row = 0;
|
||||||
String srv = viewer.getServer() != null ? capitalize(viewer.getServer().getInfo().getName()) : "\u2014";
|
String srv = viewer.getServer() != null ? capitalize(viewer.getServer().getInfo().getName()) : "\u2014";
|
||||||
String world = net.viper.status.StatusAPI.playerWorlds.getOrDefault(viewer.getUniqueId(), "world");
|
String world = net.viper.status.StatusAPI.playerWorlds.getOrDefault(viewer.getUniqueId(), "world");
|
||||||
String rank = getRank(viewer);
|
String rank = getRank(viewer); String time = sdf.format(new Date());
|
||||||
String time = sdf.format(new Date());
|
String balance = getBalance(viewer); int online = ProxyServer.getInstance().getOnlineCount();
|
||||||
String balance = getBalance(viewer);
|
|
||||||
int online = ProxyServer.getInstance().getOnlineCount();
|
|
||||||
|
|
||||||
boolean compactMode = "compact".equalsIgnoreCase(layoutMode);
|
|
||||||
|
|
||||||
if (!compactMode) {
|
|
||||||
for (InfoEntry entry : infoEntries) {
|
for (InfoEntry entry : infoEntries) {
|
||||||
if (!entry.enabled) continue;
|
if (!entry.enabled || row + 1 >= rows) continue;
|
||||||
if (row + 1 >= rows) break;
|
if (entry.label != null && !entry.label.isEmpty())
|
||||||
if (entry.label != null && !entry.label.isEmpty()) {
|
|
||||||
row = set(texts, base, row, c(replacePlaceholders(entry.label, viewer, srv, world, rank, time, balance, online)));
|
row = set(texts, base, row, c(replacePlaceholders(entry.label, viewer, srv, world, rank, time, balance, online)));
|
||||||
}
|
|
||||||
String val;
|
String val;
|
||||||
switch (entry.type) {
|
switch (entry.type) {
|
||||||
case "name": val = "&f" + viewer.getName(); break;
|
case "name": val = "&f" + viewer.getName(); break;
|
||||||
@@ -353,34 +368,28 @@ public class TablistModule implements Module, Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Server-Spieler Spalten ────────────────────────────────────────────
|
// Server-Spalten
|
||||||
List<String> servers = getServerOrder();
|
List<String> servers = getServerOrder();
|
||||||
int startCol = compactMode ? 0 : 1;
|
int startCol = compact ? 0 : 1;
|
||||||
for (int col = startCol; col < columns && (col - startCol) < servers.size(); col++) {
|
for (int col = startCol; col < columns && (col - startCol) < servers.size(); col++) {
|
||||||
base = col * rows;
|
int base = col * rows, row = 0;
|
||||||
row = 0;
|
|
||||||
String sName = servers.get(col - startCol);
|
String sName = servers.get(col - startCol);
|
||||||
row = set(texts, base, row, c(colorSrvHeader + capitalize(sName)));
|
row = set(texts, base, row, c(colorSrvHeader + capitalize(sName)));
|
||||||
ServerInfo info = ProxyServer.getInstance().getServerInfo(sName);
|
ServerInfo si = ProxyServer.getInstance().getServerInfo(sName);
|
||||||
if (info != null) {
|
if (si != null) {
|
||||||
// Spieler nach Rang-Reihenfolge sortieren
|
for (ProxiedPlayer p : sortPlayersByRank(new ArrayList<>(si.getPlayers()))) {
|
||||||
List<ProxiedPlayer> sorted = sortPlayersByRank(new ArrayList<>(info.getPlayers()));
|
|
||||||
for (ProxiedPlayer p : sorted) {
|
|
||||||
if (row >= rows) break;
|
if (row >= rows) break;
|
||||||
String prefix = getLuckPermsPrefix(p);
|
String prefix = getLuckPermsPrefix(p);
|
||||||
String display = prefix.isEmpty()
|
set(texts, base, row, prefix.isEmpty() ? c("&7" + p.getName()) : c(prefix + "&r " + p.getName()));
|
||||||
? c("&7" + p.getName())
|
// Skin aus Cache – immer aktuell
|
||||||
: c(prefix + "&r " + p.getName());
|
net.md_5.bungee.protocol.data.Property[] skin = skinCache.get(p.getUniqueId());
|
||||||
set(texts, base, row, display);
|
skins[base + row] = (skin != null && skin.length > 0) ? skin : EMPTY_SKIN;
|
||||||
skins[base + row] = getPlayerSkin(p);
|
pings[base + row] = p.getPing() < 0 ? 1 : p.getPing();
|
||||||
int ping = p.getPing();
|
|
||||||
pings[base + row] = ping < 0 ? 1 : ping;
|
|
||||||
row++;
|
row++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alle Slots listed=true – Layout bleibt erhalten
|
|
||||||
Item[] items = new Item[total];
|
Item[] items = new Item[total];
|
||||||
for (int i = 0; i < total; i++) {
|
for (int i = 0; i < total; i++) {
|
||||||
Item item = new Item();
|
Item item = new Item();
|
||||||
@@ -402,58 +411,33 @@ public class TablistModule implements Module, Listener {
|
|||||||
private void hideRealPlayers(ProxiedPlayer viewer) {
|
private void hideRealPlayers(ProxiedPlayer viewer) {
|
||||||
if (sendPacketQueuedMethod == null) return;
|
if (sendPacketQueuedMethod == null) return;
|
||||||
try {
|
try {
|
||||||
java.util.Collection<ProxiedPlayer> online = ProxyServer.getInstance().getPlayers();
|
Collection<ProxiedPlayer> online = ProxyServer.getInstance().getPlayers();
|
||||||
if (online.isEmpty()) return;
|
if (online.isEmpty()) return;
|
||||||
PlayerListItemUpdate pkt = new PlayerListItemUpdate();
|
PlayerListItemUpdate pkt = new PlayerListItemUpdate();
|
||||||
pkt.setActions(EnumSet.of(PlayerListItemUpdate.Action.UPDATE_LISTED));
|
pkt.setActions(EnumSet.of(PlayerListItemUpdate.Action.UPDATE_LISTED));
|
||||||
Item[] items = new Item[online.size()];
|
Item[] items = new Item[online.size()];
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
for (ProxiedPlayer p : online) {
|
for (ProxiedPlayer p : online) {
|
||||||
Item item = new Item();
|
Item it = new Item(); it.setUuid(p.getUniqueId()); it.setListed(false); items[idx++] = it;
|
||||||
item.setUuid(p.getUniqueId());
|
|
||||||
item.setListed(false);
|
|
||||||
items[idx++] = item;
|
|
||||||
}
|
}
|
||||||
pkt.setItems(items);
|
pkt.setItems(items);
|
||||||
sendPacketQueuedMethod.invoke(viewer, pkt);
|
sendPacketQueuedMethod.invoke(viewer, pkt);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) { plugin.getLogger().warning("[TablistModule] hideRealPlayers: " + e.getMessage()); }
|
||||||
plugin.getLogger().warning("[TablistModule] hideRealPlayers: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private void sendSlots(ProxiedPlayer viewer, Item[] items) {
|
private void sendSlots(ProxiedPlayer viewer, Item[] items) {
|
||||||
if (sendPacketQueuedMethod == null) return;
|
if (sendPacketQueuedMethod == null) return;
|
||||||
|
// Immer vollständiges ADD_PLAYER – einfach und zuverlässig
|
||||||
boolean isNew = initializedViewers.add(viewer.getUniqueId());
|
PlayerListItemUpdate pkt = new PlayerListItemUpdate();
|
||||||
|
pkt.setActions(EnumSet.of(
|
||||||
if (isNew) {
|
|
||||||
// Erstes Mal: ADD_PLAYER + UPDATE_DISPLAY_NAME + UPDATE_LISTED
|
|
||||||
PlayerListItemUpdate addPkt = new PlayerListItemUpdate();
|
|
||||||
addPkt.setActions(EnumSet.of(
|
|
||||||
PlayerListItemUpdate.Action.ADD_PLAYER,
|
PlayerListItemUpdate.Action.ADD_PLAYER,
|
||||||
PlayerListItemUpdate.Action.UPDATE_DISPLAY_NAME,
|
PlayerListItemUpdate.Action.UPDATE_DISPLAY_NAME,
|
||||||
PlayerListItemUpdate.Action.UPDATE_LISTED));
|
PlayerListItemUpdate.Action.UPDATE_LISTED,
|
||||||
addPkt.setItems(items);
|
PlayerListItemUpdate.Action.UPDATE_LATENCY));
|
||||||
try { sendPacketQueuedMethod.invoke(viewer, addPkt); }
|
pkt.setItems(items);
|
||||||
catch (Exception e) { plugin.getLogger().warning("[TablistModule] ADD_PLAYER: " + e.getMessage()); return; }
|
try { sendPacketQueuedMethod.invoke(viewer, pkt); }
|
||||||
} else {
|
catch (Exception e) { plugin.getLogger().warning("[TablistModule] sendSlots: " + e.getMessage()); }
|
||||||
// Folgeupdate: nur DisplayName + Listed aktualisieren (kein Flackern)
|
|
||||||
PlayerListItemUpdate updPkt = new PlayerListItemUpdate();
|
|
||||||
updPkt.setActions(EnumSet.of(
|
|
||||||
PlayerListItemUpdate.Action.UPDATE_DISPLAY_NAME,
|
|
||||||
PlayerListItemUpdate.Action.UPDATE_LISTED));
|
|
||||||
updPkt.setItems(items);
|
|
||||||
try { sendPacketQueuedMethod.invoke(viewer, updPkt); }
|
|
||||||
catch (Exception e) { plugin.getLogger().warning("[TablistModule] UPDATE_DISPLAY_NAME: " + e.getMessage()); return; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ping immer separat senden
|
|
||||||
PlayerListItemUpdate pingPkt = new PlayerListItemUpdate();
|
|
||||||
pingPkt.setActions(EnumSet.of(PlayerListItemUpdate.Action.UPDATE_LATENCY));
|
|
||||||
pingPkt.setItems(items);
|
|
||||||
try { sendPacketQueuedMethod.invoke(viewer, pingPkt); }
|
|
||||||
catch (Exception e) { plugin.getLogger().warning("[TablistModule] UPDATE_LATENCY: " + e.getMessage()); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeFakeSlots(ProxiedPlayer viewer) {
|
private void removeFakeSlots(ProxiedPlayer viewer) {
|
||||||
@@ -477,25 +461,25 @@ public class TablistModule implements Module, Listener {
|
|||||||
|
|
||||||
// ── Helpers ────────────────────────────────────────────────────────────────
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private int set(String[] arr, int base, int row, String text) {
|
private net.md_5.bungee.protocol.data.Property[] fetchSkin(ProxiedPlayer player) {
|
||||||
if (base + row < total) arr[base + row] = text == null ? " " : text;
|
|
||||||
return row + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private net.md_5.bungee.protocol.data.Property[] getPlayerSkin(ProxiedPlayer player) {
|
|
||||||
try {
|
try {
|
||||||
Object pending = player.getPendingConnection();
|
Object pending = player.getPendingConnection();
|
||||||
net.md_5.bungee.connection.LoginResult profile =
|
net.md_5.bungee.connection.LoginResult profile =
|
||||||
(net.md_5.bungee.connection.LoginResult)
|
(net.md_5.bungee.connection.LoginResult) pending.getClass().getMethod("getLoginProfile").invoke(pending);
|
||||||
pending.getClass().getMethod("getLoginProfile").invoke(pending);
|
if (profile != null && profile.getProperties() != null && profile.getProperties().length > 0)
|
||||||
if (profile != null && profile.getProperties() != null) return profile.getProperties();
|
return profile.getProperties();
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
return new net.md_5.bungee.protocol.data.Property[0];
|
return new net.md_5.bungee.protocol.data.Property[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getServerOrder() {
|
private List<String> getServerOrder() {
|
||||||
if (!serverOrder.isEmpty()) return new ArrayList<>(serverOrder);
|
List<String> list;
|
||||||
List<String> list = new ArrayList<>();
|
if (!serverOrder.isEmpty()) {
|
||||||
|
list = new ArrayList<>(serverOrder);
|
||||||
|
// Versteckte Server auch aus manueller Liste entfernen
|
||||||
|
list.removeIf(s -> hiddenServers.contains(s.toLowerCase()));
|
||||||
|
} else {
|
||||||
|
list = new ArrayList<>();
|
||||||
final String[] lobbyKey = {null};
|
final String[] lobbyKey = {null};
|
||||||
for (String key : ProxyServer.getInstance().getServers().keySet())
|
for (String key : ProxyServer.getInstance().getServers().keySet())
|
||||||
if (key.equalsIgnoreCase("lobby")) { lobbyKey[0] = key; break; }
|
if (key.equalsIgnoreCase("lobby")) { lobbyKey[0] = key; break; }
|
||||||
@@ -503,11 +487,33 @@ public class TablistModule implements Module, Listener {
|
|||||||
ProxyServer.getInstance().getServers().keySet().stream()
|
ProxyServer.getInstance().getServers().keySet().stream()
|
||||||
.filter(s -> lobbyKey[0] == null || !s.equalsIgnoreCase(lobbyKey[0]))
|
.filter(s -> lobbyKey[0] == null || !s.equalsIgnoreCase(lobbyKey[0]))
|
||||||
.filter(s -> !hiddenServers.contains(s.toLowerCase()))
|
.filter(s -> !hiddenServers.contains(s.toLowerCase()))
|
||||||
.sorted(String.CASE_INSENSITIVE_ORDER)
|
.sorted(String.CASE_INSENSITIVE_ORDER).forEach(list::add);
|
||||||
.forEach(list::add);
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ProxiedPlayer> sortPlayersByRank(List<ProxiedPlayer> players) {
|
||||||
|
if (rankOrder.isEmpty()) return players;
|
||||||
|
players.sort((a, b) -> { int ia = getRankIndex(a), ib = getRankIndex(b);
|
||||||
|
return ia != ib ? Integer.compare(ia, ib) : a.getName().compareToIgnoreCase(b.getName()); });
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getRankIndex(ProxiedPlayer player) {
|
||||||
|
try {
|
||||||
|
Class<?> prov = Class.forName("net.luckperms.api.LuckPermsProvider");
|
||||||
|
Object api = prov.getMethod("get").invoke(null);
|
||||||
|
Object um = api.getClass().getMethod("getUserManager").invoke(api);
|
||||||
|
Object usr = um.getClass().getMethod("getUser", UUID.class).invoke(um, player.getUniqueId());
|
||||||
|
if (usr != null) {
|
||||||
|
Object pg = usr.getClass().getMethod("getPrimaryGroup").invoke(usr);
|
||||||
|
if (pg != null) { String g = pg.toString().toLowerCase();
|
||||||
|
for (int i = 0; i < rankOrder.size(); i++) if (rankOrder.get(i).equalsIgnoreCase(g)) return i; }
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
return rankOrder.size();
|
||||||
|
}
|
||||||
|
|
||||||
private String getRank(ProxiedPlayer player) {
|
private String getRank(ProxiedPlayer player) {
|
||||||
try {
|
try {
|
||||||
Class<?> prov = Class.forName("net.luckperms.api.LuckPermsProvider");
|
Class<?> prov = Class.forName("net.luckperms.api.LuckPermsProvider");
|
||||||
@@ -546,81 +552,67 @@ public class TablistModule implements Module, Listener {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sortiert Spieler nach der konfigurierten Rang-Reihenfolge.
|
|
||||||
* Spieler mit hohem Rang (Index 0 in rankOrder) kommen zuerst.
|
|
||||||
* Spieler mit unbekanntem Rang kommen ans Ende, alphabetisch sortiert.
|
|
||||||
*/
|
|
||||||
private List<ProxiedPlayer> sortPlayersByRank(List<ProxiedPlayer> players) {
|
|
||||||
if (rankOrder.isEmpty()) return players;
|
|
||||||
players.sort((a, b) -> {
|
|
||||||
int idxA = getRankIndex(a);
|
|
||||||
int idxB = getRankIndex(b);
|
|
||||||
if (idxA != idxB) return Integer.compare(idxA, idxB);
|
|
||||||
return a.getName().compareToIgnoreCase(b.getName());
|
|
||||||
});
|
|
||||||
return players;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gibt den Index des Spielers in der rankOrder-Liste zurück (niedrig = höher). */
|
|
||||||
private int getRankIndex(ProxiedPlayer player) {
|
|
||||||
try {
|
|
||||||
Class<?> prov = Class.forName("net.luckperms.api.LuckPermsProvider");
|
|
||||||
Object api = prov.getMethod("get").invoke(null);
|
|
||||||
Object um = api.getClass().getMethod("getUserManager").invoke(api);
|
|
||||||
Object usr = um.getClass().getMethod("getUser", UUID.class).invoke(um, player.getUniqueId());
|
|
||||||
if (usr != null) {
|
|
||||||
Object pg = usr.getClass().getMethod("getPrimaryGroup").invoke(usr);
|
|
||||||
if (pg != null) {
|
|
||||||
String group = pg.toString().toLowerCase();
|
|
||||||
for (int i = 0; i < rankOrder.size(); i++) {
|
|
||||||
if (rankOrder.get(i).equalsIgnoreCase(group)) return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
return rankOrder.size(); // unbekannter Rang ans Ende
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String fakeName(int i) { return String.format("~vt%03d", i); }
|
|
||||||
private static String c(String s) { return ChatColor.translateAlternateColorCodes('&', s == null ? "" : s); }
|
|
||||||
private static String capitalize(String s) { return s == null || s.isEmpty() ? s : Character.toUpperCase(s.charAt(0)) + s.substring(1); }
|
|
||||||
private static String rep(char ch, int n) { StringBuilder sb = new StringBuilder(n); for (int i=0;i<n;i++) sb.append(ch); return sb.toString(); }
|
|
||||||
private int parseInt(String s, int fb) { try { return Integer.parseInt(s == null ? "" : s.trim()); } catch (Exception e) { return fb; } }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ersetzt alle Platzhalter in einem Text:
|
|
||||||
* %player% %rank% %server% %world% %time% %balance% %ping% %online%
|
|
||||||
*/
|
|
||||||
private String replacePlaceholders(String text, ProxiedPlayer viewer,
|
|
||||||
String srv, String world, String rank,
|
|
||||||
String time, String balance, int online) {
|
|
||||||
if (text == null) return "";
|
|
||||||
return text
|
|
||||||
.replace("%player%", viewer.getName())
|
|
||||||
.replace("%rank%", rank)
|
|
||||||
.replace("%server%", srv)
|
|
||||||
.replace("%world%", world)
|
|
||||||
.replace("%time%", time)
|
|
||||||
.replace("%balance%", balance)
|
|
||||||
.replace("%ping%", String.valueOf(viewer.getPing()))
|
|
||||||
.replace("%online%", String.valueOf(online));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Liest den Kontostand aus der StatusAPI-Economy-Map (wird von StatusAPIBridge gepusht). */
|
|
||||||
private String getBalance(ProxiedPlayer player) {
|
private String getBalance(ProxiedPlayer player) {
|
||||||
try {
|
try {
|
||||||
java.util.Map<?, ?> balances = (java.util.Map<?, ?>) net.viper.status.StatusAPI.class
|
Map<?,?> balances = (Map<?,?>) net.viper.status.StatusAPI.class.getField("playerBalances").get(null);
|
||||||
.getField("playerBalances").get(null);
|
|
||||||
Object val = balances.get(player.getUniqueId());
|
Object val = balances.get(player.getUniqueId());
|
||||||
if (val != null) {
|
if (val != null) return String.format("%,.2f", ((Number) val).doubleValue());
|
||||||
double d = ((Number) val).doubleValue();
|
|
||||||
return String.format("%,.2f", d);
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
return "0.00";
|
return "0.00";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String replacePlaceholders(String text, ProxiedPlayer viewer, String srv, String world, String rank, String time, String balance, int online) {
|
||||||
|
if (text == null) return "";
|
||||||
|
return text.replace("%player%", viewer.getName()).replace("%rank%", rank)
|
||||||
|
.replace("%server%", srv).replace("%world%", world).replace("%time%", time)
|
||||||
|
.replace("%balance%", balance).replace("%ping%", String.valueOf(viewer.getPing()))
|
||||||
|
.replace("%online%", String.valueOf(online));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int set(String[] arr, int base, int row, String text) {
|
||||||
|
if (base + row < total) arr[base + row] = text == null ? " " : text; return row + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String c(String s) {
|
||||||
|
if (s == null) return "";
|
||||||
|
s = replaceHexColors(s);
|
||||||
|
return ChatColor.translateAlternateColorCodes('&', s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String replaceHexColors(String text) {
|
||||||
|
if (text == null || (!text.contains("&#") && !text.contains("{#"))) return text;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int i = 0;
|
||||||
|
while (i < text.length()) {
|
||||||
|
if (i + 7 <= text.length() && text.charAt(i) == '&' && text.charAt(i+1) == '#') {
|
||||||
|
String hex = text.substring(i+2, i+8);
|
||||||
|
if (hex.matches("[0-9a-fA-F]{6}")) {
|
||||||
|
sb.append('\u00A7').append('x');
|
||||||
|
for (char ch : hex.toCharArray()) sb.append('\u00A7').append(ch);
|
||||||
|
i += 8; continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i + 8 < text.length() && text.charAt(i) == '{' && text.charAt(i+1) == '#') {
|
||||||
|
int end = text.indexOf('}', i+2);
|
||||||
|
if (end == i+8) {
|
||||||
|
String hex = text.substring(i+2, i+8);
|
||||||
|
if (hex.matches("[0-9a-fA-F]{6}")) {
|
||||||
|
sb.append('\u00A7').append('x');
|
||||||
|
for (char ch : hex.toCharArray()) sb.append('\u00A7').append(ch);
|
||||||
|
i += 9; continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append(text.charAt(i)); i++;
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String fakeName(int i) { return String.format("~vt%03d", i); }
|
||||||
|
private static String capitalize(String s){ return s==null||s.isEmpty()?s:Character.toUpperCase(s.charAt(0))+s.substring(1); }
|
||||||
|
private static String rep(char ch, int n) { StringBuilder sb=new StringBuilder(n); for(int i=0;i<n;i++) sb.append(ch); return sb.toString(); }
|
||||||
|
private int parseInt(String s, int fb) { try{return Integer.parseInt(s==null?"":s.trim());}catch(Exception e){return fb;} }
|
||||||
|
|
||||||
// ── Config ─────────────────────────────────────────────────────────────────
|
// ── Config ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private void ensureConfigExists() {
|
private void ensureConfigExists() {
|
||||||
@@ -631,16 +623,13 @@ public class TablistModule implements Module, Listener {
|
|||||||
String content =
|
String content =
|
||||||
"# TablistModule Konfiguration\n" +
|
"# TablistModule Konfiguration\n" +
|
||||||
"tablist.enabled=true\n" +
|
"tablist.enabled=true\n" +
|
||||||
"tablist.update_interval=5\n\n" +
|
"tablist.tab_size=160\n" +
|
||||||
"# Layout-Modus: classic (Trennlinien + Info-Spalte links) oder compact (wie SecretCraft)\n" +
|
"tablist.update_interval=5\n" +
|
||||||
"tablist.layout=classic\n\n" +
|
"# Layout-Modus: classic oder compact\n" +
|
||||||
"# Server-Reihenfolge (leer = Lobby zuerst, dann alphabetisch)\n" +
|
"tablist.layout=compact\n" +
|
||||||
"tablist.server_order=\n\n" +
|
"tablist.server_order=\n" +
|
||||||
"# Server die NICHT angezeigt werden (kommagetrennt, leer = alle anzeigen)\n" +
|
"tablist.hidden_servers=\n" +
|
||||||
"tablist.hidden_servers=\n\n" +
|
|
||||||
"# Rang-Reihenfolge fuer Spieler-Sortierung (hoechster Rang zuerst, LuckPerms Gruppenname)\n" +
|
|
||||||
"tablist.rank_order=owner,mod,primo,vip,scout,bewohner\n\n" +
|
"tablist.rank_order=owner,mod,primo,vip,scout,bewohner\n\n" +
|
||||||
"# ── Classic Layout ──────────────────────────────────────────────────\n" +
|
|
||||||
"tablist.header.line1=&8&m" + sep + "\n" +
|
"tablist.header.line1=&8&m" + sep + "\n" +
|
||||||
"tablist.header.line2= &6&lViper Network\n" +
|
"tablist.header.line2= &6&lViper Network\n" +
|
||||||
"tablist.header.line3=&8&m" + sep + "\n\n" +
|
"tablist.header.line3=&8&m" + sep + "\n\n" +
|
||||||
@@ -649,9 +638,9 @@ public class TablistModule implements Module, Listener {
|
|||||||
"tablist.footer.line3=&8&m" + sep + "\n\n" +
|
"tablist.footer.line3=&8&m" + sep + "\n\n" +
|
||||||
"# ── Compact Layout ──────────────────────────────────────────────────\n" +
|
"# ── Compact Layout ──────────────────────────────────────────────────\n" +
|
||||||
"# Platzhalter: %player% %rank% %server% %world% %time% %balance% %ping% %online%\n" +
|
"# Platzhalter: %player% %rank% %server% %world% %time% %balance% %ping% %online%\n" +
|
||||||
"# spacer=true: leere Zeile = sichtbarer Abstand | spacer=false: leere Zeile = wird uebersprungen\n" +
|
"# spacer=true: leere Zeile = Abstand | spacer=false: leere Zeile = überspringen\n" +
|
||||||
"tablist.compact.header.line1=&6&lViper Network &8• &2Hallo, &a%player%&7! &6Schön dass du da bist!\n" +
|
"tablist.compact.header.line1=&6&lViper Network &8• &2Hallo, &a%player%&7!\n" +
|
||||||
"tablist.compact.header.line2=&dCitybuild &8• &aSurvival &8• &eMinigames &3– Für jeden etwas dabei!\n" +
|
"tablist.compact.header.line2=&dCitybuild &8• &aSurvival &8• &eMinigames\n" +
|
||||||
"tablist.compact.header.line2.spacer=false\n" +
|
"tablist.compact.header.line2.spacer=false\n" +
|
||||||
"tablist.compact.header.line3=\n" +
|
"tablist.compact.header.line3=\n" +
|
||||||
"tablist.compact.header.line3.spacer=false\n\n" +
|
"tablist.compact.header.line3.spacer=false\n\n" +
|
||||||
@@ -666,8 +655,7 @@ public class TablistModule implements Module, Listener {
|
|||||||
"tablist.color.server_header=&6&l\n" +
|
"tablist.color.server_header=&6&l\n" +
|
||||||
"tablist.time_format=HH:mm:ss / h:mm a\n" +
|
"tablist.time_format=HH:mm:ss / h:mm a\n" +
|
||||||
"tablist.timezone=Europe/Berlin\n\n" +
|
"tablist.timezone=Europe/Berlin\n\n" +
|
||||||
"# ── Info-Spalte (nur classic Layout) ────────────────────────────────\n" +
|
"# ── Info-Spalte (nur classic) ────────────────────────────────────────\n" +
|
||||||
"# Platzhalter auch hier verfuegbar: %player% %balance% %ping% %online% usw.\n" +
|
|
||||||
"tablist.info.order=website,name,rank,server,world,time,teamspeak\n\n" +
|
"tablist.info.order=website,name,rank,server,world,time,teamspeak\n\n" +
|
||||||
"tablist.info.website.enabled=true\n" +
|
"tablist.info.website.enabled=true\n" +
|
||||||
"tablist.info.website.label=&b&lWebsite:\n" +
|
"tablist.info.website.label=&b&lWebsite:\n" +
|
||||||
@@ -693,62 +681,75 @@ public class TablistModule implements Module, Listener {
|
|||||||
"tablist.info.teamspeak.type=teamspeak\n" +
|
"tablist.info.teamspeak.type=teamspeak\n" +
|
||||||
"tablist.info.teamspeak.value=&fts.viper-network.de\n";
|
"tablist.info.teamspeak.value=&fts.viper-network.de\n";
|
||||||
try (OutputStream out = new FileOutputStream(f)) { out.write(content.getBytes(StandardCharsets.UTF_8)); }
|
try (OutputStream out = new FileOutputStream(f)) { out.write(content.getBytes(StandardCharsets.UTF_8)); }
|
||||||
catch (Exception e) { plugin.getLogger().warning("[TablistModule] Config-Fehler: " + e.getMessage()); }
|
catch (Exception e) { plugin.getLogger().warning("[TablistModule] Config: " + e.getMessage()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadConfig() {
|
private void loadConfig() {
|
||||||
File file = new File(plugin.getDataFolder(), CONFIG_FILE);
|
File file = new File(plugin.getDataFolder(), CONFIG_FILE);
|
||||||
Properties p = new Properties();
|
Map<String, String> map = new LinkedHashMap<>();
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
try (FileInputStream fis = new FileInputStream(file)) {
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
|
||||||
p.load(new InputStreamReader(fis, StandardCharsets.UTF_8));
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
line = line.trim();
|
||||||
|
if (line.isEmpty() || line.startsWith("#")) continue;
|
||||||
|
int eq = line.indexOf('=');
|
||||||
|
if (eq < 1) continue;
|
||||||
|
map.put(line.substring(0, eq).trim(), line.substring(eq + 1));
|
||||||
|
}
|
||||||
} catch (Exception e) { plugin.getLogger().warning("[TablistModule] Ladefehler: " + e.getMessage()); }
|
} catch (Exception e) { plugin.getLogger().warning("[TablistModule] Ladefehler: " + e.getMessage()); }
|
||||||
}
|
}
|
||||||
enabled = Boolean.parseBoolean(p.getProperty("tablist.enabled", "true"));
|
java.util.function.BiFunction<String,String,String> get = (k,d) -> map.getOrDefault(k,d);
|
||||||
updateInterval = parseInt(p.getProperty("tablist.update_interval", "5"), 5);
|
|
||||||
layoutMode = p.getProperty("tablist.layout", "classic").trim().toLowerCase();
|
configuredTabSize = parseInt(get.apply("tablist.tab_size", "0"), 0);
|
||||||
headerLine1 = p.getProperty("tablist.header.line1", headerLine1);
|
enabled = Boolean.parseBoolean(get.apply("tablist.enabled", "true"));
|
||||||
headerLine2 = p.getProperty("tablist.header.line2", headerLine2);
|
updateInterval = parseInt(get.apply("tablist.update_interval", "5"), 5);
|
||||||
headerLine3 = p.getProperty("tablist.header.line3", headerLine3);
|
layoutMode = get.apply("tablist.layout", "compact").trim().toLowerCase();
|
||||||
footerLine1 = p.getProperty("tablist.footer.line1", footerLine1);
|
headerLine1 = get.apply("tablist.header.line1", headerLine1);
|
||||||
footerLine2 = p.getProperty("tablist.footer.line2", footerLine2);
|
headerLine2 = get.apply("tablist.header.line2", headerLine2);
|
||||||
footerLine3 = p.getProperty("tablist.footer.line3", footerLine3);
|
headerLine3 = get.apply("tablist.header.line3", headerLine3);
|
||||||
compactHeader1 = p.getProperty("tablist.compact.header.line1", compactHeader1);
|
footerLine1 = get.apply("tablist.footer.line1", footerLine1);
|
||||||
compactHeader2 = p.getProperty("tablist.compact.header.line2", compactHeader2);
|
footerLine2 = get.apply("tablist.footer.line2", footerLine2);
|
||||||
compactHeader3 = p.getProperty("tablist.compact.header.line3", compactHeader3);
|
footerLine3 = get.apply("tablist.footer.line3", footerLine3);
|
||||||
compactHeader2Spacer = Boolean.parseBoolean(p.getProperty("tablist.compact.header.line2.spacer", "false"));
|
compactHeader1 = get.apply("tablist.compact.header.line1", compactHeader1);
|
||||||
compactHeader3Spacer = Boolean.parseBoolean(p.getProperty("tablist.compact.header.line3.spacer", "false"));
|
compactHeader2 = get.apply("tablist.compact.header.line2", compactHeader2);
|
||||||
compactFooter1 = p.getProperty("tablist.compact.footer.line1", compactFooter1);
|
compactHeader3 = get.apply("tablist.compact.header.line3", compactHeader3);
|
||||||
compactFooter2 = p.getProperty("tablist.compact.footer.line2", compactFooter2);
|
compactHeader2Spacer = Boolean.parseBoolean(get.apply("tablist.compact.header.line2.spacer", "false"));
|
||||||
compactFooter3 = p.getProperty("tablist.compact.footer.line3", compactFooter3);
|
compactHeader3Spacer = Boolean.parseBoolean(get.apply("tablist.compact.header.line3.spacer", "false"));
|
||||||
compactFooter4 = p.getProperty("tablist.compact.footer.line4", compactFooter4);
|
compactFooter1 = get.apply("tablist.compact.footer.line1", compactFooter1);
|
||||||
compactFooter1Spacer = Boolean.parseBoolean(p.getProperty("tablist.compact.footer.line1.spacer", "false"));
|
compactFooter2 = get.apply("tablist.compact.footer.line2", compactFooter2);
|
||||||
compactFooter4Spacer = Boolean.parseBoolean(p.getProperty("tablist.compact.footer.line4.spacer", "false"));
|
compactFooter3 = get.apply("tablist.compact.footer.line3", compactFooter3);
|
||||||
colorSrvHeader = p.getProperty("tablist.color.server_header", colorSrvHeader);
|
compactFooter4 = get.apply("tablist.compact.footer.line4", compactFooter4);
|
||||||
timeFormat = p.getProperty("tablist.time_format", timeFormat);
|
compactFooter1Spacer = Boolean.parseBoolean(get.apply("tablist.compact.footer.line1.spacer", "false"));
|
||||||
timeZone = p.getProperty("tablist.timezone", timeZone);
|
compactFooter4Spacer = Boolean.parseBoolean(get.apply("tablist.compact.footer.line4.spacer", "false"));
|
||||||
try {
|
colorSrvHeader = get.apply("tablist.color.server_header", colorSrvHeader);
|
||||||
sdf = new SimpleDateFormat(timeFormat);
|
timeFormat = get.apply("tablist.time_format", timeFormat);
|
||||||
sdf.setTimeZone(java.util.TimeZone.getTimeZone(timeZone));
|
timeZone = get.apply("tablist.timezone", timeZone);
|
||||||
} catch (Exception e) {
|
try { sdf = new SimpleDateFormat(timeFormat); sdf.setTimeZone(java.util.TimeZone.getTimeZone(timeZone)); }
|
||||||
sdf = new SimpleDateFormat("HH:mm:ss / h:mm a");
|
catch (Exception e) { sdf = new SimpleDateFormat("HH:mm:ss / h:mm a"); }
|
||||||
sdf.setTimeZone(java.util.TimeZone.getTimeZone("Europe/Berlin"));
|
|
||||||
}
|
rankOrder.clear();
|
||||||
|
String rankRaw = get.apply("tablist.rank_order", "").trim();
|
||||||
|
if (!rankRaw.isEmpty()) for (String s : rankRaw.split(",")) { String t=s.trim(); if(!t.isEmpty()) rankOrder.add(t.toLowerCase()); }
|
||||||
|
|
||||||
|
serverOrder.clear();
|
||||||
|
String raw = get.apply("tablist.server_order", "").trim();
|
||||||
|
if (!raw.isEmpty()) for (String s : raw.split(",")) { String t=s.trim(); if(!t.isEmpty()) serverOrder.add(t.toLowerCase()); }
|
||||||
|
|
||||||
|
hiddenServers.clear();
|
||||||
|
String hRaw = get.apply("tablist.hidden_servers", "").trim();
|
||||||
|
if (!hRaw.isEmpty()) for (String s : hRaw.split(",")) { String t=s.trim().toLowerCase(); if(!t.isEmpty()) hiddenServers.add(t); }
|
||||||
|
|
||||||
// Info-Eintraege laden
|
|
||||||
infoEntries.clear();
|
infoEntries.clear();
|
||||||
String orderRaw = p.getProperty("tablist.info.order",
|
String orderRaw = get.apply("tablist.info.order", "website,name,rank,server,world,time,teamspeak").trim();
|
||||||
"website,name,rank,server,world,time,teamspeak").trim();
|
|
||||||
for (String id : orderRaw.split(",")) {
|
for (String id : orderRaw.split(",")) {
|
||||||
id = id.trim();
|
id = id.trim(); if (id.isEmpty()) continue;
|
||||||
if (id.isEmpty()) continue;
|
boolean en = Boolean.parseBoolean(get.apply("tablist.info." + id + ".enabled", "true"));
|
||||||
boolean enabled = Boolean.parseBoolean(p.getProperty("tablist.info." + id + ".enabled", "true"));
|
String label = get.apply("tablist.info." + id + ".label", "");
|
||||||
String label = p.getProperty("tablist.info." + id + ".label", "");
|
String type = get.apply("tablist.info." + id + ".type", "custom");
|
||||||
String type = p.getProperty("tablist.info." + id + ".type", "custom");
|
String value = get.apply("tablist.info." + id + ".value", "");
|
||||||
String value = p.getProperty("tablist.info." + id + ".value", "");
|
infoEntries.add(new InfoEntry(label, type, value, en));
|
||||||
infoEntries.add(new InfoEntry(label, type, value, enabled));
|
|
||||||
}
|
}
|
||||||
// Fallback wenn keine Eintraege konfiguriert
|
|
||||||
if (infoEntries.isEmpty()) {
|
if (infoEntries.isEmpty()) {
|
||||||
infoEntries.add(new InfoEntry("&b&lWebsite:", "website", "&fviper-network.de", true));
|
infoEntries.add(new InfoEntry("&b&lWebsite:", "website", "&fviper-network.de", true));
|
||||||
infoEntries.add(new InfoEntry("&b&lName:", "name", "", true));
|
infoEntries.add(new InfoEntry("&b&lName:", "name", "", true));
|
||||||
@@ -758,19 +759,5 @@ public class TablistModule implements Module, Listener {
|
|||||||
infoEntries.add(new InfoEntry("&b&lTime:", "time", "", true));
|
infoEntries.add(new InfoEntry("&b&lTime:", "time", "", true));
|
||||||
infoEntries.add(new InfoEntry("&b&lTeamspeak:", "teamspeak", "&fts.viper-network.de", true));
|
infoEntries.add(new InfoEntry("&b&lTeamspeak:", "teamspeak", "&fts.viper-network.de", true));
|
||||||
}
|
}
|
||||||
|
|
||||||
rankOrder.clear();
|
|
||||||
String rankRaw = p.getProperty("tablist.rank_order", "").trim();
|
|
||||||
if (!rankRaw.isEmpty())
|
|
||||||
for (String s : rankRaw.split(",")) { String t = s.trim(); if (!t.isEmpty()) rankOrder.add(t.toLowerCase()); }
|
|
||||||
|
|
||||||
serverOrder.clear();
|
|
||||||
String raw = p.getProperty("tablist.server_order", "").trim();
|
|
||||||
if (!raw.isEmpty())
|
|
||||||
for (String s : raw.split(",")) { String t = s.trim(); if (!t.isEmpty()) serverOrder.add(t.toLowerCase()); }
|
|
||||||
hiddenServers.clear();
|
|
||||||
String hiddenRaw = p.getProperty("tablist.hidden_servers", "").trim();
|
|
||||||
if (!hiddenRaw.isEmpty())
|
|
||||||
for (String s : hiddenRaw.split(",")) { String t = s.trim().toLowerCase(); if (!t.isEmpty()) hiddenServers.add(t); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
package net.viper.status.modules.verify;
|
package net.viper.status.modules.verify;
|
||||||
|
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Command;
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
|
import net.viper.status.StatusAPI;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.viper.status.module.Module;
|
import net.viper.status.module.Module;
|
||||||
|
|
||||||
@@ -38,7 +44,7 @@ public class VerifyModule implements Module {
|
|||||||
public void onEnable(Plugin plugin) {
|
public void onEnable(Plugin plugin) {
|
||||||
loadConfig(plugin);
|
loadConfig(plugin);
|
||||||
ProxyServer.getInstance().getPluginManager().registerCommand(plugin, new VerifyCommand());
|
ProxyServer.getInstance().getPluginManager().registerCommand(plugin, new VerifyCommand());
|
||||||
plugin.getLogger().info("VerifyModule aktiviert. " + serverConfigs.size() + " Server-Konfigurationen geladen.");
|
plugin.getLogger().fine("VerifyModule aktiviert. " + serverConfigs.size() + " Server-Konfigurationen geladen.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -56,7 +62,7 @@ public class VerifyModule implements Module {
|
|||||||
if (in == null) { plugin.getLogger().warning("Standard-config '" + fileName + "' nicht in JAR."); return; }
|
if (in == null) { plugin.getLogger().warning("Standard-config '" + fileName + "' nicht in JAR."); return; }
|
||||||
byte[] buffer = new byte[1024]; int length;
|
byte[] buffer = new byte[1024]; int length;
|
||||||
while ((length = in.read(buffer)) > 0) out.write(buffer, 0, length);
|
while ((length = in.read(buffer)) > 0) out.write(buffer, 0, length);
|
||||||
plugin.getLogger().info("Konfigurationsdatei '" + fileName + "' erstellt.");
|
StatusAPI.debugLog(plugin, "Konfigurationsdatei '" + fileName + "' erstellt.");
|
||||||
} catch (Exception e) { plugin.getLogger().severe("Fehler beim Erstellen der Config: " + e.getMessage()); return; }
|
} catch (Exception e) { plugin.getLogger().severe("Fehler beim Erstellen der Config: " + e.getMessage()); return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: StatusAPI
|
name: StatusAPI
|
||||||
main: net.viper.status.StatusAPI
|
main: net.viper.status.StatusAPI
|
||||||
version: 4.1.1
|
version: 4.1.0
|
||||||
author: M_Viper
|
author: M_Viper
|
||||||
description: StatusAPI für BungeeCord inkl. Update-Checker, Modul-System und ChatModule
|
description: StatusAPI für BungeeCord inkl. Update-Checker, Modul-System und ChatModule
|
||||||
# Mindestanforderung: Minecraft 1.20 / BungeeCord mit PlayerChatEvent-Unterstützung
|
# Mindestanforderung: Minecraft 1.20 / BungeeCord mit PlayerChatEvent-Unterstützung
|
||||||
|
|||||||
Reference in New Issue
Block a user