| 67 | |
| 68 | |
| 69 | class Server(Syncable): |
| 70 | def __init__(self, addr, server_id): |
| 71 | self.addr = addr |
| 72 | self.id = server_id |
| 73 | self.players = [] |
| 74 | if not self.sync(): |
| 75 | raise ServerError("server not responding in time") |
| 76 | |
| 77 | def _sync(self): |
| 78 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
| 79 | s.settimeout(1) |
| 80 | s.sendto(b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffgief", self.addr) |
| 81 | bits = s.recvfrom(1024)[0][14:].split(b"\x00") |
| 82 | s.close() |
| 83 | self.version, server_name, map_name = bits[:3] |
| 84 | self.name = server_name.decode("latin1") |
| 85 | self.map = map_name.decode("latin1") |
| 86 | self.gametype = bits[3] |
| 87 | self.flags, self.progression, player_count, self.max_players = map( |
| 88 | int, bits[4:8] |
| 89 | ) |
| 90 | |
| 91 | # sync the player stats |
| 92 | players = {p.name: p for p in self.players} |
| 93 | for i in range(player_count): |
| 94 | name = bits[8 + i * 2].decode("latin1") |
| 95 | score = int(bits[9 + i * 2]) |
| 96 | |
| 97 | # update existing player |
| 98 | if name in players: |
| 99 | player = players.pop(name) |
| 100 | player.score = score |
| 101 | # add new player |
| 102 | else: |
| 103 | self.players.append(Player(self, name, score)) |
| 104 | # delete players that left |
| 105 | for player in players.values(): |
| 106 | try: |
| 107 | self.players.remove(player) |
| 108 | except Exception: |
| 109 | pass |
| 110 | |
| 111 | # sort the player list and count them |
| 112 | self.players.sort(key=lambda x: -x.score) |
| 113 | self.player_count = len(self.players) |
| 114 | |
| 115 | def __cmp__(self, other): |
| 116 | return unicodecmp(self.name, other.name) |
| 117 | |
| 118 | |
| 119 | class Player: |
no outgoing calls
no test coverage detected