def startProtocol(self): self.transport.connect(self.host, self.port) cds = CubeDataStream() cds.putint(1) self.transport.write(str(cds))
def __init__(self) -> None: self.game_clock: Optional[GameClock] = None self.messages = CubeDataStream() self.state: int = -1 self.lifesequence = 0 self.frags = 0 self.deaths = 0 self.suicides = 0 self.teamkills = 0 self.damage_dealt = 0 self.damage_spent = 0 self.flags = 0 self.flag_returns = 0 self.health = 100 self.maxhealth = 100 self.armour = 0 self.armourtype = armor_types.A_BLUE self.gunselect = weapon_types.GUN_PISTOL self.ammo = [0] * weapon_types.NUMGUNS self.death_timer = None self.pos = vec(0, 0, 0) self._quadexpiry: Optional[Expiry] = None self.shotwait: Optional[Expiry] = None self.spawnwait: Optional[Expiry] = None self._pending_spawn = False self.rockets: Dict = {} self.grenades: Dict = {} self.position = b'' self.reset()
def write_state(self, room_positions: CubeDataStream, room_messages: CubeDataStream) -> None: if self.state.position is not None: room_positions.write(self.state.position) if not self.state.messages.empty(): swh.put_clientdata(room_messages, self, self.state.messages)
def info_request(self, address, millis): cds = CubeDataStream() cds.putint(millis) swh.put_info_reply(cds, self.room.lan_info_name, self.room.player_count, self.room.maxplayers, self.room.mode_num, self.room.map_name, self.room.timeleft, self.room.mastermask, self.room.is_paused, 100) self.respond(bytes(cds), address)
def process(self, channel, data): if len(data) == 0: return [] if channel == 0: messages = self._parse_channel_0_data(data) elif channel == 1: messages = sauerbraten_stream_spec.read(data, {'aiclientnum': -1}) else: return [] print(channel) # ... <cube int: port><cube str: domain><cube int: mode num><cube str: map name> cds = CubeDataStream(data) print((cds.getint())) print((cds.getint())) print((cds.getint())) print((cds.getint())) print((cds.getint())) print((cds.getstring())) print((cds.getbyte())) print((cds.getstring())) print((repr(data))) sys.exit(0) return messages
def get_ext_info_reply_cds(rcds): cds = CubeDataStream() cds.write(rcds.data) cds.putint(EXT_ACK) cds.putint(EXT_VERSION) return cds
def info_request(self, address, millis): cds = CubeDataStream() cds.putint(millis) swh.put_info_reply( cds, self.room.lan_info_name, self.room.player_count, self.room.maxplayers, self.room.mode_num, self.room.map_name, self.room.timeleft, self.room.mastermask, self.room.is_paused, 100) self.respond(str(cds), address)
def broadcastbuffer( self, channel: int, reliable: bool = False, exclude: Optional[Union[List[Client], Tuple, List[Player]]] = None, clients: Optional[List[Client]] = None ) -> Iterator[CubeDataStream]: cds = CubeDataStream() yield cds self.broadcast(channel, cds, reliable, exclude, clients)
def send(self, channel: int, data: CubeDataStream, reliable: bool, no_allocate: bool = False) -> None: if type(data) == memoryview: data = data.tobytes() elif type(data) == CubeDataStream: data = memoryview(data.data).tobytes() elif type(data) != str: data = str(data) self.protocol_wrapper.send(channel, data, reliable, no_allocate)
class PlayerState(object): def __init__(self): self.game_clock = None self.messages = CubeDataStream() self.state = -1 self.reset() def use_game_clock(self, game_clock): self.game_clock = game_clock @property def has_quad(self): if self._quadexpiry is not None: return not self._quadexpiry.is_expired return False @property def quad_multiplier(self): if self.has_quad: return 4 else: return 1 @property def quadremaining(self): if self.has_quad: return self._quadexpiry.remaining else: return 0 @property def can_shoot(self): if not self.is_alive: return False if self.shotwait is not None: return self.shotwait.is_expired return True @property def can_spawn(self): if self.is_spectator: return False if self.is_alive: return False if self._pending_spawn: return False if self.spawnwait is not None: return self.spawnwait.is_expired return True @property def kpd(self): return KPD(self.frags, self.deaths) @property def acc_formatted(self): acc = self.acc_percent if acc is Ellipsis: return "inf" else: return "{:.2f}%".format(acc) @property def acc_percent(self): if self.damage_spent == 0: return Ellipsis return (100 * self.damage_dealt) / self.damage_spent @property def acc_percent_int(self): acc = self.acc_percent if acc is Ellipsis: return 0 else: return int(acc) @property def time_playing_this_match(self): if self.playing_timer is not None: return self.playing_timer.time_elapsed else: return 0.0 @property def is_alive(self): return self.state == client_states.CS_ALIVE @property def millis_since_death(self): if self.death_timer is None: return None return self.death_timer.time_elapsed * 1000 def check_alive(self, threshold=None): if threshold is None: return self.is_alive if self.is_alive: return True else: millis_since_death = self.millis_since_death return millis_since_death is not None and millis_since_death < threshold @property def is_spectator(self): return self.state == client_states.CS_SPECTATOR @is_spectator.setter def is_spectator(self, value): if value and not self.is_spectator: self.state = client_states.CS_SPECTATOR if self.playing_timer is not None: self.playing_timer.pause() elif not value and self.is_spectator: self.state = client_states.CS_DEAD if self.playing_timer is not None: self.playing_timer.resume() else: print("failed to set is_spectator") def respawn(self): self._pending_spawn = True self.lifesequence = (self.lifesequence + 1) & 0x7F self._quadexpiry = None self.position = None def on_respawn(self, lifesequence, gunselect): if lifesequence != self.lifesequence: return self._pending_spawn = False self.state = client_states.CS_ALIVE self.gunselect = gunselect swh.put_spawn(self.messages, self) def update_position(self, position, raw_position): self.position = raw_position self.pos.v = position def clear_flushed_state(self): self.messages = CubeDataStream() self.position = None def map_change_reset(self): if self.state != client_states.CS_SPECTATOR: self.state = client_states.CS_DEAD self.frags = 0 self.deaths = 0 self.suicides = 0 self.teamkills = 0 self.damage_dealt = 0 self.damage_spent = 0 self.flags = 0 self.flag_returns = 0 self.health = 100 self.maxhealth = 100 self.armour = 0 self.armourtype = armor_types.A_BLUE self.gunselect = weapon_types.GUN_PISTOL self.ammo = [0] * weapon_types.NUMGUNS if self.game_clock is not None: self.playing_timer = Timer(self.game_clock) else: self.playing_timer = None self.death_timer = None self.pos = vec(0, 0, 0) self._quadexpiry = None self.shotwait = None self.spawnwait = None self._pending_spawn = False self.rockets = {} self.grenades = {} self.messages.clear() self.position = None def reset(self): self.map_change_reset() self.state = client_states.CS_ALIVE self.lifesequence = -1 def receive_damage(self, damage): # let armour absorb when possible ad = damage * (self.armourtype + 1) * (25.0 / 100.0) if ad > self.armour: ad = self.armour self.armour -= int(ad) damage = int(damage - int(ad)) self.health -= damage return damage def suicide(self): self.frags -= 1 self.deaths += 1 self.suicides += 1 self.state = client_states.CS_DEAD def died(self): if self.game_clock is not None: self.death_timer = Timer(self.game_clock) else: self.death_timer = None def pickup_item(self, item_type): if item_type < item_types.I_SHELLS or item_type > item_types.I_QUAD: print("Item out of range could not be picked up.") return itemstat = itemstats[item_type - item_types.I_SHELLS] if item_type == item_types.I_BOOST: # boost also adds to health if self.maxhealth >= itemstat.max: return False self.maxhealth = min(self.maxhealth + itemstat.add, itemstat.max) if item_type in (item_types.I_BOOST, item_types.I_HEALTH): self.health = min(self.health + itemstat.add, self.maxhealth) elif item_type in [ item_types.I_GREENARMOUR, item_types.I_YELLOWARMOUR ]: if self.armour >= itemstat.max: return False self.armour = min(self.armour + itemstat.add, itemstat.max) self.armourtype = itemstat.info elif item_type == item_types.I_QUAD: if self.has_quad: self._quadexpiry.extend( float(itemstat.add) / 1000.0, float(itemstat.max) / 1000.0) else: self._quadexpiry = Expiry(self.game_clock, float(itemstat.add) / 1000.0) else: # is an ammo if self.ammo[itemstat.info] >= itemstat.max: return False self.ammo[itemstat.info] = min( self.ammo[itemstat.info] + itemstat.add, itemstat.max) return True
def clear_flushed_state(self): self.messages = CubeDataStream() self.position = None
def broadcastbuffer(self, channel, reliable=False, exclude=[], clients=None): cds = CubeDataStream() yield cds self.broadcast(channel, cds, reliable, exclude, clients)
def flush_messages(self): try: class ClientBufferReference(object): def __init__(self, client, positions_next_byte, positions_size, messages_next_byte, messages_size): self.client = client self.positions_next_byte = positions_next_byte self.positions_size = positions_size self.messages_next_byte = messages_next_byte self.messages_size = messages_size room_positions = CubeDataStream() room_messages = CubeDataStream() references = [] positions_next_byte = 0 messages_next_byte = 0 for client in self._client_collection.to_iterator(): player = client.get_player() positions_first_byte = positions_next_byte messages_first_byte = messages_next_byte player.write_state(room_positions, room_messages) positions_next_byte = len(room_positions) messages_next_byte = len(room_messages) positions_size = positions_next_byte - positions_first_byte messages_size = messages_next_byte - messages_first_byte references.append(ClientBufferReference(client, positions_next_byte, positions_size, messages_next_byte, messages_size)) positions_len = len(room_positions) messages_len = len(room_messages) room_positions.write(room_positions) room_messages.write(room_messages) position_data = memoryview(room_positions.data) message_data = memoryview(room_messages.data) for ref in references: client = ref.client pnb = ref.positions_next_byte mnb = ref.messages_next_byte psize = ref.positions_size msize = ref.messages_size if positions_len - psize > 0: # TODO: Use no_allocate option here client.send(0, position_data[pnb:pnb + (positions_len - psize)], False, False) if messages_len - msize > 0: # TODO: Use no_allocate option here client.send(1, message_data[mnb:mnb + (messages_len - msize)], True, False) for player in self._player_collection.to_iterator(): player.state.clear_flushed_state() except: traceback.print_exc()
def sendbuffer(self, channel: int, reliable: bool) -> Iterator[CubeDataStream]: cds = CubeDataStream() yield cds self.send(channel, cds, reliable)
def sound(self, sound): for client in self._client_collection.to_iterator(): with client.sendbuffer(1, True) as cds: tm = CubeDataStream() swh.put_sound(tm, sound) swh.put_clientdata(cds, client, str(tm))
def on_edit_mode(self, room, player, editmode): with room.broadcastbuffer(1, True, [player]) as cds: tm = CubeDataStream() swh.put_editmode(tm, editmode) swh.put_clientdata(cds, player.client, str(tm))
def flush_messages(self) -> None: try: class ClientBufferReference(object): def __init__(self, client, positions_next_byte, positions_size, messages_next_byte, messages_size): self.client = client self.positions_next_byte = positions_next_byte self.positions_size = positions_size self.messages_next_byte = messages_next_byte self.messages_size = messages_size room_positions = CubeDataStream() room_messages = CubeDataStream() references = [] positions_next_byte = 0 messages_next_byte = 0 for client in self._client_collection.to_iterator(): player = client.get_player() positions_first_byte = positions_next_byte messages_first_byte = messages_next_byte player.write_state(room_positions, room_messages) positions_next_byte = len(room_positions) messages_next_byte = len(room_messages) positions_size = positions_next_byte - positions_first_byte messages_size = messages_next_byte - messages_first_byte references.append( ClientBufferReference(client, positions_next_byte, positions_size, messages_next_byte, messages_size)) positions_len = len(room_positions) messages_len = len(room_messages) room_positions.write(room_positions) room_messages.write(room_messages) position_data = memoryview(room_positions.data) message_data = memoryview(room_messages.data) for ref in references: client = ref.client pnb = ref.positions_next_byte mnb = ref.messages_next_byte psize = ref.positions_size msize = ref.messages_size if positions_len - psize > 0: # TODO: Use no_allocate option here client.send( 0, position_data[pnb:pnb + (positions_len - psize)], False, False) if messages_len - msize > 0: # TODO: Use no_allocate option here client.send(1, message_data[mnb:mnb + (messages_len - msize)], True, False) for player in self._player_collection.to_iterator(): player.state.clear_flushed_state() except: traceback.print_exc()
def __init__(self): self.game_clock = None self.messages = CubeDataStream() self.state = -1 self.reset()
def sendbuffer(self, channel, reliable): cds = CubeDataStream() yield cds self.send(channel, cds, reliable)
class PlayerState(object): def __init__(self): self.game_clock = None self.messages = CubeDataStream() self.state = -1 self.reset() def use_game_clock(self, game_clock): self.game_clock = game_clock @property def has_quad(self): if self._quadexpiry is not None: return not self._quadexpiry.is_expired return False @property def quad_multiplier(self): if self.has_quad: return 4 else: return 1 @property def quadremaining(self): if self.has_quad: return self._quadexpiry.remaining else: return 0 @property def can_shoot(self): if not self.is_alive: return False if self.shotwait is not None: return self.shotwait.is_expired return True @property def can_spawn(self): if self.is_spectator: return False if self.is_alive: return False if self._pending_spawn: return False if self.spawnwait is not None: return self.spawnwait.is_expired return True @property def kpd(self): return KPD(self.frags, self.deaths) @property def acc_formatted(self): acc = self.acc_percent if acc is Ellipsis: return "inf" else: return "{:.2f}%".format(acc) @property def acc_percent(self): if self.damage_spent == 0: return Ellipsis return (100 * self.damage_dealt) / self.damage_spent @property def acc_percent_int(self): acc = self.acc_percent if acc is Ellipsis: return 0 else: return int(acc) @property def time_playing_this_match(self): if self.playing_timer is not None: return self.playing_timer.time_elapsed else: return 0.0 @property def is_alive(self): return self.state == client_states.CS_ALIVE @property def millis_since_death(self): if self.death_timer is None: return None return self.death_timer.time_elapsed * 1000 def check_alive(self, threshold=None): if threshold is None: return self.is_alive if self.is_alive: return True else: millis_since_death = self.millis_since_death return millis_since_death is not None and millis_since_death < threshold @property def is_spectator(self): return self.state == client_states.CS_SPECTATOR @is_spectator.setter def is_spectator(self, value): if value and not self.is_spectator: self.state = client_states.CS_SPECTATOR if self.playing_timer is not None: self.playing_timer.pause() elif not value and self.is_spectator: self.state = client_states.CS_DEAD if self.playing_timer is not None: self.playing_timer.resume() else: print "failed to set is_spectator" def respawn(self): self._pending_spawn = True self.lifesequence = (self.lifesequence + 1) & 0x7F self._quadexpiry = None self.position = None def on_respawn(self, lifesequence, gunselect): if lifesequence != self.lifesequence: return self._pending_spawn = False self.state = client_states.CS_ALIVE self.gunselect = gunselect swh.put_spawn(self.messages, self) def update_position(self, position, raw_position): self.position = raw_position self.pos.v = position def clear_flushed_state(self): self.messages = CubeDataStream() self.position = None def map_change_reset(self): if self.state != client_states.CS_SPECTATOR: self.state = client_states.CS_DEAD self.frags = 0 self.deaths = 0 self.suicides = 0 self.teamkills = 0 self.damage_dealt = 0 self.damage_spent = 0 self.flags = 0 self.flag_returns = 0 self.health = 100 self.maxhealth = 100 self.armour = 0 self.armourtype = armor_types.A_BLUE self.gunselect = weapon_types.GUN_PISTOL self.ammo = [0] * weapon_types.NUMGUNS if self.game_clock is not None: self.playing_timer = Timer(self.game_clock) else: self.playing_timer = None self.death_timer = None self.pos = vec(0, 0, 0) self._quadexpiry = None self.shotwait = None self.spawnwait = None self._pending_spawn = False self.rockets = {} self.grenades = {} self.messages.clear() self.position = None def reset(self): self.map_change_reset() self.state = client_states.CS_ALIVE self.lifesequence = -1 def receive_damage(self, damage): # let armour absorb when possible ad = damage * (self.armourtype + 1) * (25.0 / 100.0) if ad > self.armour: ad = self.armour self.armour -= int(ad) damage = int(damage - int(ad)) self.health -= damage return damage def suicide(self): self.frags -= 1 self.deaths += 1 self.suicides += 1 self.state = client_states.CS_DEAD def died(self): if self.game_clock is not None: self.death_timer = Timer(self.game_clock) else: self.death_timer = None def pickup_item(self, item_type): if item_type < item_types.I_SHELLS or item_type > item_types.I_QUAD: print "Item out of range could not be picked up." return itemstat = itemstats[item_type - item_types.I_SHELLS] if item_type == item_types.I_BOOST: # boost also adds to health if self.maxhealth >= itemstat.max: return False self.maxhealth = min(self.maxhealth + itemstat.add, itemstat.max) if item_type in (item_types.I_BOOST, item_types.I_HEALTH): self.health = min(self.health + itemstat.add, self.maxhealth) elif item_type in [item_types.I_GREENARMOUR, item_types.I_YELLOWARMOUR]: if self.armour >= itemstat.max: return False self.armour = min(self.armour + itemstat.add, itemstat.max) self.armourtype = itemstat.info elif item_type == item_types.I_QUAD: if self.has_quad: self._quadexpiry.extend(float(itemstat.add) / 1000.0, float(itemstat.max) / 1000.0) else: self._quadexpiry = Expiry(self.game_clock, float(itemstat.add) / 1000.0) else: # is an ammo if self.ammo[itemstat.info] >= itemstat.max: return False self.ammo[itemstat.info] = min(self.ammo[itemstat.info] + itemstat.add, itemstat.max) return True