Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import os
- import subprocess
- import requests
- import json
- import time
- import sys
- # --- Server Configuration ---
- SERVER_DIRECTORY = "minecraft_server"
- SERVER_JAR_NAME = "paper.jar"
- GEYSER_JAR_NAME = "Geyser-Spigot.jar"
- SERVER_MEMORY_MB = 4096
- SESSION_NAME = "mc_server"
- # --- API URLs for Updates ---
- PAPER_API_URL = "https://api.papermc.io/v2/projects/paper"
- GEYSER_API_URL = "https://ci.geysermc.org/job/Geyser-Spigot/lastSuccessfulBuild/api/json"
- # --- Color Definitions ---
- COLORS = {
- "red": "\033[31m", "green": "\033[32m", "yellow": "\033[33m", "blue": "\033[34m",
- "magenta": "\033[35m", "cyan": "\033[36m", "bright_blue": "\033[94m",
- "bright_green": "\033[92m", "bright_magenta": "\033[95m", "bright_yellow": "\033[93m",
- "end": "\033[0m", "bold": "\033[1m",
- }
- RAINBOW_COLORS = [
- COLORS["red"], COLORS["yellow"], COLORS["green"], COLORS["cyan"], COLORS["blue"], COLORS["magenta"]
- ]
- def rainbow_text(text):
- output = ""
- for i, char in enumerate(text):
- output += RAINBOW_COLORS[i % len(RAINBOW_COLORS)] + char
- output += COLORS["end"]
- print(output)
- def clear_screen():
- os.system('cls' if os.name == 'nt' else 'clear')
- def print_header():
- clear_screen()
- rainbow_text("======================================================")
- rainbow_text("== Unified Minecraft Server Manager (Java+Bedrock) ==")
- rainbow_text("== MIT Programming Class ==")
- rainbow_text("======================================================")
- print("")
- def download_file(url, filename):
- print(f"{COLORS['yellow']}Downloading {os.path.basename(filename)}...{COLORS['end']}")
- try:
- with requests.get(url, stream=True) as r:
- r.raise_for_status()
- total_size = int(r.headers.get('content-length', 0))
- block_size = 8192
- with open(filename, 'wb') as f:
- downloaded = 0
- for chunk in r.iter_content(chunk_size=block_size):
- f.write(chunk)
- downloaded += len(chunk)
- done = int(50 * downloaded / total_size) if total_size > 0 else 0
- sys.stdout.write(f"\r[{'=' * done}{' ' * (50-done)}] {downloaded / (1024*1024):.2f} MB")
- sys.stdout.flush()
- print(f"\n{COLORS['green']}Download complete!{COLORS['end']}")
- return True
- except requests.exceptions.RequestException as e:
- print(f"\n{COLORS['red']}Error downloading file: {e}{COLORS['end']}")
- return False
- def update_server():
- print_header()
- print(f"{COLORS['cyan']}Checking for updates...{COLORS['end']}")
- os.makedirs(SERVER_DIRECTORY, exist_ok=True)
- try:
- print(f"\n{COLORS['bright_blue']}--- Updating Paper Server ---{COLORS['end']}")
- versions_res = requests.get(PAPER_API_URL).json()
- latest_version = versions_res['versions'][-1]
- builds_res = requests.get(f"{PAPER_API_URL}/versions/{latest_version}/builds").json()
- latest_build = builds_res['builds'][-1]
- build_number = latest_build['build']
- jar_name = latest_build['downloads']['application']['name']
- download_url = f"{PAPER_API_URL}/versions/{latest_version}/builds/{build_number}/downloads/{jar_name}"
- download_file(download_url, os.path.join(SERVER_DIRECTORY, SERVER_JAR_NAME))
- except Exception as e:
- print(f"{COLORS['red']}Could not update Paper: {e}{COLORS['end']}")
- try:
- print(f"\n{COLORS['bright_green']}--- Updating Geyser Proxy ---{COLORS['end']}")
- geyser_res = requests.get(GEYSER_API_URL).json()
- artifact = geyser_res['artifacts'][0]
- download_url = f"{geyser_res['url']}artifact/{artifact['relativePath']}"
- plugins_dir = os.path.join(SERVER_DIRECTORY, "plugins")
- os.makedirs(plugins_dir, exist_ok=True)
- download_file(download_url, os.path.join(plugins_dir, GEYSER_JAR_NAME))
- except Exception as e:
- print(f"{COLORS['red']}Could not update Geyser: {e}{COLORS['end']}")
- input(f"\n{COLORS['bold']}Updates complete. Press Enter to return...{COLORS['end']}")
- def initial_setup():
- print_header()
- print(f"{COLORS['yellow']}Performing first-time setup...{COLORS['end']}")
- update_server()
- print(f"\n{COLORS['red']}{COLORS['bold']}You must agree to the Minecraft EULA.{COLORS['end']}")
- try:
- print(f"{COLORS['cyan']}Running server once to generate configuration files...{COLORS['end']}")
- java_command = f"java -Xms1024M -Xmx1024M -jar {SERVER_JAR_NAME} --nogui"
- subprocess.run(java_command, shell=True, cwd=SERVER_DIRECTORY, check=False, timeout=60, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
- except subprocess.TimeoutExpired:
- print("Server generated files and timed out (this is expected for setup).")
- except Exception as e:
- print(f"{COLORS['red']}An error occurred: {e}{COLORS['end']}")
- try:
- with open(os.path.join(SERVER_DIRECTORY, "eula.txt"), "w") as f:
- f.write("eula=true\n")
- print(f"{COLORS['green']}EULA accepted. 'eula.txt' created.{COLORS['end']}")
- except Exception as e:
- print(f"{COLORS['red']}Could not write eula.txt: {e}{COLORS['end']}")
- input(f"\n{COLORS['bold']}Initial setup complete. Please use the menu to enable Bedrock support. Press Enter...{COLORS['end']}")
- def enable_floodgate():
- """Modifies the geyser config to allow bedrock accounts."""
- print_header()
- print(f"{COLORS['bright_yellow']}--- Enabling Bedrock Support (Floodgate) ---{COLORS['end']}")
- geyser_config_path = os.path.join(SERVER_DIRECTORY, "plugins", "Geyser-Spigot", "config.yml")
- if not os.path.exists(geyser_config_path):
- print(f"{COLORS['red']}Error: Geyser config not found!{COLORS['end']}")
- print(f"Please run the server at least ONCE to generate the file '{geyser_config_path}'")
- input(f"\n{COLORS['bold']}Press Enter to return...{COLORS['end']}")
- return
- try:
- with open(geyser_config_path, 'r') as f:
- lines = f.readlines()
- new_lines = []
- changed = False
- for line in lines:
- if line.strip().startswith("auth-type:"):
- if "floodgate" in line:
- print(f"{COLORS['green']}Bedrock support is already enabled (auth-type is 'floodgate').{COLORS['end']}")
- input(f"\n{COLORS['bold']}Press Enter to return...{COLORS['end']}")
- return
- new_lines.append(line.replace("online", "floodgate"))
- changed = True
- else:
- new_lines.append(line)
- if changed:
- with open(geyser_config_path, 'w') as f:
- f.writelines(new_lines)
- print(f"{COLORS['green']}Successfully updated Geyser 'config.yml' for Bedrock support.{COLORS['end']}")
- else:
- print(f"{COLORS['yellow']}Could not find 'auth-type' setting. It might have already been changed.{COLORS['end']}")
- except Exception as e:
- print(f"{COLORS['red']}An error occurred while modifying the config file: {e}{COLORS['end']}")
- input(f"\n{COLORS['bold']}Press Enter to return...{COLORS['end']}")
- def is_server_running():
- result = subprocess.run(f"screen -ls | grep -q '\\.{SESSION_NAME}\\s'", shell=True)
- return result.returncode == 0
- def start_server():
- print_header()
- if is_server_running():
- print(f"{COLORS['yellow']}Server is already running!{COLORS['end']}")
- print(f"To connect to its console, type: {COLORS['cyan']}screen -r {SESSION_NAME}{COLORS['end']}")
- else:
- print(f"{COLORS['green']}Starting server...{COLORS['end']}")
- if not os.path.exists(os.path.join(SERVER_DIRECTORY, SERVER_JAR_NAME)):
- print(f"{COLORS['red']}Server JAR not found! Run setup/update first.{COLORS['end']}")
- input(f"\n{COLORS['bold']}Press Enter...{COLORS['end']}")
- return
- java_command = f"java -Xms{SERVER_MEMORY_MB}M -Xmx{SERVER_MEMORY_MB}M -jar {SERVER_JAR_NAME} --nogui"
- screen_command = f"screen -dmS {SESSION_NAME} {java_command}"
- subprocess.run(screen_command, shell=True, cwd=SERVER_DIRECTORY)
- print(f"Server starting in screen session '{COLORS['cyan']}{SESSION_NAME}{COLORS['end']}'.")
- input(f"\n{COLORS['bold']}Press Enter to return...{COLORS['end']}")
- def stop_server():
- print_header()
- if not is_server_running():
- print(f"{COLORS['yellow']}Server is not currently running.{COLORS['end']}")
- else:
- print(f"{COLORS['red']}Stopping server gracefully...{COLORS['end']}")
- subprocess.run(f"screen -S {SESSION_NAME} -X stuff 'stop\n'", shell=True)
- input(f"\n{COLORS['bold']}Press Enter to return...{COLORS['end']}")
- def open_console():
- if not is_server_running():
- print_header()
- print(f"{COLORS['yellow']}Server is not running.{COLORS['end']}")
- input(f"\n{COLORS['bold']}Press Enter to return...{COLORS['end']}")
- else:
- print(f"{COLORS['green']}Attaching to console... Press {COLORS['bold']}CTRL+A, then D{COLORS['end']}{COLORS['green']} to detach.{COLORS['end']}")
- time.sleep(3)
- os.system(f"screen -r {SESSION_NAME}")
- def main_menu():
- while True:
- print_header()
- status = f"{COLORS['green']}ONLINE{COLORS['end']}" if is_server_running() else f"{COLORS['red']}OFFLINE{COLORS['end']}"
- print(f"Server Status: {status}\n")
- print(f"{COLORS['bright_yellow']}--- Main Menu ---{COLORS['end']}")
- print(f"1. Start Server")
- print(f"2. Stop Server")
- print(f"3. Open Server Console")
- print(f"\n{COLORS['bright_magenta']}--- Maintenance ---{COLORS['end']}")
- print(f"4. Update Server (Paper & Geyser)")
- print(f"5. Enable Bedrock Support (Floodgate)")
- print(f"6. Perform First-Time Setup")
- print(f"\n{COLORS['red']}7. Exit{COLORS['end']}")
- choice = input(f"\n{COLORS['bold']}Enter your choice [1-7]: {COLORS['end']}")
- if choice == '1': start_server()
- elif choice == '2': stop_server()
- elif choice == '3': open_console()
- elif choice == '4': update_server()
- elif choice == '5': enable_floodgate()
- elif choice == '6': initial_setup()
- elif choice == '7':
- print(f"\n{COLORS['green']}Goodbye!{COLORS['end']}")
- break
- else:
- print(f"\n{COLORS['red']}Invalid choice.{COLORS['end']}"); time.sleep(1)
- if __name__ == "__main__":
- if not os.path.isdir(SERVER_DIRECTORY):
- initial_setup()
- main_menu()
Add Comment
Please, Sign In to add comment