119 lines
4.5 KiB
Java
119 lines
4.5 KiB
Java
package de.nexuslobby.modules.servers;
|
|
|
|
import de.nexuslobby.NexusLobby;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.ChatColor;
|
|
import org.bukkit.World;
|
|
import org.bukkit.entity.ArmorStand;
|
|
|
|
import java.io.IOException;
|
|
import java.net.InetSocketAddress;
|
|
import java.net.Socket;
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
|
public class ServerChecker {
|
|
|
|
/**
|
|
* Prüft asynchron, ob ein Server unter der angegebenen IP und Port erreichbar ist.
|
|
*/
|
|
public static CompletableFuture<Boolean> isOnline(String ip, int port) {
|
|
return CompletableFuture.supplyAsync(() -> {
|
|
try (Socket socket = new Socket()) {
|
|
// 500ms Timeout für stabilere Erkennung
|
|
socket.connect(new InetSocketAddress(ip, port), 500);
|
|
return true;
|
|
} catch (IOException e) {
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Startet den Scheduler, der alle ArmorStands in allen Welten regelmäßig prüft.
|
|
*/
|
|
public static void startGlobalChecker() {
|
|
// WICHTIG: runTaskTimer (synchron), um den Main-Thread für getEntitiesByClass zu nutzen
|
|
Bukkit.getScheduler().runTaskTimer(NexusLobby.getInstance(), () -> {
|
|
for (World world : Bukkit.getWorlds()) {
|
|
// Das Abrufen der Entities muss auf dem Main-Thread passieren
|
|
for (ArmorStand as : world.getEntitiesByClass(ArmorStand.class)) {
|
|
checkAndUpdateArmorStand(as);
|
|
}
|
|
}
|
|
}, 100L, 200L);
|
|
}
|
|
|
|
/**
|
|
* Analysiert die Tags eines ArmorStands und aktualisiert den Namen basierend auf dem Serverstatus.
|
|
*/
|
|
private static void checkAndUpdateArmorStand(ArmorStand as) {
|
|
for (String tag : as.getScoreboardTags()) {
|
|
// Erwartetes Format: ascmd:slot1:slot2:type:command
|
|
if (tag.startsWith("ascmd:")) {
|
|
String[] parts = tag.split(":");
|
|
if (parts.length < 5) continue;
|
|
|
|
String type = parts[3].toLowerCase();
|
|
if (!type.equals("bungee")) continue;
|
|
|
|
String serverName = parts[4];
|
|
|
|
// Suche den passenden Key in der Config
|
|
String configKey = null;
|
|
if (NexusLobby.getInstance().getConfig().getConfigurationSection("servers") != null) {
|
|
for (String key : NexusLobby.getInstance().getConfig().getConfigurationSection("servers").getKeys(false)) {
|
|
if (key.equalsIgnoreCase(serverName)) {
|
|
configKey = key;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (configKey == null) continue;
|
|
|
|
String ip = NexusLobby.getInstance().getConfig().getString("servers." + configKey + ".ip");
|
|
int port = NexusLobby.getInstance().getConfig().getInt("servers." + configKey + ".port");
|
|
|
|
if (ip == null) continue;
|
|
|
|
// Der Ping selbst läuft asynchron weg vom Main-Thread
|
|
isOnline(ip, port).thenAccept(online -> {
|
|
// Zurück zum Main-Thread für die Änderung des ArmorStands
|
|
Bukkit.getScheduler().runTask(NexusLobby.getInstance(), () -> {
|
|
if (!as.isValid()) return; // Sicherheitscheck falls AS gelöscht wurde
|
|
|
|
if (online) {
|
|
restoreName(as);
|
|
} else {
|
|
String offlineText = "§c● §lOFFLINE §c●";
|
|
if (!offlineText.equals(as.getCustomName())) {
|
|
as.setCustomName(offlineText);
|
|
as.setCustomNameVisible(true);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stellt den ursprünglichen Namen des ArmorStands wieder her.
|
|
* Nutzt den Tag "asname:NAME" als Backup.
|
|
*/
|
|
private static void restoreName(ArmorStand as) {
|
|
for (String t : as.getScoreboardTags()) {
|
|
if (t.startsWith("asname:")) {
|
|
String originalName = t.substring(7);
|
|
String translatedName = ChatColor.translateAlternateColorCodes('&', originalName);
|
|
|
|
if (!translatedName.equals(as.getCustomName())) {
|
|
as.setCustomName(translatedName);
|
|
as.setCustomNameVisible(true);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
} |