def __init__(self, interface: bytes, config_dict: Dict[str, Any]) -> None: # logfile path relative to config dir if not abs path log_filename = logfile.get() if log_filename.strip(): # catches empty filename if not os.path.isabs(log_filename): log_filename = os.path.join(config.config_dir, log_filename) ensure_dir_exists(log_filename) if logging_rotate_daily.get(): logging_file = DailyLogFile(log_filename, '.') else: logging_file = open(log_filename, 'a') predicate = LogLevelFilterPredicate( LogLevel.levelWithName(loglevel.get())) observers = [ FilteringLogObserver(textFileLogObserver(sys.stderr), [predicate]), FilteringLogObserver(textFileLogObserver(logging_file), [predicate]) ] globalLogBeginner.beginLoggingTo(observers) log.info('piqueserver started on %s' % time.strftime('%c')) self.config = config_dict if random_rotation.get(): self.map_rotator_type = random_choice_cycle else: self.map_rotator_type = itertools.cycle self.default_time_limit = default_time_limit.get() self.default_cap_limit = cap_limit.get() self.advance_on_win = int(advance_on_win.get()) self.win_count = itertools.count(1) self.bans = NetworkDict() # attempt to load a saved bans list try: with open(os.path.join(config.config_dir, bans_file.get()), 'r') as f: self.bans.read_list(json.load(f)) log.debug("loaded {count} bans", count=len(self.bans)) except FileNotFoundError: log.debug("skip loading bans: file unavailable", count=len(self.bans)) except IOError as e: log.error('Could not read bans.txt: {}'.format(e)) except ValueError as e: log.error('Could not parse bans.txt: {}'.format(e)) self.hard_bans = set() # possible DDoS'ers are added here self.player_memory = deque(maxlen=100) if len(self.name) > MAX_SERVER_NAME_SIZE: log.warn('(server name too long; it will be truncated to "%s")' % (self.name[:MAX_SERVER_NAME_SIZE])) self.respawn_time = respawn_time_option.get() self.respawn_waves = respawn_waves.get() # since AoS only supports CTF and TC at a protocol level, we need to get # the base game mode if we are using a custom game mode. game_mode_name = game_mode.get() if game_mode_name == 'ctf': self.game_mode = CTF_MODE elif game_mode.get() == 'tc': self.game_mode = TC_MODE elif self.game_mode not in [CTF_MODE, TC_MODE]: raise ValueError( 'invalid game mode: custom game mode "{}" does not set ' 'protocol.game_mode to one of TC_MODE or CTF_MODE. Are ' 'you sure the thing you have specified is a game mode?'.format( game_mode_name)) self.game_mode_name = game_mode.get().split('.')[-1] self.team1_name = team1_name.get()[:9] self.team2_name = team2_name.get()[:9] self.team1_color = tuple(team1_color.get()) self.team2_color = tuple(team2_color.get()) self.friendly_fire = friendly_fire.get() self.friendly_fire_on_grief = friendly_fire_on_grief.get() self.friendly_fire_time = grief_friendly_fire_time.get() self.spade_teamkills_on_grief = spade_teamkills_on_grief.get() self.fall_damage = fall_damage.get() self.teamswitch_interval = teamswitch_interval.get() self.teamswitch_allowed = teamswitch_allowed.get() self.max_players = max_players.get() self.melee_damage = melee_damage.get() self.max_connections_per_ip = max_connections_per_ip.get() self.passwords = passwords.get() self.server_prefix = server_prefix.get() self.time_announcements = time_announcements.get() self.balanced_teams = balanced_teams.get() self.login_retries = login_retries.get() # voting configuration self.default_ban_time = default_ban_duration.get() self.speedhack_detect = speedhack_detect.get() self.rubberband_distance = rubberband_distance.get() if user_blocks_only.get(): self.user_blocks = set() self.set_god_build = set_god_build.get() self.debug_log = debug_log_enabled.get() if self.debug_log: # TODO: make this configurable pyspades.debug.open_debug_log( os.path.join(config.config_dir, 'debug.log')) if ssh_enabled.get(): from piqueserver.ssh import RemoteConsole self.remote_console = RemoteConsole(self) irc = irc_options.get() if irc.get('enabled', False): from piqueserver.irc import IRCRelay self.irc_relay = IRCRelay(self, irc) if status_server_enabled.get(): from piqueserver.statusserver import StatusServer self.status_server = StatusServer(self) ensureDeferred(self.status_server.listen()) if ban_publish.get(): from piqueserver.banpublish import PublishServer self.ban_publish = PublishServer(self, ban_publish_port.get()) if bans_urls.get(): from piqueserver import bansubscribe self.ban_manager = bansubscribe.BanManager(self) self.start_time = time.time() self.end_calls = [] # TODO: why is this here? create_console(self) for user_type, func_names in rights.get().items(): for func_name in func_names: commands.add_rights(user_type, func_name) self.port = port_option.get() ServerProtocol.__init__(self, self.port, interface) self.host.intercept = self.receive_callback try: self.set_map_rotation(self.config['rotation']) except MapNotFound as e: log.critical('Invalid map in map rotation (%s), exiting.' % e.map) raise SystemExit map_load_d = self.advance_rotation() # discard the result of the map advance for now map_load_d.addCallback(lambda x: self._post_init()) ip_getter = ip_getter_option.get() if ip_getter: ensureDeferred(as_deferred(self.get_external_ip(ip_getter))) self.new_release = None notify_new_releases = config.option("release_notifications", default=True) if notify_new_releases.get(): ensureDeferred(as_deferred(self.watch_for_releases())) self.vacuum_loop = LoopingCall(self.vacuum_bans) # Run the vacuum every 6 hours, and kick it off it right now self.vacuum_loop.start(60 * 60 * 6, True) reactor.addSystemEventTrigger('before', 'shutdown', lambda: ensureDeferred(self.shutdown()))
""" Protects players when they first spawn for a given time CONFIG SETTING EXAMPLE for 3 seconds of protection "spawn_protection_time": 3 Script by Rugg """ from pyspades.constants import FALL_KILL from piqueserver.config import config from twisted.internet import reactor spawntimer_config = config.option('spawn_protection_time', default=3) def apply_script(protocol, connection, config): class invincibilityConnection(connection): invulnerable = True spawntimer = None protectionTime = spawntimer_config.get() def on_shoot_set(self, fire): if fire and self.invulnerable: self.invulnerable = False connection.on_shoot_set(self, fire) def on_hit(self, hit_amount, hit_player, kill_type, grenade): if hit_player.invulnerable: return False connection.on_hit(self, hit_amount, hit_player, kill_type, grenade)
def sleep(secs): return deferLater(reactor, secs, lambda: None) # declare configuration options bans_config = config.section('bans') logging_config = config.section('logging') team1_config = config.section('team1') team2_config = config.section('team2') bans_file = bans_config.option('file', default='bans.txt') bans_urls = bans_config.option('urls', []) respawn_time_option = config.option('respawn_time', default="8sec", cast=cast_duration) respawn_waves = config.option('respawn_waves', default=False) game_mode = config.option('game_mode', default='ctf') random_rotation = config.option('random_rotation', default=False) passwords = config.option('passwords', default={}) logfile = logging_config.option('logfile', default='./logs/log.txt') loglevel = logging_config.option('loglevel', default='info') map_rotation = config.option('rotation', default=['classicgen', 'random'], validate=lambda x: isinstance(x, list)) default_time_limit = config.option('default_time_limit', default="20min", cast=lambda x: cast_duration(x) / 60) cap_limit = config.option('cap_limit', default=10,
from piqueserver.config import config from twisted.internet import reactor from pyspades.constants import FALL_KILL from twisted.internet.error import AlreadyCalled sectionConfig = config.section('regen') regenDelay = sectionConfig.option('regenDelay', default=5.0).get() healSpeed = sectionConfig.option('healSpeed', default=0.05).get() healAmount = sectionConfig.option('healAmount', default=1.0).get() friendly_fire = config.option('friendly_fire', default=True).get() def apply_script(protocol, connection, config): class regenConnection(connection): regenCallID = None def regen(self): if (self.hp is not None): connection.set_hp(self, self.hp + healAmount, kill_type=FALL_KILL) self.regenCallID = reactor.callLater(healSpeed, self.regen) def stopRegen(self): try: self.regenCallID.cancel() except AttributeError as aterr: pass except AlreadyCalled as acerr: pass
from PIL import Image from io import BytesIO from aiohttp.abc import AbstractAccessLogger from twisted.logger import Logger from piqueserver.utils import as_deferred from piqueserver.config import config, cast_duration status_server_config = config.section("status_server") host_option = status_server_config.option("host", "0.0.0.0") port_option = status_server_config.option("port", 32886) logging_option = status_server_config.option("logging", False) interval_option = status_server_config.option("update_interval", default="1min", cast=cast_duration) scripts_option = config.option("scripts", []) class AccessLogger(AbstractAccessLogger): def log(self, request, response, time): self.logger.info( "{remote} {method} {url}: {status} {time:0.2f}ms -- {ua}", remote=request.remote, ua=request.headers["User-Agent"], method=request.method, url=request.url, time=time * 1000, status=response.status) async def set_default_headers(request, response):
MELEE, HIT_TOLERANCE, MELEE_DISTANCE, MELEE_KILL, HEAD, HEADSHOT_KILL, WEAPON_KILL) from pyspades.team import Team from pyspades.constants import * from pyspades.packet import call_packet_handler, register_packet_handler from pyspades import contained as loaders from pyspades.collision import vector_collision, collision_3d from pyspades import world from pyspades.common import Vertex3, get_color, make_color from pyspades.weapon import WEAPONS from pyspades.mapgenerator import ProgressiveMapGenerator from piqueserver.config import config log = Logger() # distance the server tolerates between the place it thinks the client is to where the client actually is. rubberband_distance = config.option('rubberband_distance', default=10) set_tool = loaders.SetTool() block_action = loaders.BlockAction() position_data = loaders.PositionData() restock = loaders.Restock() create_player = loaders.CreatePlayer() intel_pickup = loaders.IntelPickup() intel_capture = loaders.IntelCapture() intel_drop = loaders.IntelDrop() player_left = loaders.PlayerLeft() set_hp = loaders.SetHP() existing_player = loaders.ExistingPlayer() kill_action = loaders.KillAction() chat_message = loaders.ChatMessage() map_data = loaders.MapChunk()
seen.add(script) if dups: log.warn("Scripts included multiple times: {}".format(dups)) return False return True # declare configuration options bans_config = config.section('bans') logging_config = config.section('logging') team1_config = config.section('team1') team2_config = config.section('team2') bans_file = bans_config.option('file', default='bans.txt') bans_urls = bans_config.option('urls', []) respawn_time_option = config.option('respawn_time', default=8) respawn_waves = config.option('respawn_waves', default=False) game_mode = config.option('game_mode', default='ctf') random_rotation = config.option('random_rotation', default=False) passwords = config.option('passwords', default={}) logfile = logging_config.option('logfile', default='./logs/log.txt') map_rotation = config.option('rotation', default=['classicgen', 'random'], validate=lambda x: isinstance(x, list)) default_time_limit = config.option( 'default_time_limit', default=20, validate=lambda x: isinstance(x, (int, float))) cap_limit = config.option('cap_limit', default=10, validate=lambda x: isinstance(x, (int, float)))
Gives the player infinite blocks and a given amount of grenades CONFIG SETTING EXAMPLE for 5 grenades "starting_grenades": 5, Script by Rugg """ import math from twisted.internet import reactor from pyspades.constants import GRENADE_KILL from pyspades.contained import * from pyspades.constants import BLOCK_TOOL from pyspades import contained as loaders from piqueserver.config import config grenades_config = config.option('starting_grenades', default = 3) def apply_script(protocol, connection, config): class EnterConnection(connection): startinggrenades = grenades_config.get() grenadecount = 0 def on_spawn(self, position): self.grenadecount = self.startinggrenades connection.on_spawn(self, position) def on_grenade_thrown(self, grenade): self.grenadecount -= 1 if(self.grenadecount<-4): grenade.fuse = 500000 connection.send_chat(self, "You have thrown too many dud grenades.",global_message = False) connection.kill(self)