Compare commits

..

2 Commits

1
.gitignore vendored

@ -160,3 +160,4 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.vscode/settings.json

@ -86,9 +86,19 @@ gaming_server_profiles = {
'args_DontStarveWeirdlyAtSandersOverworld': ["C:/Program Files (x86)/Steam/steamapps/common/Don't Starve Together Dedicated Server/bin/dontstarve_dedicated_server_nullrenderer.exe", '-persistent_storage_root', r"C:/Users/4lexK/Desktop/GameServers/Dont Starve/Dont Starve weirdly at Sanders", '-conf_dir', "DontStarveWeirdlyAtSandersOverworld", '-console', '-cluster', 'DontStarveWeirdlyAtSanders', '-shard', 'Master'],
'args_DontStarveWeirdlyAtSandersCave': ["C:/Program Files (x86)/Steam/steamapps/common/Don't Starve Together Dedicated Server/bin/dontstarve_dedicated_server_nullrenderer.exe", '-persistent_storage_root', r"C:/Users/4lexK/Desktop/GameServers/Dont Starve/Dont Starve weirdly at Sanders", '-conf_dir', "DontStarveWeirdlyAtSandersCave", '-console', '-cluster', 'DontStarveWeirdlyAtSanders', '-shard', 'Caves'],
'wait_time': 30
}
},
# Ragnarok Online
"sanderro": {
'profile_id': 'sanderro',
'exec_type': 'exe_ro',
'exec_path': "C:/Users/4lexK/Desktop/GameServers/Ragnarok Online/SanderRo_rathena/2 . Emulator/rathena", # Path zur Rathena Installation
'server_name': 'SanderRO',
'directory': "C:/Users/4lexK/Desktop/GameServers/Ragnarok Online/SanderRo_rathena",
'args_asgard': "",
'args_midgar': "",
'args_svartalfeim': "",
'wait_time': 30
}
# World of Warcraft
}
@ -336,27 +346,14 @@ def start_gameserver(profile: str) -> str:
# Create logs directory if it doesn't exist
os.makedirs(os.path.dirname(log_file), exist_ok=True)
if os.path.exists(pid_file):
with open(pid_file, 'r') as file:
pid = int(file.read().strip())
if psutil.pid_exists(pid) and is_java_process(pid):
response_msg = f"Server {server['server_name']} läuft bereits."
return response_msg
else:
os.remove(pid_file)
with open(log_file, 'w') as log:
process = subprocess.Popen(
server['command'],
cwd=server['directory'],
stdout=log,
stderr=log,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == 'nt' else 0
)
#time.sleep(wait_time)
# Prüfen, ob Prozesse bereits laufen
response = initialize_pid(pid_file, {server['server_name']}, is_java_process)
response_msg += response
pid = start_process(log_file, command=server['command'], cur_wrk_dir=server['directory'])
with open(pid_file, 'w') as file:
file.write(str(process.pid))
response_msg = f"Server {server['server_name']} wurde mit PID '{process.pid}' gestartet."
file.write(str(pid))
response_msg = f"Server {server['server_name']} wurde mit PID '{pid}' gestartet."
case "exe_dst":
# Bei exe der DST sind immer mehrere Commands abzusetzen (je nach dem wie viele Shards da sind)
os.chdir(server['directory'])
@ -371,33 +368,54 @@ def start_gameserver(profile: str) -> str:
os.makedirs(os.path.dirname(log_file), exist_ok=True)
# checken wie prozesse heißen
if os.path.exists(pid_file):
with open(pid_file, 'r') as file:
pid = int(file.read().strip())
if psutil.pid_exists(pid) and is_dst_process(pid):
response_msg = f"Server {shard}{server['server_name']} läuft bereits."
return response_msg
else:
os.remove(pid_file)
with open(log_file, 'w') as log:
try:
process = subprocess.Popen(
server[f"args_{shard}"],
cwd=server['exec_path'],
#shell=True,
stdout=log,
stderr=log,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == 'nt' else 0
)
except Exception as err:
print(f"{err = }")
#time.sleep(wait_time)
# Prüfen, ob Prozesse bereits laufen
response = initialize_pid(pid_file, f"{shard}{server['server_name']}", is_dst_process)
response_msg += response
pid = start_process(log_file, command=server[f"args_{shard}"], cur_wrk_dir=server['exec_path'])
with open(pid_file, 'w') as file:
file.write(str(process.pid))
response_msg += f"Server {server['server_name']} ({shard}) wurde mit PID '{process.pid}' gestartet. "
file.write(str(pid))
response_msg += f"Server {server['server_name']} ({shard}) wurde mit PID '{pid}' gestartet. "
case "exe_ro":
# Bei exe von Ragnarok Online werden immer mehrere Server gestartet da verschiedene Server
# unterschiedliche Aufgaben haben und zusammen arbeiten (je nach dem wie viele Realms eingebaut sind | zur Zeit [08/2024] 3)
os.chdir(server['directory'])
# Es wird immer Map- und Web-Server Basis gestartet. Hinzu kommt jeweils ein Char- und ein Login-Server pro Realm (z.Zt [08/2024] 3)
# Map-Server
pid_file_map = os.path.join(server['directory'], f'{server['srv_map_name']}.pid')
log_file_map = os.path.join(server['directory'], 'logs', f'server_{server['srv_map_name']}_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log')
# Web-Server
pid_file_web = os.path.join(server['directory'], f'{server['srv_web_name']}.pid')
log_file_web = os.path.join(server['directory'], 'logs', f'server_{server['srv_web_name']}_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log')
os.makedirs(os.path.dirname(log_file_map), exist_ok=True)
# Realm Server
realm_names = server['realm_names']
for realm in realm_names:
# TODO Checken, wie hier automatisiert werden kann mit realm list.
#Char Server des Realm
pid_file_realm_char = os.path.join(server['directory'], f'{realm}_char.pid')
log_file_realm_char = os.path.join(server['directory'], 'logs', f'server_{realm}_char_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log')
#Login Server des Realm
pid_file_realm_login = os.path.join(server['directory'], f'{realm}_login.pid')
log_file_realm_login = os.path.join(server['directory'], 'logs', f'server_{realm}_login_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log')
# Prüfen, ob Prozesse bereits laufen
response = initialize_pid(pid_file_realm_char, f"{shard}{server['server_name']}", is_dst_process)
response_msg += response
# Starten des Prozess
pid = start_process(log_file, command=server[f"args_{shard}"], cur_wrk_dir=server['exec_path'])
with open(pid_file, 'w') as file:
file.write(str(pid))
response_msg += f"Server {server['server_name']} ({shard}) wurde mit PID '{pid}' gestartet. "
else:
response_msg = f"Server Informationen für Profile {profile} existieren nicht. Bitte prüfen."
return response_msg
@ -490,6 +508,32 @@ def read_pid_file(pid_file):
except (FileNotFoundError, ValueError):
return None
def initialize_pid(path_to_pid: str, server_name: str, type_validater_fn: callable)->str:
if os.path.exists(path_to_pid):
with open(path_to_pid, 'r') as file:
pid = int(file.read().strip())
if psutil.pid_exists(pid) and type_validater_fn(pid):
response_msg = f"Server {server_name} läuft bereits."
return response_msg
else:
os.remove(path_to_pid)
response_msg = f"Server-PID zu {server_name} als Stale identifiziert. Initialisiere."
return response_msg
def start_process(log_file: str, command: list, cur_wrk_dir: str) -> int:
with open(log_file, 'w') as log:
try:
process = subprocess.Popen(
command,
cwd=cur_wrk_dir,
stdout=log,
stderr=log,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == 'nt' else 0
)
except Exception as err:
print(f"{err = }")
return process.pid
def is_java_process(pid):
try:
p = psutil.Process(pid)
@ -619,17 +663,11 @@ async def handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
logging.info("Received request for gameserver status.")
status_msg = get_status_gameservers()
await query.message.reply_text(f"{status_msg}")
case "gameservers_minecraft":
await query.message.reply_text("Wähle einen Minecraft Server:", reply_markup=InlineKeyboardMarkup(minecraft_menu))
case "gameservers_dontstarve":
await query.message.reply_text("Wähle eine Aktion für den Dont Starve Server:", reply_markup=InlineKeyboardMarkup(dont_starve_menu))
case "gameservers_ragnarok_online":
await query.message.reply_text("Wähle eine Aktion für den Ragnarok Online Server:", reply_markup=InlineKeyboardMarkup(ragnarok_online_menu))
case "gameservers_wow":
await query.message.reply_text("Wähle einen Aktion für den World of Warcraft Server:", reply_markup=InlineKeyboardMarkup(wow_menu))
case "gameservers_back":
await send_main_menu(context, query.message.chat_id)
# Minecraft Servers
case "gameservers_minecraft":
await query.message.reply_text("Wähle einen Minecraft Server:", reply_markup=InlineKeyboardMarkup(minecraft_menu))
case "minecraft_vanilla":
await query.message.reply_text("Wähle einen Aktion für den Minecraft Vanilla Server:", reply_markup=InlineKeyboardMarkup(mc_vanilla_menu))
case "minecraft_sanderpack":
@ -687,6 +725,7 @@ async def handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
await query.message.reply_text(f"{msg}")
case "mc_sandervalley_back":
await query.message.reply_text("Wähle einen Minecraft Server:", reply_markup=InlineKeyboardMarkup(minecraft_menu))
# Dont Starve Server
case "gameservers_dst":
await query.message.reply_text("Wähle einen Don't Starve Together Server:", reply_markup=InlineKeyboardMarkup(dont_starve_menu))
@ -721,18 +760,22 @@ async def handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
# await query.message.reply_text(f"{msg}")
#case "dstas_back":
# await query.message.reply_text("Wähle einen Don't Starve Together Server:", reply_markup=InlineKeyboardMarkup(dont_starve_menu))
# Ragnarok Online Server
# Ragnarok Online Server
case "gameservers_ragnarok_online":
await query.message.reply_text("Wähle eine Aktion für den Ragnarok Online Server (Note: Betrifft immer Alle Realms):", reply_markup=InlineKeyboardMarkup(ragnarok_online_menu))
case "ro_start":
msg = "Not Implemented yet"
await query.message.reply_text(f"{msg}")
await send_main_menu(context, query.message.chat_id)
msg = start_gameserver("sanderro")
await query.message.reply_text(f"{msg}")
case "ro_stop":
msg = "Not Implemented yet"
await query.message.reply_text(f"{msg}")
await send_main_menu(context, query.message.chat_id)
msg = stop_gameserver("sanderro")
await query.message.reply_text(f"{msg}")
case "ro_back":
await query.message.reply_text("Wähle einen Gameserver Typ:", reply_markup=InlineKeyboardMarkup(gameserver_menu))
# World of Warcraft Server
case "gameservers_wow":
await query.message.reply_text("Wähle einen Aktion für den World of Warcraft Server (Note: Betrifft immer Alle Realms):", reply_markup=InlineKeyboardMarkup(wow_menu))
case "wow_start":
msg = "Not Implemented yet"
await query.message.reply_text(f"{msg}")

