def disconnect_player(self, player): if not isinstance(player, OnlinePlayer): player = self.get_player(player) if not player: return self.players.remove(player) self.ids.remove(player.steam_id) logs.ServerLogs(self.id).add( 'joins', f'{player.name} was disconnected after {str(player.online_time())} minutes' )
def _parse_maps(self): res = self.rcon.show_maps() """ Response format example: Current map is Logar Valley Skirmish v1, Next map is Gorodok AAS v2 """ # Try to read the current map try: current_map = Map(re.search(r"Current map is (.+),", res).group(1)) except: current_map = self.current_map # Try to read the upcoming map try: next_map = Map(re.search(r"Next map is (.+)", res).group(1)) except: next_map = self.next_map self.is_transitioning = False if current_map == "/Game/Maps/TransitionMap": self.is_transitioning = True current_map = self.current_map if self.current_map and current_map != self.current_map: # Map has changed self.is_transitioning = True message = f"Map changed from {self.current_map} to {current_map}." if self.last_map_change: message += f" The match lasted {str(int((datetime.now() - self.last_map_change).total_seconds() / 60))} minutes." else: message += " Match duration is unknown." logs.ServerLogs(self.id).add('match', message) self.last_map_change = datetime.now() if self.map_rotation: next_map = self.map_changed(current_map) if self.current_map != current_map: self.current_map = current_map if self.next_map != next_map: self.next_map = next_map if self.next_map and not self.next_map.validate(): self.next_map = self._get_next_map() if self.next_map: self.rcon.set_next_map(str(self.next_map))
def _parse_players(self): res = self.rcon.list_players() """ We need to turn the data given by the server into a more feasible structure. This is what the result from the server looks like: ----- Active Players ----- ID: 0 | SteamID: 76561199023367826 | Name: (WTH) Heidegger | Team ID: 1 | Squad ID: N/A ID: 4 | SteamID: 76561199023367826 | Name: (WTH) Abusify | Team ID: 2 | Squad ID: 1 ----- Recently Disconnected Players [Max of 15] ----- ID: 10 | SteamID: 76561198062628191 | Since Disconnect: 02m.30s | Name: [2.FJg]Gh0st """ players = [] disconnected = [] lines = res.split("\n") for line in lines: if not line.strip() or len(line) < 20: continue # Line is empty if "----- Active Players -----" in line: continue # Skip this line elif "----- Recently Disconnected Players [Max of 15] -----" in line: break # Stop parsing else: # Parse line try: re_res = re.search( r'ID: (\d+) \| SteamID: (\d{17}) \| Name: (.*) \| Team ID: ([12]) \| Squad ID: ([\w/]*)', line).groups() except: # Unable to fetch all data, skip this line pass else: data = {} data['id'] = int(re_res[0]) data['steam_id'] = int(re_res[1]) data['name'] = str(re_res[2]) data['team_id'] = int(re_res[3]) try: data['squad_id'] = int(re_res[4].strip()) except: data['squad_id'] = -1 player = OnlinePlayer(data['steam_id'], data['name'], data['team_id'], data['squad_id'], data['id']) players.append(player) ids = [player.steam_id for player in players] """ Now that we've added all online players to a nice dict, lets compare them with what's cached. Let's start off by getting a list of steam64id's that connected or disconnected. Then, we update what's cached and do whatever else we like with this information. """ connected = [ player for player in players if int(player) not in self.ids ] disconnected = [ player for player in self.players if int(player) not in ids ] # Update the cache for i, player in enumerate(players): old_player = self.select(steam_id=player.steam_id) if old_player: players[i].online_since = old_player[0].online_since players[i].score = old_player[0].score self.players = players self.ids = ids # Log players connecting and disconnecting messages = [] for player in connected: messages.append(f'{player.name} connected') for player in disconnected: messages.append( f'{player.name} disconnected after {str(player.online_time())} minutes' ) if messages: logs.ServerLogs(self.id).add('joins', messages)
def _parse_maps(self): current_map = self.rcon.show_current_map() next_map = self.rcon.show_next_map() """ Old response format example: 'Current map is Logar Valley Skirmish v1, Next map is Gorodok AAS v2' New response format example: 'Current level is Yehorivka, layer is Yehorivka RAAS v3' 'Next level is Kohat, layer is Kohat RAAS v4' """ try: res = re.match(r"Current map is (.+), Next map is (.+)", next_map).groups() except: # Try to read the current map try: current_map = Map( re.match(r"Current level is (.+), layer is (.+)", current_map).group(2)) except: current_map = self.current_map # Try to read the upcoming map try: next_map = Map( re.match(r"Next level is (.+), layer is (.+)", next_map).group(2)) except: next_map = self.next_map else: current_map = Map(res[0]) next_map = Map(res[1]) logging.info('Inst %s: Current map is %s, next map is %s', self.id, current_map, next_map) self.is_transitioning = False if current_map == "/Game/Maps/TransitionMap": self.is_transitioning = True return if self.current_map and current_map != self.current_map: # Map has changed self.is_transitioning = True message = f"Map changed from {self.current_map} to {current_map}." if self.last_map_change: message += f" The match lasted {str(int((datetime.now() - self.last_map_change).total_seconds() / 60))} minutes." else: message += " Match duration is unknown." logging.info('Inst %s: %s', self.id, message) logs.ServerLogs(self.id).add('match', message) self.last_map_change = datetime.now() if self.map_rotation: try: next_map = self.map_changed(current_map) logging.info('Inst %s: MAPROT: Next map will be %s', self.id, next_map) except Exception as e: logging.error( 'Inst %s: MAPROT: An error was raised while looking for next map: %s: %s', self.id, e.__class__.__name__, e) if self.current_map != current_map: self.current_map = current_map if self.next_map != next_map: self.next_map = next_map