class ConsoleInput(LineReceiver): name = 'Console' admin = True delimiter = b'\n' def __init__(self, protocol): self.protocol = protocol self.user_types = AttributeSet(['admin', 'console']) self.rights = AttributeSet() for user_type in self.user_types: self.rights.update(commands.get_rights(user_type)) def lineReceived(self, line): if not line: return try: result = commands.handle_input(self, line.decode()) # pylint: disable=broad-except except Exception: traceback.print_exc() else: if result is not None: print(result) # methods used to emulate the behaviour of regular Connection objects to # prevent errors when command writers didn't test that their scripts would # work when run on the console def send_chat(self, value: str, _): print(value) def send_lines(self, lines: List[str]): print("\n".join(lines))
class IRCClientFactory(protocol.ClientFactory): protocol = IRCBot lost_reconnect_delay = 20 failed_reconnect_delay = 60 bot = None aliases = None colors = True admin = None user_types = None rights = None def __init__(self, server, config): self.aliases = {} self.admin = True self.user_types = AttributeSet(['admin', 'irc']) self.rights = AttributeSet() for user_type in self.user_types: self.rights.update(commands.get_rights(user_type)) self.server = server self.nickname = config.get('nickname', 'piqueserver%s' % random.randrange(0, 99)) self.username = config.get('username', 'piqueserver') self.realname = config.get('realname', server.name) self.channel = config.get('channel', "#piqueserver.bots").lower() self.commandprefix = config.get('commandprefix', '.') self.chatprefix = config.get('chatprefix', '') self.password = config.get('password', '') or None def startedConnecting(self, connector): log.info("Connecting to IRC server...") def clientConnectionLost(self, connector, reason): log.info( "Lost connection to IRC server ({}), reconnecting in {} seconds". format(reason, self.lost_reconnect_delay)) reactor.callLater(self.lost_reconnect_delay, connector.connect) def clientConnectionFailed(self, connector, reason): log.info( "Could not connect to IRC server ({}), retrying in {} seconds". format(reason, self.failed_reconnect_delay)) reactor.callLater(self.failed_reconnect_delay, connector.connect) def buildProtocol(self, address): p = self.protocol() p.factory = self p.protocol = self.server self.bot = p return p
class IRCClientFactory(protocol.ClientFactory): protocol = IRCBot lost_reconnect_delay = 20 failed_reconnect_delay = 60 bot = None aliases = None colors = True admin = None user_types = None rights = None def __init__(self, server, config): self.aliases = {} self.admin = True self.user_types = AttributeSet(['admin', 'irc']) self.rights = AttributeSet() for user_type in self.user_types: self.rights.update(commands.rights.get(user_type, ())) self.server = server self.nickname = config.get('nickname', 'pyspades%s' % random.randrange(0, 99)).encode('ascii') self.username = config.get('username', 'pyspades').encode('ascii') self.realname = config.get('realname', server.name).encode('ascii') self.channel = config.get('channel', "#pyspades.bots").encode( 'ascii').lower() self.commandprefix = config.get('commandprefix', '.').encode('ascii') self.chatprefix = config.get('chatprefix', '').encode('ascii') self.password = config.get('password', '').encode('ascii') or None def startedConnecting(self, connector): print "Connecting to IRC server..." def clientConnectionLost(self, connector, reason): print "Lost connection to IRC server (%s), reconnecting in %s seconds" % ( reason, self.lost_reconnect_delay) reactor.callLater(self.lost_reconnect_delay, connector.connect) def clientConnectionFailed(self, connector, reason): print "Could not connect to IRC server (%s), retrying in %s seconds" % ( reason, self.failed_reconnect_delay) reactor.callLater(self.failed_reconnect_delay, connector.connect) def buildProtocol(self, address): p = self.protocol() p.factory = self p.protocol = self.server self.bot = p return p
class ConsoleInput(LineReceiver): name = 'Console' admin = True delimiter = b'\n' def __init__(self, protocol): self.protocol = protocol self.user_types = AttributeSet(['admin', 'console']) self.rights = AttributeSet() for user_type in self.user_types: self.rights.update(commands.get_rights(user_type)) def lineReceived(self, line): if not line: return result = commands.handle_input(self, line.decode()) if result is not None: print(result)
class ConsoleInput(LineReceiver): name = 'Console' admin = True delimiter = '\n' def __init__(self, protocol): self.protocol = protocol self.user_types = AttributeSet(['admin', 'console']) self.rights = AttributeSet() for user_type in self.user_types: self.rights.update(commands.get_rights(user_type)) def lineReceived(self, line): if line.startswith('/'): line = line[1:] result = commands.handle_input(self, line) if result is not None: print(result) else: self.protocol.send_chat(line)
class ConsoleInput(LineReceiver): name = 'Console' admin = True delimiter = '\n' def __init__(self, protocol): self.protocol = protocol self.user_types = AttributeSet(['admin', 'console']) self.rights = AttributeSet() for user_type in self.user_types: self.rights.update(commands.rights.get(user_type, ())) def lineReceived(self, line): if line.startswith('/'): line = line[1:] result = commands.handle_input(self, line) if result is not None: print result else: self.protocol.send_chat(line)
class FeatureConnection(ServerConnection): printable_name = None admin = False last_switch = None mute = False deaf = False login_retries = None god = False god_build = False fly = False invisible = False building = True killing = True streak = 0 best_streak = 0 last_chat = None chat_time = 0 chat_count = 0 user_types = None def on_connect(self): protocol = self.protocol client_ip = self.address[0] try: name, reason, timestamp = self.protocol.bans[client_ip] if timestamp is not None and reactor.seconds() >= timestamp: protocol.remove_ban(client_ip) protocol.save_bans() else: print 'banned user %s (%s) attempted to join' % (name, client_ip) self.disconnect(ERROR_BANNED) return except KeyError: pass manager = self.protocol.ban_manager if manager is not None: reason = manager.get_ban(client_ip) if reason is not None: print ('federated banned user (%s) attempted to join, ' 'banned for %r') % (client_ip, reason) self.disconnect(ERROR_BANNED) return ServerConnection.on_connect(self) def on_join(self): if self.protocol.motd is not None: self.send_lines(self.protocol.motd) def on_login(self, name): self.printable_name = name.encode('ascii', 'replace') print '%s (IP %s, ID %s) entered the game!' % (self.printable_name, self.address[0], self.player_id) self.protocol.irc_say('* %s entered the game' % self.name) if self.user_types is None: self.user_types = AttributeSet() self.rights = AttributeSet() if self.protocol.everyone_is_admin: self.on_user_login('admin', False) def get_spawn_location(self): get_location = self.protocol.map_info.get_spawn_location if get_location is not None: result = get_location(self) if result is not None: return result return ServerConnection.get_spawn_location(self) def on_disconnect(self): if self.name is not None: print self.printable_name, 'disconnected!' self.protocol.irc_say('* %s disconnected' % self.name) self.protocol.player_memory.append((self.name, self.address[0])) else: print '%s disconnected' % self.address[0] ServerConnection.on_disconnect(self) def on_command(self, command, parameters): result = commands.handle_command(self, command, parameters) if result == False: parameters = ['***'] * len(parameters) log_message = '<%s> /%s %s' % (self.name, command, ' '.join(parameters)) if result: log_message += ' -> %s' % result self.send_chat(result) print log_message.encode('ascii', 'replace') def _can_build(self): if not self.building: return False if not self.god and not self.protocol.building: return False def on_block_build_attempt(self, x, y, z): return self._can_build() def on_line_build_attempt(self, points): return self._can_build() def on_line_build(self, points): if self.god: self.refill() if self.god_build: if self.protocol.god_blocks is None: self.protocol.god_blocks = set() self.protocol.god_blocks.update(points) elif self.protocol.user_blocks is not None: self.protocol.user_blocks.update(points) def on_block_build(self, x, y, z): if self.god: self.refill() if self.god_build: if self.protocol.god_blocks is None: self.protocol.god_blocks = set() self.protocol.god_blocks.add((x, y, z)) elif self.protocol.user_blocks is not None: self.protocol.user_blocks.add((x, y, z)) def on_block_destroy(self, x, y, z, mode): map_on_block_destroy = self.protocol.map_info.on_block_destroy if map_on_block_destroy is not None: result = map_on_block_destroy(self, x, y, z, mode) if result == False: return result if not self.building: return False if not self.god: if not self.protocol.building: return False is_indestructable = self.protocol.is_indestructable if mode == DESTROY_BLOCK: if is_indestructable(x, y, z): return False elif mode == SPADE_DESTROY: if (is_indestructable(x, y, z) or is_indestructable(x, y, z + 1) or is_indestructable(x, y, z - 1)): return False elif mode == GRENADE_DESTROY: for nade_x in xrange(x - 1, x + 2): for nade_y in xrange(y - 1, y + 2): for nade_z in xrange(z - 1, z + 2): if is_indestructable(nade_x, nade_y, nade_z): return False def on_block_removed(self, x, y, z): if self.protocol.user_blocks is not None: self.protocol.user_blocks.discard((x, y, z)) if self.protocol.god_blocks is not None: self.protocol.god_blocks.discard((x, y, z)) def on_hit(self, hit_amount, player, type, grenade): if not self.protocol.killing: self.send_chat( "You can't kill anyone right now! Damage is turned OFF") return False if not self.killing: self.send_chat("%s. You can't kill anyone." % player.name) return False elif player.god: if not player.invisible: self.send_chat("You can't hurt %s! That player is in " "*god mode*" % player.name) return False if self.god: self.protocol.send_chat('%s, killing in god mode is forbidden!' % self.name, irc = True) self.protocol.send_chat('%s returned to being a mere human.' % self.name, irc = True) self.god = False self.god_build = False def on_kill(self, killer, type, grenade): self.streak = 0 if killer is None or self.team is killer.team: return if not grenade or grenade.name == 'grenade': # doesn't give streak kills on airstrikes (or other types of # explosions) killer.streak += 1 killer.best_streak = max(killer.streak, killer.best_streak) killer.team.kills += 1 def on_reset(self): self.streak = 0 self.best_streak = 0 def on_animation_update(self, jump, crouch, sneak, sprint): if self.fly and crouch and self.world_object.velocity.z != 0.0: jump = True return jump, crouch, sneak, sprint def on_fall(self, damage): if self.god: return False if not self.protocol.fall_damage: return False def on_grenade(self, time_left): if self.god: self.refill() def on_team_join(self, team): if self.team is not None: if self.protocol.teamswitch_interval: teamswitch_interval = self.protocol.teamswitch_interval if teamswitch_interval == 'never': self.send_chat('Switching teams is not allowed') return False if (self.last_switch is not None and reactor.seconds() - self.last_switch < teamswitch_interval * 60): self.send_chat('You must wait before switching teams again') return False if team.locked: self.send_chat('Team is locked') return False balanced_teams = self.protocol.balanced_teams if balanced_teams and not team.spectator: other_team = team.other if other_team.count() < team.count() + 1 - balanced_teams: self.send_chat('Team is full') return False self.last_switch = reactor.seconds() def on_chat(self, value, global_message): if not self.mute: current_time = reactor.seconds() if self.last_chat is None: self.last_chat = current_time else: self.chat_time += current_time - self.last_chat if self.chat_count > CHAT_WINDOW_SIZE: if self.chat_count / self.chat_time > CHAT_PER_SECOND: self.mute = True self.protocol.send_chat( '%s has been muted for excessive spam' % (self.name), irc = True) self.chat_time = self.chat_count = 0 else: self.chat_count += 1 self.last_chat = current_time message = '<%s> %s' % (self.name, value) if self.mute: message = '(MUTED) %s' % message elif global_message and self.protocol.global_chat: self.protocol.irc_say('<%s> %s' % (self.name, value)) print message.encode('ascii', 'replace') if self.mute: self.send_chat('(Chat not sent - you are muted)') return False elif global_message and not self.protocol.global_chat: self.send_chat('(Chat not sent - global chat disabled)') return False return value def kick(self, reason = None, silent = False): if not silent: if reason is not None: message = '%s was kicked: %s' % (self.name, reason) else: message = '%s was kicked' % self.name self.protocol.send_chat(message, irc = True) # FIXME: Client should handle disconnect events the same way in both # main and initial loading network loops self.disconnect(ERROR_KICKED + 8) def ban(self, reason = None, duration = None): reason = ': ' + reason if reason is not None else '' duration = duration or None if duration is None: message = '%s permabanned%s' % (self.name, reason) else: message = '%s banned for %s%s' % (self.name, prettify_timespan(duration * 60), reason) if self.protocol.on_ban_attempt(self, reason, duration): self.protocol.send_chat(message, irc = True) self.protocol.on_ban(self, reason, duration) if self.address[0]=="127.0.0.1": self.protocol.send_chat("Ban ignored: localhost") else: self.protocol.add_ban(self.address[0], reason, duration, self.name) def send_lines(self, lines): current_time = 0 for line in lines: reactor.callLater(current_time, self.send_chat, line) current_time += 2 def on_hack_attempt(self, reason): print 'Hack attempt detected from %s: %s' % (self.printable_name, reason) self.kick(reason) def on_user_login(self, user_type, verbose = True): if user_type == 'admin': self.admin = True self.speedhack_detect = False self.user_types.add(user_type) rights = set(commands.rights.get(user_type, ())) self.rights.update(rights) if verbose: message = ' logged in as %s' % (user_type) self.send_chat('You' + message) self.protocol.irc_say("* " + self.name + message) def timed_out(self): if self.name is not None: print '%s timed out' % self.printable_name ServerConnection.timed_out(self)
class FeatureConnection(ServerConnection): printable_name = None admin = False last_switch = None mute = False deaf = False login_retries = None god = False god_build = False fly = False invisible = False building = True killing = True streak = 0 best_streak = 0 last_chat = None chat_time = 0 chat_count = 0 user_types = None def on_connect(self): protocol = self.protocol client_ip = self.address[0] try: name, reason, timestamp, now = self.protocol.bans[client_ip] if timestamp is not None and reactor.seconds() >= timestamp: protocol.remove_ban(client_ip) protocol.save_bans() else: print 'banned user %s (%s) attempted to join' % (name, client_ip) self.disconnect(ERROR_BANNED) return except KeyError: pass manager = self.protocol.ban_manager if manager is not None: reason = manager.get_ban(client_ip) if reason is not None: print( 'federated banned user (%s) attempted to join, ' 'banned for %r') % (client_ip, reason) self.disconnect(ERROR_BANNED) return ServerConnection.on_connect(self) def on_join(self): if self.protocol.motd is not None: self.send_lines(self.protocol.motd) def on_login(self, name): self.printable_name = name.encode('ascii', 'replace') print '%s (IP %s, ID %s) entered the game!' % ( self.printable_name, self.address[0], self.player_id) self.protocol.irc_say('* %s (IP %s) entered the game' % (self.name, self.address[0])) if self.user_types is None: self.user_types = AttributeSet() self.rights = AttributeSet() if self.protocol.everyone_is_admin: self.on_user_login('admin', False) def get_spawn_location(self): get_location = self.protocol.map_info.get_spawn_location if get_location is not None: result = get_location(self) if result is not None: return result return ServerConnection.get_spawn_location(self) def on_disconnect(self): if self.name is not None: print self.printable_name, 'disconnected!' self.protocol.irc_say('* %s (IP %s) disconnected' % (self.name, self.address[0])) self.protocol.player_memory.append((self.name, self.address[0])) else: print '%s disconnected' % self.address[0] ServerConnection.on_disconnect(self) def on_command(self, command, parameters): result = commands.handle_command(self, command, parameters) if result == False: parameters = ['***'] * len(parameters) log_message = '<%s> /%s %s' % (self.name, command, ' '.join(parameters)) if result: log_message += ' -> %s' % result self.send_chat(result) print log_message.encode('ascii', 'replace') def _can_build(self): if not self.building: return False if not self.god and not self.protocol.building: return False def on_block_build_attempt(self, x, y, z): return self._can_build() def on_line_build_attempt(self, points): return self._can_build() def on_line_build(self, points): if self.god: self.refill() if self.god_build: if self.protocol.god_blocks is None: self.protocol.god_blocks = set() self.protocol.god_blocks.update(points) elif self.protocol.user_blocks is not None: self.protocol.user_blocks.update(points) def on_block_build(self, x, y, z): if self.god: self.refill() if self.god_build: if self.protocol.god_blocks is None: self.protocol.god_blocks = set() self.protocol.god_blocks.add((x, y, z)) elif self.protocol.user_blocks is not None: self.protocol.user_blocks.add((x, y, z)) def on_block_destroy(self, x, y, z, mode): map_on_block_destroy = self.protocol.map_info.on_block_destroy if map_on_block_destroy is not None: result = map_on_block_destroy(self, x, y, z, mode) if result == False: return result if not self.building: return False if not self.god: if not self.protocol.building: return False is_indestructable = self.protocol.is_indestructable if mode == DESTROY_BLOCK: if is_indestructable(x, y, z): return False elif mode == SPADE_DESTROY: if (is_indestructable(x, y, z) or is_indestructable(x, y, z + 1) or is_indestructable(x, y, z - 1)): return False elif mode == GRENADE_DESTROY: for nade_x in xrange(x - 1, x + 2): for nade_y in xrange(y - 1, y + 2): for nade_z in xrange(z - 1, z + 2): if is_indestructable(nade_x, nade_y, nade_z): return False def on_block_removed(self, x, y, z): if self.protocol.user_blocks is not None: self.protocol.user_blocks.discard((x, y, z)) if self.protocol.god_blocks is not None: self.protocol.god_blocks.discard((x, y, z)) def on_hit(self, hit_amount, player, type, grenade): if not self.protocol.killing: self.send_chat( "You can't kill anyone right now! Damage is turned OFF") return False if not self.killing: self.send_chat("%s. You can't kill anyone." % player.name) return False elif player.god: if not player.invisible: self.send_chat("You can't hurt %s! That player is in " "*god mode*" % player.name) return False if self.god: self.protocol.send_chat('%s, killing in god mode is forbidden!' % self.name, irc=True) self.protocol.send_chat('%s returned to being a mere human.' % self.name, irc=True) self.god = False self.god_build = False def on_kill(self, killer, type, grenade): self.streak = 0 if killer is None or self.team is killer.team: return if not grenade or grenade.name == 'grenade': # doesn't give streak kills on airstrikes (or other types of # explosions) killer.streak += 1 killer.best_streak = max(killer.streak, killer.best_streak) killer.team.kills += 1 def on_reset(self): self.streak = 0 self.best_streak = 0 def on_animation_update(self, jump, crouch, sneak, sprint): if self.fly and crouch and self.world_object.velocity.z != 0.0: jump = True return jump, crouch, sneak, sprint def on_fall(self, damage): if self.god: return False if not self.protocol.fall_damage: return False def on_grenade(self, time_left): if self.god: self.refill() def on_team_join(self, team): if self.team is not None: if self.protocol.teamswitch_interval: teamswitch_interval = self.protocol.teamswitch_interval if teamswitch_interval == 'never': self.send_chat('Switching teams is not allowed') return False if (self.last_switch is not None and reactor.seconds() - self.last_switch < teamswitch_interval * 60): self.send_chat( 'You must wait before switching teams again') return False if team.locked: self.send_chat('Team is locked') if not team.spectator and not team.other.locked: return team.other return False balanced_teams = self.protocol.balanced_teams if balanced_teams and not team.spectator: other_team = team.other if other_team.count() < team.count() + 1 - balanced_teams: if other_team.locked: return False self.send_chat('Team is full, moved to %s' % other_team.name) return other_team self.last_switch = reactor.seconds() def on_chat(self, value, global_message): if not self.mute: current_time = reactor.seconds() if self.last_chat is None: self.last_chat = current_time else: self.chat_time += current_time - self.last_chat if self.chat_count > CHAT_WINDOW_SIZE: if self.chat_count / self.chat_time > CHAT_PER_SECOND: self.mute = True self.protocol.send_chat( '%s has been muted for excessive spam' % (self.name), irc=True) self.chat_time = self.chat_count = 0 else: self.chat_count += 1 self.last_chat = current_time message = '<%s> %s' % (self.name, value) if self.mute: message = '(MUTED) %s' % message elif global_message and self.protocol.global_chat: self.protocol.irc_say('<%s> %s' % (self.name, value)) print message.encode('ascii', 'replace') if self.mute: self.send_chat('(Chat not sent - you are muted)') return False elif global_message and not self.protocol.global_chat: self.send_chat('(Chat not sent - global chat disabled)') return False return value def kick(self, reason=None, silent=False): if not silent: if reason is not None: message = '%s was kicked: %s' % (self.name, reason) else: message = '%s was kicked' % self.name self.protocol.send_chat(message, irc=False) self.protocol.irc_say('%s has been kicked by %s : %s ' % (self.name, connection.name, reason)) # FIXME: Client should handle disconnect events the same way in both # main and initial loading network loops self.disconnect(ERROR_KICKED + 8) def ban(self, reason=None, duration=None): reason = ': ' + reason if reason is not None else '' duration = duration or None if duration is None: message = '%s permabanned%s' % (self.name, reason) else: message = '%s banned for %s%s' % ( self.name, prettify_timespan(duration * 60), reason) if self.protocol.on_ban_attempt(self, reason, duration): self.protocol.irc_say('* %s %s' % (message)) self.protocol.on_ban(self, reason, duration) if self.address[0] == "127.0.0.1": self.protocol.send_chat("Ban ignored: localhost") else: self.protocol.add_ban(self.address[0], reason, duration, self.name) return '* %s %s' % message def send_lines(self, lines): current_time = 0 for line in lines: reactor.callLater(current_time, self.send_chat, line) current_time += 2 def on_hack_attempt(self, reason): print 'Hack attempt detected from %s: %s' % (self.printable_name, reason) self.kick(reason) def on_user_login(self, user_type, verbose=True): if user_type == 'admin': self.admin = True self.speedhack_detect = False self.user_types.add(user_type) rights = set(commands.rights.get(user_type, ())) self.rights.update(rights) if verbose: message = ' logged in as %s' % (user_type) self.send_chat('You' + message) self.protocol.irc_say("* " + self.name + message) def timed_out(self): if self.name is not None: print '%s timed out' % self.printable_name ServerConnection.timed_out(self)
class FeatureConnection(ServerConnection): def __init__(self, *args, **kwargs): self.printable_name = None self.admin = False self.last_switch = None self.mute = False self.deaf = False self.login_retries = None self.god = False self.god_build = False self.fly = False self.invisible = False self.building = True self.killing = True self.streak = 0 self.best_streak = 0 self.chat_limiter = RateLimiter(CHAT_WINDOW_SIZE, CHAT_WINDOW_SIZE / CHAT_PER_SECOND) self.user_types = None self.rights = None self.can_complete_line_build = True super().__init__(*args, **kwargs) def on_connect(self) -> None: protocol = self.protocol client_ip = self.address[0] if client_ip in self.protocol.bans: name, reason, timestamp = self.protocol.bans[client_ip] if timestamp is not None and reactor.seconds() >= timestamp: protocol.remove_ban(client_ip) protocol.save_bans() else: log.info('banned user {} ({}) attempted to join'.format( name, client_ip)) self.disconnect(ERROR_BANNED) return manager = self.protocol.ban_manager if manager is not None: reason = manager.get_ban(client_ip) if reason is not None: log.info(('federated banned user (%s) attempted to join, ' 'banned for %r') % (client_ip, reason)) self.disconnect(ERROR_BANNED) return ServerConnection.on_connect(self) def on_join(self) -> None: if self.protocol.motd is not None: self.send_lines(self.protocol.motd) def on_login(self, name: str) -> None: self.printable_name = escape_control_codes(name) if len(self.printable_name) > 15: self.kick(silent=True) log.info('{name} (IP {ip}, ID {pid}) entered the game!', name=self.printable_name, ip=self.address[0], pid=self.player_id) self.protocol.irc_say('* %s (IP %s, ID %s) entered the game!' % (self.name, self.address[0], self.player_id)) if self.user_types is None: self.user_types = AttributeSet() self.rights = AttributeSet() if self.protocol.everyone_is_admin: self.on_user_login('admin', False) def get_spawn_location(self) -> Tuple[int, int, int]: get_location = self.protocol.map_info.get_spawn_location if get_location is not None: result = get_location(self) if result is not None: return result return ServerConnection.get_spawn_location(self) def on_disconnect(self) -> None: if self.name is not None: log.info('{name} disconnected!', name=self.printable_name) self.protocol.irc_say('* %s (IP %s) disconnected' % (self.name, self.address[0])) self.protocol.player_memory.append((self.name, self.address[0])) else: log.info('{ip} disconnected', ip=self.address[0]) ServerConnection.on_disconnect(self) def on_command(self, command: str, parameters: List[str]) -> None: result = commands.handle_command(self, command, parameters) if result: for i in reversed(result.split("\n")): self.send_chat(i) def _can_build(self) -> bool: if not self.building: return False if not self.god and not self.protocol.building: return False return True def on_block_build_attempt(self, x: int, y: int, z: int) -> bool: return self._can_build() def on_line_build_attempt(self, points) -> bool: return self._can_build() def on_line_build(self, points) -> None: if self.god: self.refill() if self.god_build: if self.protocol.god_blocks is None: self.protocol.god_blocks = set() self.protocol.god_blocks.update(points) elif self.protocol.user_blocks is not None: self.protocol.user_blocks.update(points) def on_block_build(self, x: int, y: int, z: int) -> None: if self.god: self.refill() if self.god_build: if self.protocol.god_blocks is None: self.protocol.god_blocks = set() self.protocol.god_blocks.add((x, y, z)) elif self.protocol.user_blocks is not None: self.protocol.user_blocks.add((x, y, z)) def on_block_destroy(self, x: int, y: int, z: int, mode: int) -> bool: map_on_block_destroy = self.protocol.map_info.on_block_destroy if map_on_block_destroy is not None: result = map_on_block_destroy(self, x, y, z, mode) if result == False: return result if not self.building: return False if not self.god: if not self.protocol.building: return False is_indestructable = self.protocol.is_indestructable if mode == DESTROY_BLOCK: if is_indestructable(x, y, z): return False elif mode == SPADE_DESTROY: if (is_indestructable(x, y, z) or is_indestructable(x, y, z + 1) or is_indestructable(x, y, z - 1)): return False elif mode == GRENADE_DESTROY: for nade_x in range(x - 1, x + 2): for nade_y in range(y - 1, y + 2): for nade_z in range(z - 1, z + 2): if is_indestructable(nade_x, nade_y, nade_z): return False def on_block_removed(self, x: int, y: int, z: int) -> None: if self.protocol.user_blocks is not None: self.protocol.user_blocks.discard((x, y, z)) if self.protocol.god_blocks is not None: self.protocol.god_blocks.discard((x, y, z)) def on_hit(self, hit_amount: float, player: 'FeatureConnection', _type: int, grenade: Grenade) -> HookValue: if not self.protocol.killing: self.send_chat( "You can't kill anyone right now! Damage is turned OFF") return False if not self.killing: self.send_chat("%s. You can't kill anyone." % player.name) return False elif player.god: if not player.invisible: self.send_chat("You can't hurt %s! That player is in " "*god mode*" % player.name) return False if self.god: self.protocol.send_chat('%s, killing in god mode is forbidden!' % self.name, irc=True) self.protocol.send_chat('%s returned to being a mere human.' % self.name, irc=True) self.god = False self.god_build = False def on_kill(self, killer: Optional['FeatureConnection'], _type: int, grenade: None) -> None: self.streak = 0 if killer is None or self.team is killer.team: return if not grenade or grenade.name == 'grenade': # doesn't give streak kills on airstrikes (or other types of # explosions) killer.streak += 1 killer.best_streak = max(killer.streak, killer.best_streak) killer.team.kills += 1 def on_reset(self) -> None: self.streak = 0 self.best_streak = 0 def on_animation_update(self, jump: bool, crouch: bool, sneak: bool, sprint: bool) -> Tuple[bool, bool, bool, bool]: if self.fly and crouch and self.world_object.velocity.z != 0.0: jump = True return jump, crouch, sneak, sprint def on_fall(self, damage: int) -> HookValue: if self.god: return False if not self.protocol.fall_damage: return False def on_grenade(self, time_left: float) -> None: if self.god: self.refill() def on_team_join(self, team: Team) -> HookValue: if self.team is not None: if self.protocol.teamswitch_interval: teamswitch_interval = self.protocol.teamswitch_interval teamswitch_allowed = self.protocol.teamswitch_allowed if not teamswitch_allowed: self.send_chat('Switching teams is not allowed') return False if (self.last_switch is not None and reactor.seconds() - self.last_switch < teamswitch_interval): self.send_chat( 'You must wait before switching teams again') return False if team.locked: self.send_chat('Team is locked') if not team.spectator and not team.other.locked: return team.other return False balanced_teams = self.protocol.balanced_teams if balanced_teams and not team.spectator: other_team = team.other if other_team.count() < team.count() + 1 - balanced_teams: if other_team.locked: return False self.send_chat('Team is full, moved to %s' % other_team.name) return other_team self.last_switch = reactor.seconds() def on_chat(self, value: str, global_message: bool) -> Union[str, bool]: """ notifies when the server receives a chat message return False to block sending the message """ message = '<{}> {}'.format(self.name, value) if self.mute: message = '(MUTED) {}'.format(message) self.send_chat('(Chat not sent - you are muted)') return False if global_message: if self.protocol.global_chat: # forward message to IRC self.protocol.irc_say(message) else: self.send_chat('(Chat not sent - global chat disabled)') return False # antispam: current_time = reactor.seconds() self.chat_limiter.record_event(current_time) if self.chat_limiter.above_limit(): self.mute = True self.protocol.send_chat('%s has been muted for excessive spam' % (self.name), irc=True) log.info("<{name}> {message}", name=escape_control_codes(self.name), message=escape_control_codes(value)) return value def kick(self, reason=None, silent=False): if not silent: if reason is not None: message = '{} was kicked: {}'.format(self.name, reason) else: message = '%s was kicked' % self.name self.protocol.send_chat(message, irc=True) log.info(message) # FIXME: Client should handle disconnect events the same way in both # main and initial loading network loops self.disconnect(ERROR_KICKED) def ban(self, reason=None, duration=None): reason = ': ' + reason if reason is not None else '' duration = duration or None if duration is None: message = '{} permabanned{}'.format(self.name, reason) else: message = '{} banned for {}{}'.format(self.name, prettify_timespan(duration), reason) if self.protocol.on_ban_attempt(self, reason, duration): self.protocol.send_chat(message, irc=True) self.protocol.on_ban(self, reason, duration) if self.address[0] == "127.0.0.1": self.protocol.send_chat("Ban ignored: localhost") else: self.protocol.add_ban(self.address[0], reason, duration, self.name) def send_lines(self, lines: List[str]) -> None: current_time = 0 for line in lines: reactor.callLater(current_time, self.send_chat, line) current_time += 2 def on_hack_attempt(self, reason): log.warn('Hack attempt detected from {}: {}'.format( self.printable_name, reason)) self.kick(reason) def on_user_login(self, user_type, verbose=True): log.info("'{username}' logged in as {user_type}", username=self.name, user_type=user_type) if user_type == 'admin': self.admin = True self.speedhack_detect = False # notify of new release to admin on /login new_release = self.protocol.new_release if user_type == 'admin' and new_release: self.send_chat("!" * 30) self.send_chat(format_release(new_release)) self.send_chat("!" * 30) self.user_types.add(user_type) rights = set(commands.get_rights(user_type)) self.rights.update(rights) if verbose: message = ' logged in as %s' % (user_type) self.send_chat('You' + message) self.protocol.irc_say("* " + self.name + message) def timed_out(self): if self.name is not None: log.info('%s timed out' % self.printable_name) ServerConnection.timed_out(self)
class IRCBot(irc.IRCClient): owners = None admins = None moderators = None guards = None voices = None unaliased_name = None def _get_nickname(self): return self.factory.nickname nickname = property(_get_nickname) def _get_colors(self): return self.factory.colors colors = property(_get_colors) def _get_admin(self): return self.factory.admin admin = property(_get_admin) def _get_user_types(self): return self.factory.user_types user_types = property(_get_user_types) def _get_rights(self): return self.factory.rights rights = property(_get_rights) def signedOn(self): self.join(self.factory.channel, self.factory.password) def joined(self, channel): if channel.lower() == self.factory.channel: self.owners = set() self.admins = set() self.moderators = set() self.guards = set() self.voices = set() print "Joined channel %s" % channel def irc_NICK(self, prefix, params): user = prefix.split('!', 1)[0] new_user = params[0] if user in self.owners: self.owners.discard(user) self.owners.add(new_user) if user in self.admins: self.admins.discard(user) self.admins.add(new_user) if user in self.moderators: self.moderators.discard(user) self.moderators.add(new_user) if user in self.guards: self.guards.discard(user) self.guards.add(new_user) if user in self.voices: self.voices.discard(user) self.voices.add(new_user) def irc_RPL_NAMREPLY(self, *arg): if not arg[1][2].lower() == self.factory.channel: return for name in arg[1][3].split(): mode = name[0] l = {'~': self.owners, '&': self.admins, '@': self.moderators, '%': self.guards, '+': self.voices} if mode in l: l[mode].add(name[1:]) def left(self, channel): if channel.lower() == self.factory.channel: self.owners = None self.admins = None self.moderators = None self.guards = None self.voices = None @channel def modeChanged(self, user, channel, set, modes, args): ll = {'q' : self.owners, 'a' : self.admins, 'o' : self.moderators, 'h' : self.guards, 'v' : self.voices} for i in range(len(args)): mode, name = modes[i], args[i] if mode not in ll: continue l = ll[mode] if set: l.add(name) elif not set: l.discard(name) @channel def privmsg(self, user, channel, msg): if (user in self.owners or user in self.admins or user in self.moderators or user in self.guards or user in self.voices): if user in self.owners: prefix = '~' user_type = 'admin' elif user in self.admins: prefix = '&' user_type = 'admin' elif user in self.moderators: prefix = '@' user_type = 'moderator' elif user in self.guards: prefix = '%' user_type = 'guard' else: prefix = '+' user_type = 'none' alias = self.factory.aliases.get(user, user) if msg.startswith(self.factory.commandprefix) and ( user in self.owners or user in self.admins or user in self.moderators or user in self.guards): self.unaliased_name = user self.name = prefix + alias input = msg[len(self.factory.commandprefix):] rights = self.rights self.rights = AttributeSet() self.rights.update(commands.rights.get(user_type, ())) self.rights.update(commands.rights.get('irc', ())) result = commands.handle_input(self, input) self.rights = rights if result is not None: self.send("%s: %s" % (user, result)) elif msg.startswith(self.factory.chatprefix): max_len = MAX_IRC_CHAT_SIZE - len(self.protocol.server_prefix) - 1 msg = msg[len(self.factory.chatprefix):].strip() message = ("<%s> %s" % (prefix + alias, msg))[:max_len] message = message.decode('cp1252') print message.encode('ascii', 'replace') self.factory.server.send_chat(encode(message)) @channel def userLeft(self, user, channel): self.owners.discard(user) self.admins.discard(user) self.moderators.discard(user) self.guards.discard(user) self.voices.discard(user) def userQuit(self, user, message): self.userLeft(user, self.factory.channel) def userKicked(self, kickee, channel, kicker, message): self.userLeft(kickee, channel) def send(self, msg, filter = False): msg = msg.encode('cp1252', 'replace') if filter: msg = filter_printable(msg) self.msg(self.factory.channel, msg) def me(self, msg, filter = False): msg = msg.encode('cp1252', 'replace') if filter: msg = filter_printable(msg) self.describe(self.factory.channel, msg)