@ -0,0 +1,107 @@
import subprocess
import sys
import argparse
# Constants for server executable names
LOGIN_SERVER = "login-server.exe"
CHAR_SERVER = "char-server.exe"
WEB_SERVER = "web-server.exe"
MAP_SERVER = "map-server.exe"
# Store the process IDs for each server
server_pids = {
"login": None,
"char": None,
"web": None,
"map": None,
}
# Determine if the servers are running
server_running = {
"login": False,
"char": False,
"web": False,
"map": False,
}
def get_server_status(server_name, exe_name):
"""Check if the server is running and retrieve its PID."""
try:
output = subprocess.check_output(f'tasklist /FI "IMAGENAME eq {exe_name}"', shell=True, text=True, errors="ignore")
lines = output.strip().splitlines()
if len(lines) > 1 and lines[1]:
server_pids[server_name] = lines[1].split()[1]
server_running[server_name] = True
else:
server_running[server_name] = False
except subprocess.CalledProcessError:
server_running[server_name] = False
def stop_server(server_name):
"""Stop the specified server if it is running."""
if server_running[server_name]:
subprocess.call(f"taskkill /PID {server_pids[server_name]} /F", cwd=r"C:\Users\4lexK\Desktop\GameServerFiles\SanderRo_rathena\2 . Emulator\rathena", shell=True)
print(f"{server_name.capitalize()} server stopped.")
else:
print(f"{server_name.capitalize()} server is not running.")
def start_server(server_name, script_name, restart_mode):
"""Start the specified server if it is not already running."""
if not server_running[server_name]:
subprocess.Popen(f"cmd /k {script_name} restart_mode={restart_mode}", cwd=r"C:\Users\4lexK\Desktop\GameServerFiles\SanderRo_rathena\2 . Emulator\rathena", shell=True)
print(f"{server_name.capitalize()} server started.")
else:
print(f"{server_name.capitalize()} server is already running with PID {server_pids[server_name]}.")
def stop_all_servers():
"""Stop all servers."""
print("Stopping all servers...")
stop_server("login")
stop_server("char")
stop_server("web")
stop_server("map")
def start_all_servers(restart_mode="off"):
"""Start all servers."""
print("Starting all servers...")
start_server("login", 'logserv.bat', restart_mode)
start_server("char", 'charserv.bat', restart_mode)
start_server("web", 'webserv.bat', restart_mode)
start_server("map", 'mapserv.bat', restart_mode)
def check_status():
""" Check the status of all servers.
"""
print("Getting status of all servers...")
get_server_status("login", LOGIN_SERVER)
get_server_status("char", CHAR_SERVER)
get_server_status("web", WEB_SERVER)
get_server_status("map", MAP_SERVER)
for server, running in server_running.items():
if running:
print(f"{server.capitalize()} server is running with PID {server_pids[server]}")
else:
print(f"{server.capitalize()} server is not running.")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="rAthena Ragnarok Online Server Emulator Control Script")
parser.add_argument('target', choices=['status', 'watch', 'stop', 'start'], help="Choose the target action")
# Show help if no arguments are provided
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
if args.target == "status":
check_status()
elif args.target == "watch":
start_all_servers(restart_mode="on")
elif args.target == "stop":
stop_all_servers()
elif args.target == "start":
start_all_servers(restart_mode="off")
Loading…
Cancel
Save