From b9da29a996851960ad609f63eccca93a76f168c0 Mon Sep 17 00:00:00 2001 From: legan100 Date: Sun, 14 Jun 2026 21:17:33 +0200 Subject: [PATCH 1/3] feat: add TCP-Connection --- .idea/artifacts/API.xml | 1 + .idea/workspace.xml | 105 ++++------- src/de/legan100/api/API.java | 42 ++++- src/de/legan100/api/utils/BackendClient.java | 186 +++++++++++++++++++ 4 files changed, 259 insertions(+), 75 deletions(-) create mode 100644 src/de/legan100/api/utils/BackendClient.java diff --git a/.idea/artifacts/API.xml b/.idea/artifacts/API.xml index 5347cb7..0987a84 100644 --- a/.idea/artifacts/API.xml +++ b/.idea/artifacts/API.xml @@ -4,6 +4,7 @@ + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 59c36e8..6b98fc8 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -10,50 +10,10 @@ - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - { + "keyToString": { + "Maven.API [install].executor": "Run", + "Maven.API [package].executor": "Run", + "Maven.Chatsystem [package].executor": "Run", + "Maven.api [validate].executor": "Run", + "OpenRewrite.Faces4xMigrationToFaces41x.executor": "Run", + "RunOnceActivity.ShowReadmeOnStart": "true", + "SHARE_PROJECT_CONFIGURATION_FILES": "true", + "git-widget-placeholder": "main", + "kotlin-language-version-configured": "true", + "last_opened_file_path": "C:/Users/nicon/IdeaProjects/API/plugin.yml", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "project.structure.last.edited": "Artifacts", + "project.structure.proportion": "0.15", + "project.structure.side.proportion": "0.2", + "settings.editor.selected.configurable": "reference.settings.project.maven.repository.indices", + "vue.rearranger.settings.migration": "true" } -}]]> +} @@ -196,7 +156,10 @@ - + + + + - diff --git a/src/de/legan100/api/API.java b/src/de/legan100/api/API.java index b5d0e6c..57df488 100644 --- a/src/de/legan100/api/API.java +++ b/src/de/legan100/api/API.java @@ -3,6 +3,7 @@ import de.legan100.api.commands.*; import de.legan100.api.listener.ChatListener; import de.legan100.api.listener.JoinListener; +import de.legan100.api.utils.BackendClient; import de.legan100.api.utils.Broadcaster; import de.legan100.api.utils.FileManager; import de.legan100.api.utils.MySQL; @@ -11,17 +12,46 @@ public class API extends JavaPlugin { private static API instance; + private BackendClient backend; + public static API getInstance() { + return instance; + } + + public BackendClient getBackend() { + return backend; + } + @Override public void onEnable() { - (new Broadcaster(this)).startBroadcast(); + instance = this; + new Broadcaster(this).startBroadcast(); register(); FileManager.createFile(); - instance = this; - } + backend = new BackendClient(); + backend.connect(); + backend.send(""" + { + "type":"SERVER_START", + "server":"%s" + } + """.formatted(getServer().getName())); + } + @Override public void onDisable() { + + if (backend != null) { + backend.send(""" + { + "type":"SERVER_STOP" + } + """); + + backend.disconnect(); + } + MySQL.disconnect(); } @@ -65,8 +95,4 @@ public void register() { getServer().getPluginManager().registerEvents(new ChatListener(), this); getServer().getPluginManager().registerEvents(new JoinListener(), this); } - - public API getInstance(){ - return this; - } -} +} \ No newline at end of file diff --git a/src/de/legan100/api/utils/BackendClient.java b/src/de/legan100/api/utils/BackendClient.java new file mode 100644 index 0000000..d64bcfa --- /dev/null +++ b/src/de/legan100/api/utils/BackendClient.java @@ -0,0 +1,186 @@ +package de.legan100.api.utils; + +import org.bukkit.Bukkit; + +import java.io.*; +import java.net.Socket; +import java.util.concurrent.atomic.AtomicBoolean; + +public class BackendClient { + + private static final String HOST = "127.0.0.1"; + private static final int PORT = 10000; + + private Socket socket; + private PrintWriter out; + private BufferedReader in; + + private final AtomicBoolean reconnecting = new AtomicBoolean(false); + private final AtomicBoolean connected = new AtomicBoolean(false); + + public void connect() { + try { + + socket = new Socket(HOST, PORT); + + socket.setKeepAlive(true); + socket.setTcpNoDelay(true); + + out = new PrintWriter(socket.getOutputStream(), true); + in = new BufferedReader( + new InputStreamReader(socket.getInputStream())); + + connected.set(true); + + System.out.println("[BackendClient] Connected to backend"); + + startListener(); + startPingTask(); + + } catch (IOException e) { + + connected.set(false); + + System.err.println("[BackendClient] Connection failed"); + reconnect(); + } + } + + private void startListener() { + + Thread listenerThread = new Thread(() -> { + + try { + + String line; + + while (connected.get() + && socket != null + && !socket.isClosed() + && (line = in.readLine()) != null) { + + handleMessage(line); + } + + } catch (Exception e) { + + if (connected.get()) { + System.err.println("[BackendClient] Connection lost"); + } + + } finally { + + connected.set(false); + reconnect(); + } + + }); + + listenerThread.setName("Backend-Listener"); + listenerThread.setDaemon(true); + listenerThread.start(); + } + + private void handleMessage(String message) { + + if (message.equalsIgnoreCase("PONG")) { + return; + } + + System.out.println("[BACKEND] " + message); + + } + + private void startPingTask() { + Bukkit.getScheduler().runTaskTimerAsynchronously(Bukkit.getPluginManager().getPlugin("API"), () -> { + if (!isConnected()) { + return; + } + send("PING"); + },20L * 30, 20L * 30); + } + + private void reconnect() { + + if (!reconnecting.compareAndSet(false, true)) { + return; + } + + Thread reconnectThread = new Thread(() -> { + while (!connected.get()) { + try { + System.out.println("[BackendClient] Reconnecting..."); + disconnectInternal(); + socket = new Socket(HOST, PORT); + socket.setKeepAlive(true); + socket.setTcpNoDelay(true); + out = new PrintWriter( + socket.getOutputStream(), + true + ); + in = new BufferedReader( + new InputStreamReader( + socket.getInputStream() + ) + ); + connected.set(true); + System.out.println("[BackendClient] Reconnected"); + startListener(); + reconnecting.set(false); + return; + + } catch (Exception ignored) {} + + try { + Thread.sleep(5000); + } catch (InterruptedException ignored) {} + } + reconnecting.set(false); + }); + + reconnectThread.setName("Backend-Reconnect"); + reconnectThread.setDaemon(true); + reconnectThread.start(); + } + + public void send(String message) { + try { + if (!isConnected()) { + return; + } + out.println(message); + } catch (Exception e) { + connected.set(false); + reconnect(); + } + } + + public boolean isConnected() { + return connected.get() && socket != null && !socket.isClosed(); + } + + public void disconnect() { + connected.set(false); + disconnectInternal(); + } + + private void disconnectInternal() { + try { + if (in != null) { + in.close(); + } + } catch (Exception ignored) {} + + try { + if (out != null) { + out.close(); + } + } catch (Exception ignored) {} + + try { + if (socket != null) { + socket.close(); + } + } catch (Exception ignored) {} + } +} \ No newline at end of file From 22e8fed33067b260ccf136128eebfa30b54de6ba Mon Sep 17 00:00:00 2001 From: legan100 Date: Tue, 16 Jun 2026 23:03:48 +0200 Subject: [PATCH 2/3] chore: backup --- .idea/workspace.xml | 28 ++- plugin.yml | 21 +- src/de/legan100/api/API.java | 25 +-- src/de/legan100/api/commands/CMD_BCL.java | 2 +- .../commands/CMD_GetBackendConnection.java | 25 +++ src/de/legan100/api/commands/CMD_gbc.java | 41 ++++ .../api/commands/CMD_globalrestart.java | 21 ++ src/de/legan100/api/utils/BackendClient.java | 201 +++++++++--------- 8 files changed, 239 insertions(+), 125 deletions(-) create mode 100644 src/de/legan100/api/commands/CMD_GetBackendConnection.java create mode 100644 src/de/legan100/api/commands/CMD_gbc.java create mode 100644 src/de/legan100/api/commands/CMD_globalrestart.java diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 6b98fc8..042a8e9 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -9,11 +9,15 @@ - - - + + + + + + + @@ -204,7 +219,8 @@ - diff --git a/plugin.yml b/plugin.yml index 3fe45c1..b1fdc88 100644 --- a/plugin.yml +++ b/plugin.yml @@ -5,19 +5,23 @@ author: legan100 main: de.legan100.api.API commands: color: - farbe: - farben: + aliases: + - farbe + - farben rang: wartung: chat: discord: ts: - Teamspeak: + aliases: + - teamspeak regel: - regelwerk: - regeln: - apiver: + aliases: + - regelwerk + - regeln + - rules apiversion: + aliases: [apiver] gruss: msg: tell: @@ -37,4 +41,7 @@ commands: kreativ: adventure: uuid: - bcl: \ No newline at end of file + bcl: + globalrestart: + GetBackendConnection: + gbc: \ No newline at end of file diff --git a/src/de/legan100/api/API.java b/src/de/legan100/api/API.java index 57df488..2977c2c 100644 --- a/src/de/legan100/api/API.java +++ b/src/de/legan100/api/API.java @@ -12,13 +12,13 @@ public class API extends JavaPlugin { private static API instance; - private BackendClient backend; + private static BackendClient backend; public static API getInstance() { return instance; } - public BackendClient getBackend() { + public static BackendClient getBackend() { return backend; } @@ -41,18 +41,16 @@ public void onEnable() { @Override public void onDisable() { - + System.out.println("1"); if (backend != null) { - backend.send(""" - { - "type":"SERVER_STOP" - } - """); - - backend.disconnect(); + backend.send(""" + { + "type":"SERVER_STOP , + "server":"%s" + } + """.formatted(getServer().getName())); + backend.disconnect(); } - - MySQL.disconnect(); } public void register() { @@ -92,6 +90,9 @@ public void register() { getCommand("uuid").setExecutor(new CMD_uuid()); getCommand("bcl").setExecutor(new CMD_BCL()); getCommand("gm").setExecutor(new CMD_GM()); + getCommand("globalrestart").setExecutor(new CMD_globalrestart()); + getCommand("GetBackendConnection").setExecutor(new CMD_GetBackendConnection()); + getCommand("gbc").setExecutor(new CMD_gbc()); getServer().getPluginManager().registerEvents(new ChatListener(), this); getServer().getPluginManager().registerEvents(new JoinListener(), this); } diff --git a/src/de/legan100/api/commands/CMD_BCL.java b/src/de/legan100/api/commands/CMD_BCL.java index 64a8dff..d5468c7 100644 --- a/src/de/legan100/api/commands/CMD_BCL.java +++ b/src/de/legan100/api/commands/CMD_BCL.java @@ -14,7 +14,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String File messageDE = new File("plugins//API//message_de_DE.yml"); YamlConfiguration cfg1 = YamlConfiguration.loadConfiguration(messageDE); if (sender instanceof Player p) { - if (p.hasPermission("system.admin")) { + if (p.hasPermission("system.vorstand")) { if (args.length >= 1) { String bcMessage = ""; for (String arg : args) { diff --git a/src/de/legan100/api/commands/CMD_GetBackendConnection.java b/src/de/legan100/api/commands/CMD_GetBackendConnection.java new file mode 100644 index 0000000..5b654fc --- /dev/null +++ b/src/de/legan100/api/commands/CMD_GetBackendConnection.java @@ -0,0 +1,25 @@ +package de.legan100.api.commands; + +import de.legan100.api.API; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class CMD_GetBackendConnection implements CommandExecutor { + @Override + public boolean onCommand(CommandSender sender, Command cmd, @NotNull String s, @NotNull String @NotNull [] strings) { + if(sender instanceof Player p) { + if(p.hasPermission("system.vorstand")){ + if(API.getBackend().isConnected()){ + p.sendMessage("API is connected"); + }else { + p.sendMessage("API is disconnected"); + } + } + } + + return false; + } +} diff --git a/src/de/legan100/api/commands/CMD_gbc.java b/src/de/legan100/api/commands/CMD_gbc.java new file mode 100644 index 0000000..b6ef7da --- /dev/null +++ b/src/de/legan100/api/commands/CMD_gbc.java @@ -0,0 +1,41 @@ +package de.legan100.api.commands; + +import de.legan100.api.API; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; + +import java.io.File; + +public class CMD_gbc implements CommandExecutor { + @Override + public boolean onCommand(CommandSender sender, Command command, String s, String [] args) { + File messageDE = new File("plugins//API//message_de_DE.yml"); + YamlConfiguration cfg1 = YamlConfiguration.loadConfiguration(messageDE); + if(sender instanceof Player p ) { + if(p.hasPermission("system.vorstand")){ + if (args.length >= 1) { + String bcMessage = ""; + for (String arg : args) { + bcMessage = bcMessage + " " + arg; + } + if (bcMessage.contains("&")) { + bcMessage.replace("§", "&"); + } + p.getServer().broadcastMessage("§9-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"); + p.getServer().broadcastMessage(""); + p.getServer().broadcastMessage(bcMessage); + p.getServer().broadcastMessage(""); + p.getServer().broadcastMessage("§9-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"); + API.getBackend().send("bc_globalbroadcast_" + bcMessage); + } else { + p.sendMessage(cfg1.getString("message.prefix") + cfg1.getString("message.bcl.usage")); + } + } + } + + return false; + } +} diff --git a/src/de/legan100/api/commands/CMD_globalrestart.java b/src/de/legan100/api/commands/CMD_globalrestart.java new file mode 100644 index 0000000..fadb83d --- /dev/null +++ b/src/de/legan100/api/commands/CMD_globalrestart.java @@ -0,0 +1,21 @@ +package de.legan100.api.commands; + +import de.legan100.api.API; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class CMD_globalrestart implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String s, @NotNull String @NotNull [] strings) { + if(sender instanceof Player p) { + if(p.hasPermission("system.vorstand")){ + API.getBackend().send("bc_globalrestart"); + } + } + + return false; + } +} diff --git a/src/de/legan100/api/utils/BackendClient.java b/src/de/legan100/api/utils/BackendClient.java index d64bcfa..1672184 100644 --- a/src/de/legan100/api/utils/BackendClient.java +++ b/src/de/legan100/api/utils/BackendClient.java @@ -1,6 +1,8 @@ package de.legan100.api.utils; +import de.legan100.api.API; import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitTask; import java.io.*; import java.net.Socket; @@ -10,68 +12,69 @@ public class BackendClient { private static final String HOST = "127.0.0.1"; private static final int PORT = 10000; + private static final long RECONNECT_DELAY = 5000L; private Socket socket; private PrintWriter out; private BufferedReader in; - private final AtomicBoolean reconnecting = new AtomicBoolean(false); + private Thread listenerThread; + private Thread reconnectThread; + + private BukkitTask pingTask; + private final AtomicBoolean connected = new AtomicBoolean(false); + private final AtomicBoolean reconnecting = new AtomicBoolean(false); + private final AtomicBoolean shuttingDown = new AtomicBoolean(false); public void connect() { - try { - - socket = new Socket(HOST, PORT); - socket.setKeepAlive(true); - socket.setTcpNoDelay(true); + if (shuttingDown.get()) return; - out = new PrintWriter(socket.getOutputStream(), true); - in = new BufferedReader( - new InputStreamReader(socket.getInputStream())); + try { + openSocket(); connected.set(true); - - System.out.println("[BackendClient] Connected to backend"); - + System.out.println("[BackendClient] Connected"); startListener(); - startPingTask(); - - } catch (IOException e) { - + startPing(); + } catch (Exception e) { connected.set(false); - - System.err.println("[BackendClient] Connection failed"); reconnect(); } } - private void startListener() { + private void openSocket() throws IOException { + socket = new Socket(HOST, PORT); + socket.setKeepAlive(true); + socket.setTcpNoDelay(true); - Thread listenerThread = new Thread(() -> { + out = new PrintWriter(socket.getOutputStream(), true); + in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + } - try { + private void startListener() { + listenerThread = new Thread(() -> { + try { String line; - while (connected.get() - && socket != null - && !socket.isClosed() - && (line = in.readLine()) != null) { - - handleMessage(line); - } - - } catch (Exception e) { + while (!shuttingDown.get()) { - if (connected.get()) { - System.err.println("[BackendClient] Connection lost"); + try { + line = in.readLine(); + if (line == null) break; + } catch (Exception e) { + break; + } + handle(line); } } finally { - connected.set(false); - reconnect(); + if (!shuttingDown.get()) { + reconnect(); + } } }); @@ -81,61 +84,49 @@ private void startListener() { listenerThread.start(); } - private void handleMessage(String message) { - - if (message.equalsIgnoreCase("PONG")) { + private void handle(String msg) { + if ("PONG".equalsIgnoreCase(msg)) return; + if ("bc_globalrestart_allow".equalsIgnoreCase(msg)) { + API.getInstance().getServer().shutdown(); return; } - - System.out.println("[BACKEND] " + message); - + System.out.println("[BACKEND] " + msg); } - private void startPingTask() { - Bukkit.getScheduler().runTaskTimerAsynchronously(Bukkit.getPluginManager().getPlugin("API"), () -> { - if (!isConnected()) { - return; - } - send("PING"); - },20L * 30, 20L * 30); + private void startPing() { + if (pingTask != null) return; + + pingTask = Bukkit.getScheduler().runTaskTimerAsynchronously(API.getInstance(), () -> { + if (isConnected()) { + send("PING"); + }}, 20L * 30, 20L * 30); } private void reconnect() { + if (shuttingDown.get()) return; + if (!reconnecting.compareAndSet(false, true)) return; - if (!reconnecting.compareAndSet(false, true)) { - return; - } + reconnectThread = new Thread(() -> { + try { + while (!connected.get() && !shuttingDown.get()) { + try { + System.out.println("[BackendClient] Reconnecting..."); + closeSocketQuietly(); + openSocket(); + connected.set(true); + System.out.println("[BackendClient] Reconnected"); + startListener(); + return; + + } catch (Exception ignored) {} - Thread reconnectThread = new Thread(() -> { - while (!connected.get()) { - try { - System.out.println("[BackendClient] Reconnecting..."); - disconnectInternal(); - socket = new Socket(HOST, PORT); - socket.setKeepAlive(true); - socket.setTcpNoDelay(true); - out = new PrintWriter( - socket.getOutputStream(), - true - ); - in = new BufferedReader( - new InputStreamReader( - socket.getInputStream() - ) - ); - connected.set(true); - System.out.println("[BackendClient] Reconnected"); - startListener(); - reconnecting.set(false); - return; - - } catch (Exception ignored) {} - - try { - Thread.sleep(5000); - } catch (InterruptedException ignored) {} + try { + Thread.sleep(RECONNECT_DELAY); + } catch (InterruptedException ignored) {} + } + } finally { + reconnecting.set(false); } - reconnecting.set(false); }); reconnectThread.setName("Backend-Reconnect"); @@ -143,15 +134,18 @@ private void reconnect() { reconnectThread.start(); } - public void send(String message) { + public void send(String msg) { + if (!isConnected()) return; try { - if (!isConnected()) { - return; + out.println(msg); + if (out.checkError()) { + throw new IOException("Write failed"); } - out.println(message); } catch (Exception e) { connected.set(false); - reconnect(); + if (!shuttingDown.get()) { + reconnect(); + } } } @@ -160,27 +154,36 @@ public boolean isConnected() { } public void disconnect() { + shuttingDown.set(true); connected.set(false); - disconnectInternal(); + System.out.println("DISCONNECT START"); + if (pingTask != null) { + pingTask.cancel(); + pingTask = null; + } + closeSocketQuietly(); + if (listenerThread != null) { + listenerThread.interrupt(); + } + if (reconnectThread != null) { + reconnectThread.interrupt(); + } + System.out.println("DISCONNECT END"); } - - private void disconnectInternal() { + private void closeSocketQuietly() { try { - if (in != null) { - in.close(); + if (socket != null) { + socket.shutdownInput(); + socket.shutdownOutput(); } } catch (Exception ignored) {} - try { - if (out != null) { - out.close(); - } - } catch (Exception ignored) {} + try { if (in != null) in.close(); } catch (Exception ignored) {} + try { if (out != null) out.close(); } catch (Exception ignored) {} + try { if (socket != null) socket.close(); } catch (Exception ignored) {} - try { - if (socket != null) { - socket.close(); - } - } catch (Exception ignored) {} + in = null; + out = null; + socket = null; } } \ No newline at end of file From e3b9fee068c7122ea362d1bf617386d00e3bdb28 Mon Sep 17 00:00:00 2001 From: legan100 Date: Sun, 28 Jun 2026 22:32:54 +0200 Subject: [PATCH 3/3] chore: backup --- .idea/material_theme_project_new.xml | 10 ++ .idea/workspace.xml | 40 ++++-- plugin.yml | 3 +- src/de/legan100/api/API.java | 3 +- src/de/legan100/api/commands/CMD_APIver.java | 7 +- .../legan100/api/commands/CMD_Chatclear.java | 2 +- .../api/commands/CMD_backendrestart.java | 36 ++++++ ...{CMD_gbc.java => CMD_globalchatclear.java} | 15 +-- .../api/commands/CMD_globalrestart.java | 11 +- src/de/legan100/api/utils/BackendClient.java | 120 +++++++++++++----- 10 files changed, 191 insertions(+), 56 deletions(-) create mode 100644 .idea/material_theme_project_new.xml create mode 100644 src/de/legan100/api/commands/CMD_backendrestart.java rename src/de/legan100/api/commands/{CMD_gbc.java => CMD_globalchatclear.java} (67%) diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml new file mode 100644 index 0000000..780105b --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 042a8e9..a93cafe 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -9,14 +9,15 @@ - - - - + + - + + + + @@ -220,7 +243,8 @@ - diff --git a/plugin.yml b/plugin.yml index b1fdc88..500d80c 100644 --- a/plugin.yml +++ b/plugin.yml @@ -44,4 +44,5 @@ commands: bcl: globalrestart: GetBackendConnection: - gbc: \ No newline at end of file + gbc: + backendrestart: \ No newline at end of file diff --git a/src/de/legan100/api/API.java b/src/de/legan100/api/API.java index 2977c2c..6928bcb 100644 --- a/src/de/legan100/api/API.java +++ b/src/de/legan100/api/API.java @@ -92,7 +92,8 @@ public void register() { getCommand("gm").setExecutor(new CMD_GM()); getCommand("globalrestart").setExecutor(new CMD_globalrestart()); getCommand("GetBackendConnection").setExecutor(new CMD_GetBackendConnection()); - getCommand("gbc").setExecutor(new CMD_gbc()); + getCommand("gbc").setExecutor(new CMD_globalchatclear()); + getCommand("backendrestart").setExecutor(new CMD_backendrestart()); getServer().getPluginManager().registerEvents(new ChatListener(), this); getServer().getPluginManager().registerEvents(new JoinListener(), this); } diff --git a/src/de/legan100/api/commands/CMD_APIver.java b/src/de/legan100/api/commands/CMD_APIver.java index c1fb61e..5949a62 100644 --- a/src/de/legan100/api/commands/CMD_APIver.java +++ b/src/de/legan100/api/commands/CMD_APIver.java @@ -1,5 +1,6 @@ package de.legan100.api.commands; +import de.legan100.api.API; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -13,12 +14,12 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String File messageDE = new File("plugins//API//message_de_DE.yml"); YamlConfiguration cfg1 = YamlConfiguration.loadConfiguration(messageDE); if (sender instanceof Player p) { - if (p.hasPermission("system.admin")) - sender.sendMessage(cfg1.getString("message.prefix") + "Das Plugin ist in der Version 1.1"); + if (p.hasPermission("system.vorstand")) + sender.sendMessage(cfg1.getString("message.prefix") + "Das Plugin ist in der Version " + API.getInstance().getPluginMeta().getVersion()); else p.sendMessage(cfg1.getString("message.prefix") + cfg1.getString("message.noPerms")); } else { - sender.sendMessage(cfg1.getString("message.prefix") + "Das Plugin ist in der Version 1.1"); + sender.sendMessage(cfg1.getString("message.prefix") + "Das Plugin ist in der Version " + API.getInstance().getPluginMeta().getVersion()); } return true; } diff --git a/src/de/legan100/api/commands/CMD_Chatclear.java b/src/de/legan100/api/commands/CMD_Chatclear.java index b56db7e..c4bc6e9 100644 --- a/src/de/legan100/api/commands/CMD_Chatclear.java +++ b/src/de/legan100/api/commands/CMD_Chatclear.java @@ -16,7 +16,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String if (sender instanceof Player p) { if (p.hasPermission("System.Admin")||p.hasPermission("System.SrMod")){ for (Player players : Bukkit.getServer().getOnlinePlayers()) { - if (!players.hasPermission("system.vorstand")) { + if (players.hasPermission("system.default")||players.hasPermission("system.media")) { for (int i = 0; i < 150; i++) { players.sendMessage(" "); } diff --git a/src/de/legan100/api/commands/CMD_backendrestart.java b/src/de/legan100/api/commands/CMD_backendrestart.java new file mode 100644 index 0000000..c183469 --- /dev/null +++ b/src/de/legan100/api/commands/CMD_backendrestart.java @@ -0,0 +1,36 @@ +package de.legan100.api.commands; + +import de.legan100.api.API; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +public class CMD_backendrestart implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s, @NotNull String @NotNull [] args) { + File messageDE = new File("plugins//Backend//message_de_DE.yml"); + YamlConfiguration cfg1 = YamlConfiguration.loadConfiguration(messageDE); + if(sender instanceof Player p) { + if(p.hasPermission("backend.admin") ) { + if(args.length == 0) { + API.getBackend().send("bc_backendrestart"); + p.sendMessage(cfg1.getString("message.prefix") + cfg1.getString("message.backendrestart.send")); + + }else { + p.sendMessage(cfg1.getString("message.prefix") + cfg1.getString("message.backendrestart.usage")); + } + }else { + p.sendMessage(cfg1.getString("message.prefix") + cfg1.getString("message.noPerms")); + } + }else { + sender.sendMessage(cfg1.getString("message.prefix") + cfg1.getString("message.onlyPlayerAllowed")); + } + + return false; + } +} diff --git a/src/de/legan100/api/commands/CMD_gbc.java b/src/de/legan100/api/commands/CMD_globalchatclear.java similarity index 67% rename from src/de/legan100/api/commands/CMD_gbc.java rename to src/de/legan100/api/commands/CMD_globalchatclear.java index b6ef7da..965c92b 100644 --- a/src/de/legan100/api/commands/CMD_gbc.java +++ b/src/de/legan100/api/commands/CMD_globalchatclear.java @@ -9,13 +9,13 @@ import java.io.File; -public class CMD_gbc implements CommandExecutor { +public class CMD_globalchatclear implements CommandExecutor { @Override public boolean onCommand(CommandSender sender, Command command, String s, String [] args) { - File messageDE = new File("plugins//API//message_de_DE.yml"); + File messageDE = new File("plugins//Backend//message_de_DE.yml"); YamlConfiguration cfg1 = YamlConfiguration.loadConfiguration(messageDE); if(sender instanceof Player p ) { - if(p.hasPermission("system.vorstand")){ + if(p.hasPermission("backend.admin")){ if (args.length >= 1) { String bcMessage = ""; for (String arg : args) { @@ -24,16 +24,15 @@ public boolean onCommand(CommandSender sender, Command command, String s, Stri if (bcMessage.contains("&")) { bcMessage.replace("§", "&"); } - p.getServer().broadcastMessage("§9-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"); - p.getServer().broadcastMessage(""); - p.getServer().broadcastMessage(bcMessage); - p.getServer().broadcastMessage(""); - p.getServer().broadcastMessage("§9-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"); API.getBackend().send("bc_globalbroadcast_" + bcMessage); } else { p.sendMessage(cfg1.getString("message.prefix") + cfg1.getString("message.bcl.usage")); } + }else { + p.sendMessage(cfg1.getString("message.prefix") + cfg1.getString("message.noPerms")); } + }else { + sender.sendMessage(cfg1.getString("message.prefix") + cfg1.getString("message.onlyPlayerAllowed")); } return false; diff --git a/src/de/legan100/api/commands/CMD_globalrestart.java b/src/de/legan100/api/commands/CMD_globalrestart.java index fadb83d..c5170dc 100644 --- a/src/de/legan100/api/commands/CMD_globalrestart.java +++ b/src/de/legan100/api/commands/CMD_globalrestart.java @@ -4,16 +4,25 @@ import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import java.io.File; + public class CMD_globalrestart implements CommandExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String s, @NotNull String @NotNull [] strings) { + File messageDE = new File("plugins//Backend//message_de_DE.yml"); + YamlConfiguration cfg1 = YamlConfiguration.loadConfiguration(messageDE); if(sender instanceof Player p) { - if(p.hasPermission("system.vorstand")){ + if(p.hasPermission("backend.admin")){ API.getBackend().send("bc_globalrestart"); + }else { + p.sendMessage(cfg1.getString("message.prefix") + cfg1.getString("message.noPerms")); } + }else { + sender.sendMessage(cfg1.getString("message.prefix") + cfg1.getString("message.onlyPlayerAllowed")); } return false; diff --git a/src/de/legan100/api/utils/BackendClient.java b/src/de/legan100/api/utils/BackendClient.java index 1672184..c1caf7d 100644 --- a/src/de/legan100/api/utils/BackendClient.java +++ b/src/de/legan100/api/utils/BackendClient.java @@ -2,17 +2,19 @@ import de.legan100.api.API; import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; import java.io.*; import java.net.Socket; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.*; public class BackendClient { private static final String HOST = "127.0.0.1"; private static final int PORT = 10000; private static final long RECONNECT_DELAY = 5000L; + private static final int MAX_RECONNECT_ATTEMPTS = 3; private Socket socket; private PrintWriter out; @@ -27,17 +29,22 @@ public class BackendClient { private final AtomicBoolean reconnecting = new AtomicBoolean(false); private final AtomicBoolean shuttingDown = new AtomicBoolean(false); + private final AtomicInteger reconnectAttempts = new AtomicInteger(0); + public void connect() { if (shuttingDown.get()) return; - try { openSocket(); - connected.set(true); + reconnectAttempts.set(0); + for (Player player : Bukkit.getOnlinePlayers()) { + if (player.hasPermission("backend.admin")) { + player.sendMessage("[BackendClient] Connected"); + } + } System.out.println("[BackendClient] Connected"); startListener(); - startPing(); } catch (Exception e) { connected.set(false); reconnect(); @@ -48,81 +55,101 @@ private void openSocket() throws IOException { socket = new Socket(HOST, PORT); socket.setKeepAlive(true); socket.setTcpNoDelay(true); - out = new PrintWriter(socket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); } private void startListener() { listenerThread = new Thread(() -> { - try { String line; - while (!shuttingDown.get()) { - try { line = in.readLine(); - if (line == null) break; + if (line == null) { + break; + } } catch (Exception e) { break; } handle(line); } - } finally { connected.set(false); if (!shuttingDown.get()) { reconnect(); } } - }); - listenerThread.setName("Backend-Listener"); listenerThread.setDaemon(true); listenerThread.start(); } private void handle(String msg) { - if ("PONG".equalsIgnoreCase(msg)) return; if ("bc_globalrestart_allow".equalsIgnoreCase(msg)) { API.getInstance().getServer().shutdown(); - return; + } else if (msg.startsWith("gbc_")) { + String zweiterString = ""; + for (int x = 0; x < msg.length(); x++) { + if (msg.charAt(x) == '_') { + zweiterString = msg.substring(x + 1); + break; + } + } + API.getInstance().getServer().broadcastMessage("§9-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"); + API.getInstance().getServer().broadcastMessage(""); + API.getInstance().getServer().broadcastMessage(zweiterString); + API.getInstance().getServer().broadcastMessage(""); + API.getInstance().getServer().broadcastMessage("§9-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"); + } else if (msg.startsWith("bc_backendrestart")) { + for (Player player : Bukkit.getOnlinePlayers()) { + if (player.hasPermission("backend.admin")) { + player.sendMessage("Backendrestart"); + } + } } - System.out.println("[BACKEND] " + msg); - } - - private void startPing() { - if (pingTask != null) return; - pingTask = Bukkit.getScheduler().runTaskTimerAsynchronously(API.getInstance(), () -> { - if (isConnected()) { - send("PING"); - }}, 20L * 30, 20L * 30); + System.out.println("[BACKEND] " + msg); } private void reconnect() { if (shuttingDown.get()) return; - if (!reconnecting.compareAndSet(false, true)) return; + if (!reconnecting.compareAndSet(false, true)) { + return; + } reconnectThread = new Thread(() -> { try { while (!connected.get() && !shuttingDown.get()) { + int attempt = reconnectAttempts.incrementAndGet(); try { - System.out.println("[BackendClient] Reconnecting..."); + System.out.println("[BackendClient] Reconnect attempt " + attempt + "/" + MAX_RECONNECT_ATTEMPTS); closeSocketQuietly(); openSocket(); connected.set(true); + reconnectAttempts.set(0); + for (Player player : Bukkit.getOnlinePlayers()) { + if (player.hasPermission("backend.admin")) { + player.sendMessage("Backend connected"); + } + } System.out.println("[BackendClient] Reconnected"); startListener(); + send("statsport_" + API.getInstance().getServer().getPort()); return; - - } catch (Exception ignored) {} - + } catch (Exception ignored) { + if (attempt >= MAX_RECONNECT_ATTEMPTS) { + Bukkit.getLogger().severe("[BackendClient] Backend unreachable after " + MAX_RECONNECT_ATTEMPTS + " reconnect attempts. Shutting down server."); + Bukkit.getScheduler().runTask(API.getInstance(), Bukkit::shutdown); + return; + } + } try { Thread.sleep(RECONNECT_DELAY); - } catch (InterruptedException ignored) {} + } catch (InterruptedException ignored) { + return; + } } } finally { reconnecting.set(false); @@ -135,7 +162,10 @@ private void reconnect() { } public void send(String msg) { - if (!isConnected()) return; + + if (!isConnected()) { + return; + } try { out.println(msg); if (out.checkError()) { @@ -157,6 +187,11 @@ public void disconnect() { shuttingDown.set(true); connected.set(false); System.out.println("DISCONNECT START"); + for (Player player : Bukkit.getOnlinePlayers()) { + if (player.hasPermission("backend.admin")) { + player.sendMessage("DISCONNECT START"); + } + } if (pingTask != null) { pingTask.cancel(); pingTask = null; @@ -169,7 +204,13 @@ public void disconnect() { reconnectThread.interrupt(); } System.out.println("DISCONNECT END"); + for (Player player : Bukkit.getOnlinePlayers()) { + if (player.hasPermission("backend.admin")) { + player.sendMessage("DISCONNECT END"); + } + } } + private void closeSocketQuietly() { try { if (socket != null) { @@ -178,9 +219,22 @@ private void closeSocketQuietly() { } } catch (Exception ignored) {} - try { if (in != null) in.close(); } catch (Exception ignored) {} - try { if (out != null) out.close(); } catch (Exception ignored) {} - try { if (socket != null) socket.close(); } catch (Exception ignored) {} + try { + if (in != null) { + in.close(); + } + } catch (Exception ignored) {} + try { + if (out != null) { + out.close(); + } + } catch (Exception ignored) {} + + try { + if (socket != null) { + socket.close(); + } + } catch (Exception ignored) {} in = null; out = null;