From 44846d9b4fb3af9ac9151b9f0848bac7d8c64bb1 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 16 Aug 2024 13:53:18 +0200 Subject: [PATCH] Add Howto+server icon template --- HowTo_Add MC Server.md | 274 +++++++++++++++++++++++++++++++++++++++++ server_icon.xcf | Bin 0 -> 14563 bytes 2 files changed, 274 insertions(+) create mode 100644 HowTo_Add MC Server.md create mode 100644 server_icon.xcf diff --git a/HowTo_Add MC Server.md b/HowTo_Add MC Server.md new file mode 100644 index 0000000..253f1df --- /dev/null +++ b/HowTo_Add MC Server.md @@ -0,0 +1,274 @@ +# Anleitung: Minecraft-Server auf einem NUC-GameServer einrichten + +Diese Anleitung führt dich Schritt für Schritt durch den Prozess der Einrichtung eines Minecraft-Servers auf dem NUC-GameServer. +Bei fragen gerne immer Alex oder jemand anderen Admin-fähiges fragen. + +--- + +## Schritt 1: Entscheiden, welchen Server man aufbauen will + +Bevor du loslegst, musst du entscheiden, ob du einen **Vanilla-Server** (unmodifizierte Version) oder einen **modded Server** (mit Modifikationen) einrichten möchtest. + +- **Beispiel:** Du möchtest das Modpack **Farming Valley** einrichten. + +> **Tipp:** Vanilla-Server eignen sich für einfache Multiplayer-Erlebnisse ohne zusätzliche Modifikationen, während modded Server eine Vielzahl von neuen Funktionen und Inhalten bieten. + +>> **Hinweis:** Zurzeit (08/2024) ist nur ein Vanilla Minecraft 1.21 aktiv und unter der Adresse "minecraft-vanilla.iamsander.de" erreichbar. + +--- + +## Schritt 2: Server-Dateien für das gewählte Modpack finden + +Die Server-Dateien für dein Modpack müssen ausfindig gemacht werden. In vielen Fällen sind diese als seperater Download auf Plattformen wie CurseForge oder Technic Modpacks zu finden. +Üblicherweise beinhalten diese mindestens eine .jar Datei und ein server.properties Datei. + +- **Beispiel:** Die Dateien für Farming Valley findest du auf **CurseForge**. + +> **Hinweis:** Stelle sicher, dass du die richtige Version des Modpacks auf der Client-Seite (deinem Rechner) herunterlädst, die mit deinem Minecraft-Server kompatibel ist. Sonst werden dir Fehler im Multiplayer Menu angezeigt und gegebenenfalls das Betreten des Servers nicht erlaubt. + +--- + +## Schritt 3: Entpacken der Server-Dateien in den NUC-GameServers Ordner + +Nachdem du die Server-Dateien heruntergeladen hast, müssen diese in den richtigen Ordner auf deinem NUC-GameServer entpackt werden. + +- **Beispiel:** Entpacke die Dateien in den folgenden Pfad: + ```plaintext + C:\Users\4lexK\Desktop\GameServers\Minecraft + +> ***Hinweis***: Zurzeit (08/2024) sind folgende Server aktiv: +> - Minecraft Vanilla 1.21 +-> minecraft-vanilla.iamsander.de +> - The 1.12.2 Pack 1.6.3 (SanderPack) +-> mc-sanderpack.iamsander.de +> - GT New Horizons 2.6.0 (SanderHorizons) +-> mc-sanderhorizons.iamsander.de +> - RLCraft 2.9.3 (SanderHardcore) +-> mc-sanderhardcore.iamsander.de +> - Farming Valley 1.1.2 (SanderValley) +-> mc-sandervalley.iamsander.de + +## Schritt 4: Validieren und Konfigurieren der Serverdaten. + +Beispiel: +In jedem Server-Ordner mussen folgende Elemente enthalten sein: +- config Ordner +- libraries Ordner +- mods Ordner (falls modded) +- resources Ordner +- scripts Ordner +- minecraft server jar File der jeweiligen Basis Minecraft Version +- modloader jar File kompatibel mit der Minecraft version +(üblicherweise im Modpack-Ordner enthalten. Kann online geprüft werden, welche notwendig ist) +- server.json File +- options.txt +- (optional) Ein 64x64 server-icon.png File (für das Icon im Multiplayer Menü) + +Zunächst muss der Server einmal initial gestartet werden um die eula.txt erzeugen zu lassen. Dafür einmal entweder die Minecraft[...].jar (bei Vanilla) oder die Forge[...].jar (bei modded) regulär ausführen. Der Server fährt dann hoch und bricht dann nach erzeugen der eula.txt ab. Diese muss geöffnet und der False wert auf True geändert werden um die Eula zu akzeptieren. + +Im Anschluss muss die server.properties Datei mit einem Texteditor angepasst werden. Viele der Parameter hier sind geschmackssache und können bei Bedarf und interesse recherchiert und geändert werden. +Die wichtigsten drei Einstellungen sind +1. Die "level"-Parameter: +- level-name=[NameDerWelt z.b. SanderPack] +- level-seed=[EineZahl die den Startwert der Generierung bestimmt z.b. 08062021] +- level-type=[Typ der Welt z.b. BIOMESOP für Biomes O Plenty oder DEFAULT für reguläres Survival] +2. motd: +Dieser stellt die Welt-Beschreibung dar, welche im Multiplayer Menu unter dem Icon und dem Namen angezeigt wird. +3. Die "server"-Parameter: +- server-ip=[üblicherweise die IP mit der die Welt erreichbar ist; sollte stehts leer sein damit die Host-Maschinen IP gewählt wird] +- server-port=[Der Port auf der Maschine auf dem gehostet wird. Default 25565. Beim Betreiben mehrerer Server müssen die Ports jeweils umgeändert werden, da immer nur ein Port gleichzeitig verwendet werden kann] + +## Step 5: Anbinden an Nuc Morroc Telegram Bot. + +Wir haben einen Telegram-Bot, welcher das Ansteuern und Verwalten der GameServer übernimmt. +Der Bot ist unter folgendem Username zu erreichen. + +@sander_nuc_morroc_bot + +Bei erstem Kontakt (oder dem /start Befehl) wird man nach einem Passwort gefragt. +Dieses lautet: +29102021 + +Um die Funktionen und den Menu-Eintrag beim Bot korrekt einzufügen muss man eine Anpassung an unserem Osiris_listener Git-Repo (https://sandergit.iamsander.de/Alex/osiris_listener). + +Hier gibt es das Skript osiris_listener_telegram.py + +In diesem Skript müssen folgende Anpassungen gemacht werden: + +1. Neues GameServer Profil hinzufügen + +``` python +gaming_server_profiles = { + # Minecraft + "mc_vanilla" : { + 'profile_id': 'vanilla', + 'server_name': 'Vanilla 1.21', + 'directory': 'C:/Users/4lexK/Desktop/GameServers/Minecraft/Vanilla_1-21/', + 'command': ['C:/Program Files/Java/jdk-22/bin/java.exe', '-Xmx1024M', '-Xms1024M', '-jar', 'minecraft_server.1.21.jar', '--nogui', '--bonusChest'], + 'wait_time': 30 + }, +``` +Hierbei gelten folgende Regeln: +- profile_id -> Wird genutzt in diversen Mechaniken +- server_name -> Wird genutzt in Status-Nachrichten +- directory -> Zeigt immer auf den Root-Ordner des Servers +- command -> Liste aus Command und Parametern (siehe etwaige Launch-Skripte oder auf der Seite des Server-File Providers welche Params empfohlen werden) +- wait_time -> Rudimentäre Schätzung wie lange das Skript warten soll wenn ein Server seinen SIGINT (CTRL-C) erhalten hat und sich vollständig heruntergefahren hat + + +> Beispiel: +Falls beim Server-Zip ein Launchskript (.bat oder .sh File) enthalten ist, kann das direkt benutzt werden um start-Parameter für diese Zeilen zu extrahieren. + +2. Hinzufügen von einem Untermenü für den Telegram Bot + +Hierzu kann an den restlichen nested Menüs nach Beispielen für Optionen gesucht werden. +``` python +#### +# Nested Menu Bäume +#### +main_menu = [ + [ + {"text": "Tool Commands", "callback_data": "tools"}, + ], + [ + {"text": "Game Server", "callback_data": "game_servers"} + + ] + # Add neue Hauptmenu Elemente hier +] + +tools_menu = [ + [ + {"text": "<- Zurück", "callback_data": "nuc_back"} + ], + [ + {"text": "Status", "callback_data": "nuc_satus"}, + {"text": "Shutdown", "callback_data": "nuc_shutdown"}, + ] + # Add neue Tool Commands here +] +``` + +Hierbei gilt: +Jedes Menü (z.b. tools_menu) enthält Listen von Buttons mit Daten. Diese Daten enthalten immer "text" -> Der Text im Button und "callback_data" -> eine ID zur Verarbeitung der Logik. + +3. In der Funktion handle_callback werden die callback_data IDs verarbeitet: +``` python +async def handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: + query = update.callback_query + await query.answer() + await start_timer(context, query.message.chat_id) + data = query.data + + match data: + # Main + case "tools": + await query.message.reply_text("Wähle eine Tool Funktion:", reply_markup=InlineKeyboardMarkup(tools_menu)) + case "game_servers": + await query.message.reply_text("Wähle einen Gameserver Typ:", reply_markup=InlineKeyboardMarkup(gameserver_menu)) + # Tools + case "nuc_satus": + status = get_status_nuc() + await query.message.reply_text(f"Nuc Morroc Status (Auslastungen) \nCPU:{status["cpu"]}\nRAM:{status["ram"]}") + case "nuc_shutdown": + logging.info("Received request to shutdown.") + try: + os.system("shutdown /s /t 1") + await query.message.reply_text(f"Nuc Morroc wird heruntergefahren") + except Exception as exc: + logging.error(f"Error executing shutdown command: {exc}") + await query.message.reply_text(f"Fehler beim herunterfahren des Nuc Morroc.") +[...] + # MC Sanderpack (The 1.12.2 Pack) + case "mc_sanderpack_start": + msg = start_gameserver("mc_sanderpack") + await query.message.reply_text(f"{msg}") + case "mc_sanderpack_stop": + msg = stop_gameserver("mc_sanderpack") + await query.message.reply_text(f"{msg}") + case "mc_sanderpack_back": + await query.message.reply_text("Wähle einen Minecraft Server:", + reply_markup = InlineKeyboardMarkup(minecraft_menu)) +[...] +``` +Zu beachten ist, dass jede Message awaited werden muss. + + +## Step 6 Testen + +Hierbei werden die neuen Infos getestet (via Code und via Bot) um sicher zu stellen, dass alles mit Rechten Dingen zugeht. + +> **Notiz**: +Nie eine Funktion/Button einbauen der Pauschal alle GameServer / große Mengen der Server Started. Der Rechner wird mit ziemlicher Sicherheit in die Knie gehen. + +## Zusatzinfos +### Setzen von Admins (OPs) +In jedem Server-Root Ordner sollte eine Datei Namens "ops.json" enthalten sein (spätestens nach erstem hochfahren des Servers). +In dieser Datei werden alle Admins (OPs) und weitere Nutzer mit erhöhten Rechten eingetragen. +Hier ein Beispiel: +``` json +[ + { + "uuid": "4363e821-880d-4950-b492-b27682aa0202", + "name": "4lexKidd", + "level": 3, + "bypassesPlayerLimit": false + }, + { + "uuid": "f867bc59-62b2-4019-9b9a-8a0216bef6e2", + "name": "F0xy_Br0wn", + "level": 3, + "bypassesPlayerLimit": false + } +] +``` + +Erläuterungen: +- uuid: Kann extrahiert werden aus der Datei "usercache.json". Nachdem ein Spieler sich zum ersten Mal einloggt wird diese uuid dort eingetragen. Diese ist einzigartig für jeden Spieler und immer gleich(Kann von anderen Server Konfigs kopiert werden). +- name: Ist der Spieler Name +- level: Ist das Rechte Level (0 = Rechteloser Spieler bis 3 = Voll-Rechte Admin) +- bypassesPlayerLimit: Boolscher Wert der bestimmt, ob ein Spieler immer Zugang erhalten soll egal ob das Spieler Limit des Servers erreicht ist. Bei True darf der Spieler immer auf den Server. + +Falls interesse besteht mehr rechte einzuräumen (gerade uns Sanders, falls wir mit Gästen spielen), sollten diese Einträge gemacht werden und unsere Accounts höhere Rechte erhalten. + +### Setzen von Whitelist-Spielern +Falls bemerkt wird, dass zu viele aussenstehende sich auf dem Server herumtreiben und man wieder nur eine ausgewählte Menge Spieler erlauben will, kann man eine Whitelist aktivieren. + +In jedem Server-Root Ordner gibt es dafür eine whitelist.json. +Diese wird ähnlich der OP-Liste gepflegt: + +``` json +[ + { + "uuid": "4363e821-880d-4950-b492-b27682aa0202", + "name": "4lexKidd", + "level": 3, + "bypassesPlayerLimit": false + }, + { + "uuid": "f867bc59-62b2-4019-9b9a-8a0216bef6e2", + "name": "F0xy_Br0wn", + "level": 3, + "bypassesPlayerLimit": false + } +] +``` + +Zusätzlich zu den Usern muss im server.properties die Konfiguration +``` json +white-list=false +``` +auf true gesetzt werden, damit die whitelist angewendet wird und jeder auto-geblockt wird, der nicht darauf steht. + +### Einzelne Mod-Konfigurationen + +Im Server-Root Ordner müsste ein "Config" Ordner enthalten sein. Hier sind Konfigurationsdateien zu jedem Mod seperat enthalten. +In diesen sind üblicherweise ein bzw. mehrere .cfg Dateien enthalten. Diese können fein-getuned werden aber vorsicht, man sollte sich im klaren sein was man tut weil man an vielen stellen verherende Balancing Probleme inkludieren kann. +Üblicherweise sind Modpacks in dieser Hinsicht gut gebalanced und benötigen keine einzel Mod-Anpassungen mehr. + +### Eigenes Custom Server-Icon für das Multiplayer-Menu bauen. + +Damit das Icon korrekt geladen werden kann, darf es die Größe 64 x 64 nicht überschreiten. + +Zur Vereinfachung liegt beim osiris-listener Repo eine Gimp-Arbeitsvorlage ("server_icon.xcf") bei. +Nach Bearbeitung muss das Icon nur als server_icon.png exportiert und in den gewünschten Ordner gepackt werden. Der Serverstart wird das neue Icon automatisch erkennen und versuchen es zu laden. \ No newline at end of file diff --git a/server_icon.xcf b/server_icon.xcf new file mode 100644 index 0000000000000000000000000000000000000000..aeaf843c417e197d597f6c9c398e4062bce70262 GIT binary patch literal 14563 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 Wt`!Th!KX2A2Jle}90VN@p#KGg-yg{U literal 0 HcmV?d00001