def deregister_all_server(self): servers_registered = (AstroAPI.get_server( self.ipPortCombo, self.launcher.headers))['data']['Games'] self.registered = False if (len(servers_registered)) > 0: AstroLogging.logPrint( f"Attemping to deregister all ({len(servers_registered)}) servers as {self.ipPortCombo}") # pprint(servers_registered) for reg_srvr in servers_registered: AstroLogging.logPrint(f"Deregistering {reg_srvr['LobbyID']}..") AstroAPI.deregister_server( reg_srvr['LobbyID'], self.launcher.headers) AstroLogging.logPrint("All servers deregistered") time.sleep(1) return [x['LobbyID'] for x in servers_registered] return []
def start_server(self): """ Starts the Dedicated Server process and waits for it to be registered """ self.DedicatedServer.status = "starting" self.DedicatedServer.busy = False oldLobbyIDs = self.DedicatedServer.deregister_all_server() AstroLogging.logPrint("Starting Server process...") if self.launcherConfig.EnableAutoRestart: AstroLogging.logPrint( f"Next restart is at {self.DedicatedServer.nextRestartTime}") time.sleep(5) startTime = time.time() self.DedicatedServer.start() self.DaemonProcess = AstroDaemon.launch( executable=self.isExecutable, consolePID=self.DedicatedServer.process.pid) # Wait for server to finish registering... while not self.DedicatedServer.registered: try: serverData = (AstroAPI.get_server( self.DedicatedServer.ipPortCombo, self.headers)) serverData = serverData['data']['Games'] lobbyIDs = [x['LobbyID'] for x in serverData] if len(set(lobbyIDs) - set(oldLobbyIDs)) == 0: time.sleep(self.launcherConfig.PlayfabAPIFrequency) else: now = time.time() if now - startTime > 15: self.DedicatedServer.registered = True del oldLobbyIDs self.DedicatedServer.LobbyID = serverData[0]['LobbyID'] if self.DedicatedServer.process.poll() is not None: AstroLogging.logPrint( "Server was forcefully closed before registration. Exiting...." ) return False except KeyboardInterrupt: self.DedicatedServer.kill_server("Launcher shutting down") except: AstroLogging.logPrint( "Failed to check server. Probably hit rate limit. Backing off and trying again..." ) self.launcherConfig.PlayfabAPIFrequency += 1 time.sleep(self.launcherConfig.PlayfabAPIFrequency) doneTime = time.time() elapsed = doneTime - startTime AstroLogging.logPrint( f"Server ready with ID {self.DedicatedServer.LobbyID}. Took {round(elapsed,2)} seconds to register." ) self.DedicatedServer.status = "ready" self.DedicatedServer.server_loop()
def getXauth(self): if self.lastXAuth is None or (datetime.datetime.now() - self.lastXAuth).total_seconds() > 3600: try: gxAuth = None while gxAuth is None: try: gxAuth = AstroAPI.generate_XAUTH( self.settings.ServerGuid) except: time.sleep(10) self.launcher.headers['X-Authorization'] = gxAuth self.lastXAuth = datetime.datetime.now() except: self.lastXAuth += datetime.timedelta(seconds=20)
def deregister_all_server(self): servers_registered = (AstroAPI.get_server( self.ipPortCombo, self.launcher.headers))['data']['Games'] self.registered = False if (len(servers_registered)) > 0: AstroLogging.logPrint( f"Attemping to deregister all ({len(servers_registered)}) servers matching self" ) # pprint(servers_registered) for counter, reg_srvr in enumerate(servers_registered): # reg_srvr['LobbyID'] AstroLogging.logPrint( f"Deregistering {counter+1}/{len(servers_registered)}...") drg_status = AstroAPI.deregister_server( reg_srvr['LobbyID'], self.launcher.headers) if 'status' in drg_status and drg_status['status'] == "Error": AstroLogging.logPrint( "Trouble deregistering server. Multiple servers may still be registered.", msgType="warning") AstroLogging.logPrint("All servers deregistered") time.sleep(1) return [x['LobbyID'] for x in servers_registered] return []
def __init__(self, astroPath, launcherINI="Launcher.ini", disable_auto_update=None): AstroLogging.setup_logging() # check if path specified if astroPath is not None: if os.path.exists(os.path.join(astroPath, "AstroServer.exe")): self.astroPath = astroPath else: AstroLogging.logPrint( "Specified path does not contain the server executable! (AstroServer.exe)", "critical") time.sleep(5) return # check if executable in current directory elif os.path.exists(os.path.join(os.getcwd(), "AstroServer.exe")): self.astroPath = os.getcwd() # fallback to automatic detection (experimental, do NOT rely on it) else: try: autoPath = AstroAPI.getInstallPath() if os.path.exists(os.path.join(autoPath, "AstroServer.exe")): self.astroPath = autoPath except: AstroLogging.logPrint( "Unable to find server executable anywhere! (AstroServer.exe)", "critical") time.sleep(5) return AstroLogging.setup_loggingPath(self.astroPath) self.launcherINI = launcherINI self.launcherConfig = self.LauncherConfig() self.launcherPath = os.getcwd() self.refresh_launcher_config() if disable_auto_update is not None: self.launcherConfig.DisableAutoUpdate = disable_auto_update self.version = "v1.6.0" AstroLogging.logPrint( f"AstroLauncher - Unofficial Dedicated Server Launcher {self.version}" ) AstroLogging.logPrint( "If you encounter any bugs please open a new issue at:") AstroLogging.logPrint( "https://github.com/ricky-davis/AstroLauncher/issues") AstroLogging.logPrint( "To safely stop the launcher and server press CTRL+C") self.latestURL = "https://github.com/ricky-davis/AstroLauncher/releases/latest" bName = os.path.basename(sys.executable) if sys.argv[0] == os.path.splitext(bName)[0]: self.isExecutable = True else: self.isExecutable = os.path.samefile(sys.executable, sys.argv[0]) self.headers = AstroAPI.base_headers self.DaemonProcess = None self.saveObserver = None self.backupObserver = None self.hasUpdate = False self.affinity = self.launcherConfig.CPUAffinity try: if self.affinity != "": affinityList = [ int(x.strip()) for x in self.affinity.split(',') ] p = psutil.Process() p.cpu_affinity(affinityList) except ValueError as e: AstroLogging.logPrint(f"CPU Affinity Error: {e}", "critical") AstroLogging.logPrint( "Please correct this in your launcher config", "critical") return self.DedicatedServer = AstroDedicatedServer(self.astroPath, self) self.check_for_update() AstroLogging.logPrint("Starting a new session") if not self.launcherConfig.DisableNetworkCheck: AstroLogging.logPrint("Checking the network configuration..") self.check_network_config() self.save_reporting() if not self.launcherConfig.DisableBackupRetention: self.backup_retention() AstroLogging.logPrint("Backup retention started") # setup queue for data exchange if not self.launcherConfig.DisableWebServer: # start http server self.webServer = self.start_WebServer() # AstroLogging.logPrint( # f"HTTP Server started at 127.0.0.1:{self.launcherConfig.WebServerPort}") if self.launcherConfig.HideLauncherConsoleWindow: # hide window AstroLogging.logPrint( "HideLauncherConsoleWindow enabled, Hiding window in 5 seconds..." ) time.sleep(5) # pylint: disable=redefined-outer-name kernel32 = ctypes.WinDLL('kernel32') user32 = ctypes.WinDLL('user32') hWnd = kernel32.GetConsoleWindow() user32.ShowWindow(hWnd, 0) self.start_server(firstLaunch=True)
def start_server(self, firstLaunch=False): """ Starts the Dedicated Server process and waits for it to be registered """ if firstLaunch: atexit.register(self.DedicatedServer.kill_server, reason="Launcher shutting down via exit", save=True) signal.signal(signal.SIGINT, self.signal_handler) else: self.check_for_update(serverStart=True) self.DedicatedServer = AstroDedicatedServer(self.astroPath, self) self.DedicatedServer.status = "starting" self.DedicatedServer.busy = False gxAuth = None while gxAuth is None: try: gxAuth = AstroAPI.generate_XAUTH( self.DedicatedServer.settings.ServerGuid) except: AstroLogging.logPrint( "Unable to generate XAuth token... Are you connected to the internet?", msgType="warning") time.sleep(5) self.headers['X-Authorization'] = gxAuth oldLobbyIDs = self.DedicatedServer.deregister_all_server() AstroLogging.logPrint("Starting Server process...") if self.launcherConfig.EnableAutoRestart: AstroLogging.logPrint( f"Next restart is at {self.DedicatedServer.nextRestartTime}") # time.sleep(5) startTime = time.time() try: self.DedicatedServer.start() except: AstroLogging.logPrint("Unable to launch AstroServer.exe", "critical") return False reachableProcess = None pcounter = 40 while not reachableProcess: try: reachableProcess = not bool( self.DedicatedServer.process.poll()) pcounter -= 1 time.sleep(0.25) except: pcounter -= 2 time.sleep(0.5) if pcounter <= 0: AstroLogging.logPrint( "Unable to start Server Process after 10 seconds!", "critical") return False AstroLogging.logPrint("Server started! Getting ready....", ovrDWHL=True) try: self.DaemonProcess = AstroDaemon.launch( executable=self.isExecutable, consolePID=self.DedicatedServer.process.pid) except: AstroLogging.logPrint("Unable to start watcher daemon", "warning") return False # Wait for server to finish registering... serverData = None oPFF = self.launcherConfig.PlayfabAPIFrequency while not self.DedicatedServer.registered: AstroLogging.logPrint("Waiting for server to register...", "debug") try: serverData = (AstroAPI.get_server( self.DedicatedServer.ipPortCombo, self.headers)) serverData = serverData['data']['Games'] lobbyIDs = [x['LobbyID'] for x in serverData] if len(set(lobbyIDs) - set(oldLobbyIDs)) == 0: time.sleep(self.launcherConfig.PlayfabAPIFrequency) else: now = time.time() if now - startTime > 15: serverData = serverData[0] self.DedicatedServer.registered = True oldLobbyIDs = None self.DedicatedServer.LobbyID = serverData['LobbyID'] if self.DedicatedServer.process.poll() is not None: AstroLogging.logPrint( "Server was forcefully closed before registration. Exiting...." ) return False except KeyboardInterrupt: self.DedicatedServer.kill_server( "Launcher shutting down via KeyboardInterrupt") except: AstroLogging.logPrint( "Failed to check server. Probably hit rate limit. Backing off and trying again..." ) if self.launcherConfig.PlayfabAPIFrequency < 30: self.launcherConfig.PlayfabAPIFrequency += 1 time.sleep(self.launcherConfig.PlayfabAPIFrequency) self.launcherConfig.PlayfabAPIFrequency = oPFF self.DedicatedServer.serverData = serverData doneTime = time.time() elapsed = doneTime - startTime AstroLogging.logPrint( f"Server ready! Took {round(elapsed,2)} seconds to register.", ovrDWHL=True) # {self.DedicatedServer.LobbyID} self.DedicatedServer.status = "ready" self.DedicatedServer.server_loop()
def __init__(self, astroPath, launcherINI="Launcher.ini", disable_auto_update=None): AstroLogging.setup_logging() # check if path specified if astroPath is not None: if os.path.exists(os.path.join(astroPath, "AstroServer.exe")): self.astroPath = astroPath else: AstroLogging.logPrint( "Specified path does not contain the server executable! (AstroServer.exe)", "critical") time.sleep(5) return # check if executable in current directory elif os.path.exists(os.path.join(os.getcwd(), "AstroServer.exe")): self.astroPath = os.getcwd() # fallback to automatic detection (experimental, do NOT rely on it) else: try: autoPath = AstroAPI.getInstallPath() if os.path.exists(os.path.join(autoPath, "AstroServer.exe")): self.astroPath = autoPath except: AstroLogging.logPrint( "Unable to find server executable anywhere! (AstroServer.exe)", "critical") time.sleep(5) return # AstroRequests.checkProxies() self.launcherINI = launcherINI self.launcherConfig = self.LauncherConfig() self.launcherPath = os.getcwd() self.refresh_launcher_config() AstroLogging.discordWebhookURL = self.launcherConfig.DiscordWebHookURL dwhl = self.launcherConfig.DiscordWebHookLevel.lower() dwhl = dwhl if dwhl in ("all", "cmd", "chat") else "cmd" AstroLogging.discordWebhookLevel = dwhl self.start_WebHookLoop() AstroLogging.setup_loggingPath( astroPath=self.astroPath, logRetention=int(self.launcherConfig.LogRetentionDays)) if disable_auto_update is not None: self.launcherConfig.DisableAutoUpdate = disable_auto_update self.version = "v1.7.6" colsize = os.get_terminal_size().columns if colsize >= 77: vText = "Version " + self.version[1:] # pylint: disable=anomalous-backslash-in-string print( " __________________________________________________________________________\n" + "| _ _ _ _ |\n" + "| /_\\ ___| |_ _ _ ___ | | __ _ _ _ _ _ __ | |_ ___ _ _ |\n" + "| / _ \\ (_-<| _|| '_|/ _ \\ | |__ / _` || || || ' \\ / _|| ' \\ / -_)| '_| |\n" + "| /_/ \\_\\/__/ \\__||_| \\___/ |____|\\__,_| \\_,_||_||_|\\__||_||_|\\___||_| |\n" + "| |\n" + "|" + vText.center(74) + "|\n" + "|__________________________________________________________________________|" ) AstroLogging.logPrint( f"AstroLauncher - Unofficial Dedicated Server Launcher {self.version}" ) AstroLogging.logPrint( "If you encounter any bugs please open a new issue at:") AstroLogging.logPrint( "https://github.com/ricky-davis/AstroLauncher/issues") AstroLogging.logPrint( "To safely stop the launcher and server press CTRL+C") # AstroRequests.checkProxies() self.latestURL = "https://github.com/ricky-davis/AstroLauncher/releases/latest" bName = os.path.basename(sys.executable) if sys.argv[0] == os.path.splitext(bName)[0]: self.isExecutable = True else: self.isExecutable = os.path.samefile(sys.executable, sys.argv[0]) self.headers = AstroAPI.base_headers self.DaemonProcess = None self.saveObserver = None self.backupObserver = None self.hasUpdate = False self.is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0 self.affinity = self.launcherConfig.CPUAffinity try: if self.affinity != "": affinityList = [ int(x.strip()) for x in self.affinity.split(',') ] p = psutil.Process() p.cpu_affinity(affinityList) except ValueError as e: AstroLogging.logPrint(f"CPU Affinity Error: {e}", "critical") AstroLogging.logPrint( "Please correct this in your launcher config", "critical") return self.DedicatedServer = AstroDedicatedServer(self.astroPath, self) self.check_for_update() AstroLogging.logPrint("Starting a new session") self.validate_playfab_certs() self.check_ports_free() if self.launcherConfig.AdminAutoConfigureFirewall: self.configure_firewall() if not self.launcherConfig.DisableNetworkCheck: AstroLogging.logPrint("Checking the network configuration..") self.check_network_config() self.save_reporting() if not self.launcherConfig.DisableBackupRetention: self.backup_retention() AstroLogging.logPrint("Backup retention started") # setup queue for data exchange self.webServer = None if not self.launcherConfig.DisableWebServer: # start http server self.webServer = self.start_WebServer() self.start_InfoLoop() # AstroLogging.logPrint( # f"HTTP Server started at 127.0.0.1:{self.launcherConfig.WebServerPort}") if self.launcherConfig.HideLauncherConsoleWindow: # hide window AstroLogging.logPrint( "HideLauncherConsoleWindow enabled, Hiding window in 5 seconds..." ) time.sleep(5) # pylint: disable=redefined-outer-name kernel32 = ctypes.WinDLL('kernel32') user32 = ctypes.WinDLL('user32') hWnd = kernel32.GetConsoleWindow() user32.ShowWindow(hWnd, 0) self.start_server(firstLaunch=True)
def __init__(self, astroPath, launcherINI="Launcher.ini", disable_auto_update=None): # check if path specified if astroPath is not None: if os.path.exists(os.path.join(astroPath, "AstroServer.exe")): self.astroPath = astroPath else: print("Specified path does not contain the server executable") time.sleep(5) # check if executable in current directory elif os.path.exists(os.path.join(os.getcwd(), "AstroServer.exe")): self.astroPath = os.getcwd() # fallback to automatic detection (experimental, do NOT rely on it) else: try: autoPath = AstroAPI.getInstallPath() if os.path.exists(os.path.join(autoPath, "AstroServer.exe")): self.astroPath = autoPath except: AstroLogging.logPrint("Unable to find AstroServer.exe!", "critical") return AstroLogging.setup_logging(self.astroPath) self.launcherINI = launcherINI self.launcherConfig = self.LauncherConfig() self.launcherPath = os.getcwd() self.refresh_launcher_config() if disable_auto_update is not None: self.launcherConfig.DisableAutoUpdate = disable_auto_update self.version = "v1.4.6" self.latestURL = "https://github.com/ricky-davis/AstroLauncher/releases/latest" self.isExecutable = os.path.samefile(sys.executable, sys.argv[0]) self.headers = AstroAPI.base_headers self.DaemonProcess = None self.saveObserver = None self.backupObserver = None self.DSServerStats = None self.DedicatedServer = AstroDedicatedServer(self.astroPath, self) AstroLogging.logPrint( f"AstroLauncher - Unofficial Dedicated Server Launcher {self.version}" ) AstroLogging.logPrint( "If you encounter any bugs please open a new issue at:") AstroLogging.logPrint( "https://github.com/ricky-davis/AstroLauncher/issues") AstroLogging.logPrint( "To safely stop the launcher and server press CTRL+C") self.check_for_update() AstroLogging.logPrint("Starting a new session") if not self.launcherConfig.DisableNetworkCheck: AstroLogging.logPrint("Checking the network configuration..") self.check_network_config() self.headers['X-Authorization'] = AstroAPI.generate_XAUTH( self.DedicatedServer.settings.ServerGuid) self.save_reporting() if not self.launcherConfig.DisableBackupRetention: self.backup_retention() AstroLogging.logPrint("Backup retention started") # setup queue for data exchange if not self.launcherConfig.DisableWebServer: # start http server self.webServer = self.start_WebServer() AstroLogging.logPrint( f"HTTP Server started at 127.0.0.1:{self.launcherConfig.WebServerPort}" ) atexit.register(self.DedicatedServer.kill_server, reason="Launcher shutting down", save=True) self.start_server()
def server_loop(self): while True: # Ensure RCON is connected try: if not self.AstroRCON or not self.AstroRCON.connected: self.AstroRCON = self.start_RCON() self.quickToggleWhitelist() except: pass while not self.AstroRCON.connected: time.sleep(0.1) ########################### if not self.launcher.launcherConfig.DisableBackupRetention: self.launcher.backup_retention() self.launcher.save_reporting() if self.launcher.launcherConfig.EnableAutoRestart: if (((datetime.datetime.now() - self.lastRestart).total_seconds() > 60) and ((self.nextRestartTime - datetime.datetime.now()).total_seconds() < 0)): AstroLogging.logPrint("Preparing to shutdown the server.") self.lastRestart = datetime.datetime.now() self.nextRestartTime += datetime.timedelta( hours=self.launcher.launcherConfig. AutoRestartEveryHours) self.save_and_shutdown() if self.process.poll() is not None: AstroLogging.logPrint("Server was closed. Restarting..") return self.launcher.start_server() self.getXauth() if self.lastHeartbeat is None or ( datetime.datetime.now() - self.lastHeartbeat).total_seconds() > 30: serverData = [] try: serverData = (AstroAPI.get_server( self.ipPortCombo, self.launcher.headers))['data']['Games'] if len(serverData) > 0: self.serverData = serverData[0] except: pass hbServerName = { "customdata": { "ServerName": self.settings.ServerName, "ServerType": ("AstroLauncherEXE" if self.launcher.isExecutable else "AstroLauncherPy") + f" {self.launcher.version}", "ServerPaks": self.pakList } } hbStatus = AstroAPI.heartbeat_server( self.serverData, self.launcher.headers, {"serverName": json.dumps(hbServerName)}) hbTryCount = 0 while hbStatus['status'] != "OK": if hbTryCount > 3: self.kill_server( reason= "Server was unable to heartbeat, restarting...", save=True, killLauncher=False) time.sleep(5) return self.launcher.start_server() self.getXauth() hbTryCount += 1 try: hbStatus = AstroAPI.heartbeat_server( self.serverData, self.launcher.headers, {"serverName": json.dumps(hbServerName)}) except: AstroLogging.logPrint( f"Failed to heartbeat server on attempt: {hbTryCount}" ) time.sleep(5 * hbTryCount) self.lastHeartbeat = datetime.datetime.now() if self.launcher.webServer is not None: self.setStatus("ready") self.busy = "getSavesInLoop" self.getSaves() self.busy = False self.setStatus("ready") serverStats = self.AstroRCON.DSServerStatistics() if serverStats is not None and 'averageFPS' in serverStats: self.DSServerStats = serverStats if self.launcher.launcherConfig.ShowServerFPSInConsole: FPSJumpRate = (float(self.settings.MaxServerFramerate) / 5) if self.oldServerStats is None or (abs( float(self.DSServerStats['averageFPS']) - float(self.oldServerStats['averageFPS'])) > FPSJumpRate): AstroLogging.logPrint( f"Server FPS: {round(self.DSServerStats['averageFPS'])}" ) self.oldServerStats = self.DSServerStats self.setStatus("ready") playerList = self.AstroRCON.DSListPlayers() if playerList is not None and 'playerInfo' in playerList: self.players = playerList curPlayers = [ x['playerName'] for x in self.players['playerInfo'] if x['inGame'] ] if len(curPlayers) > len(self.onlinePlayers): playerDif = list( set(curPlayers) - set(self.onlinePlayers))[0] self.onlinePlayers = curPlayers if playerDif in self.stripPlayers: self.stripPlayers.remove(playerDif) AstroLogging.logPrint(f"Player joining: {playerDif}") # Add player to INI with Unlisted category if not exists or is Pending pp = list(self.settings.PlayerProperties) difGuid = [ x for x in self.players['playerInfo'] if x['playerName'] == playerDif ][0]["playerGuid"] if len([ x for x in pp if difGuid in x and "PlayerCategory=Pending" not in x ]) == 0: self.AstroRCON.DSSetPlayerCategoryForPlayerName( playerDif, "Unlisted") self.refresh_settings() elif len(curPlayers) < len(self.onlinePlayers): playerDif = list( set(self.onlinePlayers) - set(curPlayers))[0] self.onlinePlayers = curPlayers AstroLogging.logPrint(f"Player left: {playerDif}") self.players['playerInfo'] = [ x for x in playerList['playerInfo'] if x['playerName'] not in self.stripPlayers ] time.sleep(self.launcher.launcherConfig.ServerStatusFrequency)
def start_server(self, firstLaunch=False): """ Starts the Dedicated Server process and waits for it to be registered """ if firstLaunch: atexit.register(self.DedicatedServer.kill_server, reason="Launcher shutting down", save=True) signal.signal(signal.SIGINT, self.signal_handler) else: self.check_for_update(serverStart=True) self.DedicatedServer = AstroDedicatedServer(self.astroPath, self) self.DedicatedServer.status = "starting" self.DedicatedServer.busy = False gxAuth = None while gxAuth is None: try: gxAuth = AstroAPI.generate_XAUTH( self.DedicatedServer.settings.ServerGuid) except: time.sleep(10) self.headers['X-Authorization'] = gxAuth oldLobbyIDs = self.DedicatedServer.deregister_all_server() AstroLogging.logPrint("Starting Server process...") if self.launcherConfig.EnableAutoRestart: AstroLogging.logPrint( f"Next restart is at {self.DedicatedServer.nextRestartTime}") # time.sleep(5) startTime = time.time() self.DedicatedServer.start() self.DaemonProcess = AstroDaemon.launch( executable=self.isExecutable, consolePID=self.DedicatedServer.process.pid) # Wait for server to finish registering... serverData = None while not self.DedicatedServer.registered: try: serverData = (AstroAPI.get_server( self.DedicatedServer.ipPortCombo, self.headers)) serverData = serverData['data']['Games'] lobbyIDs = [x['LobbyID'] for x in serverData] if len(set(lobbyIDs) - set(oldLobbyIDs)) == 0: time.sleep(self.launcherConfig.PlayfabAPIFrequency) else: now = time.time() if now - startTime > 15: serverData = serverData[0] self.DedicatedServer.registered = True oldLobbyIDs = None self.DedicatedServer.LobbyID = serverData['LobbyID'] if self.DedicatedServer.process.poll() is not None: AstroLogging.logPrint( "Server was forcefully closed before registration. Exiting...." ) return False except KeyboardInterrupt: self.DedicatedServer.kill_server("Launcher shutting down") except: AstroLogging.logPrint( "Failed to check server. Probably hit rate limit. Backing off and trying again..." ) self.launcherConfig.PlayfabAPIFrequency += 1 time.sleep(self.launcherConfig.PlayfabAPIFrequency) self.DedicatedServer.serverData = serverData doneTime = time.time() elapsed = doneTime - startTime AstroLogging.logPrint( f"Server ready! Took {round(elapsed,2)} seconds to register." ) # {self.DedicatedServer.LobbyID} self.DedicatedServer.status = "ready" self.DedicatedServer.server_loop()