diff --git a/bootstrap.py b/bootstrap.py index 40b28b3..b7e4721 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -1,32 +1,36 @@ import asyncio import logging import argparse -import config from houdini.houdini import Houdini -from houdini.constants import ConflictResolution, Language, ClientType +from houdini.constants import Language, ConflictResolution, ClientType if __name__ == '__main__': logger = logging.getLogger('houdini') parser = argparse.ArgumentParser(description='Boot a Houdini server') - parser.add_argument('server', action='store', default='Login', - help='Name of the server to boot') + parser.add_argument('type', action='store', default='login', + choices=['login', 'world'], help='Name of the server to boot') - parser.add_argument('-id', action='store', help='Houdini server ID') - parser.add_argument('-a', '--address', action='store', help='Houdini server address') - parser.add_argument('-p', '--port', action='store', help='Houdini server port', type=int) - parser.add_argument('-c', '--capacity', action='store', help='Houdini server capacity', type=int) - parser.add_argument('-C', '--cache-expiry', dest='cache_expiry', action='store', + parser.add_argument('-id', action='store', default=3100, type=int, help='Houdini server ID') + parser.add_argument('-n', '--name', action='store', help='Houdini server name') + parser.add_argument('-a', '--address', action='store', default='0.0.0.0', + help='Houdini server address') + parser.add_argument('-p', '--port', action='store', help='Houdini server port', default=None, type=int) + parser.add_argument('-c', '--capacity', action='store', default=200, + help='Houdini server capacity', type=int) + parser.add_argument('-C', '--cache-expiry', dest='cache_expiry', action='store', default=3600, help='Cache expiry (seconds)', type=int) - parser.add_argument('-P', '--plugins', action='store', + parser.add_argument('-P', '--plugins', action='store', default='*', nargs='*', help='Plugins to load') - parser.add_argument('-l', '--language', action='store', help='Houdini language', - choices=['En', 'Fr', 'Pt', 'Es', 'De', 'Ru']) + parser.add_argument('-l', '--lang', action='store', default='en', help='Houdini language', + choices=['en', 'fr', 'pt', 'es', 'de', 'ru']) - boot_modes = parser.add_mutually_exclusive_group() - boot_modes.add_argument('-W', '--world', action='store_true', help='Run server in world mode') - boot_modes.add_argument('-L', '--login', action='store_true', help='Run server in login mode') + login_group = parser.add_argument_group('login') + login_group.add_argument('--login-failure-limit', action='store', default=5, help='Limit before flood limit', + type=int) + login_group.add_argument('--login-failure-timer', action='store', default=3600, help='Timeout after flood limit', + type=int) logging_group = parser.add_argument_group('logging') logging_group.add_argument('-lg', '--logging-general', action='store', @@ -36,139 +40,95 @@ if __name__ == '__main__': dest='logging_error_path', help='Error log path') logging_group.add_argument('-ll', '--logging-level', action='store', + default='INFO', dest='logging_level', help='Logging level') database_group = parser.add_argument_group('database') database_group.add_argument('-da', '--database-address', action='store', dest='database_address', - default=config.database['Address'], + default='localhost', help='Postgresql database address') database_group.add_argument('-du', '--database-username', action='store', dest='database_username', - default=config.database['Username'], + default='postgres', help='Postgresql database username') database_group.add_argument('-dp', '--database-password', action='store', dest='database_password', - default=config.database['Password'], + default='password', help='Postgresql database password') database_group.add_argument('-dn', '--database-name', action='store', dest='database_name', - default=config.database['Name'], + default='postgres', help='Postgresql database name') redis_group = parser.add_argument_group('redis') redis_group.add_argument('-ra', '--redis-address', action='store', dest='redis_address', - default=config.redis['Address'], + default='localhost', help='Redis server address') redis_group.add_argument('-rp', '--redis-port', action='store', dest='redis_port', type=int, - default=config.redis['Port'], + default=6379, help='Redis server port') command_group = parser.add_argument_group('commands') command_group.add_argument('-cp', '--command-prefix', action='store', dest='command_prefix', nargs='*', - default=config.commands['Prefix'], + default=['!', '?', '.'], help='Command prefixes') command_group.add_argument('-csd', '--command-string-delimiters', action='store', dest='command_string_delimiters', nargs='*', - default=config.commands['StringDelimiters'], + default=['"', "'"], help='Command string delimiters') command_group.add_argument('-ccm', '--command-conflict-mode', action='store', dest='command_conflict_mode', - default=config.commands['ConflictMode'].name, - help='Command conflict mode', choices=['Silent', 'Append', 'Exception']) + default='silent', + help='Command conflict mode', choices=['silent', 'append', 'exception']) + + games_group = parser.add_argument_group('games') + games_group.add_argument('--max-coins', action='store', + default=1000000, type=int, help='Max coins earnable') + games_group.add_argument('--max-coins-per-min', action='store', + default=250, type=int, help='Max coins per min') client_group = parser.add_argument_group('client') client_mode = client_group.add_mutually_exclusive_group() - client_mode.add_argument('--multi-client-mode', action='store_true', - help='Run server with support for both clients') client_mode.add_argument('--single-client-mode', action='store_true', - help='Run server with support for default client only') + help='Run server with support for default client only') client_group.add_argument('--legacy-version', action='store', type=int, - default=config.client['LegacyVersionChk'], + default=153, help='Legacy client version to identify legacy clients') client_group.add_argument('--vanilla-version', action='store', type=int, - default=config.client['VanillaVersionChk'], + default=253, help='Vanilla client version to identify vanilla clients') client_group.add_argument('--default-version', action='store', type=int, - default=config.client['DefaultVersionChk'], + default=153, help='Default version to identify clients when multi-client is off') client_group.add_argument('--default-client', action='store', - choices=['Legacy', 'Vanilla'], - default=config.client['DefaultClientType'].name, + choices=['legacy', 'vanilla'], + default='legacy', help='Default client when multi-client is off') client_group.add_argument('-k', '--auth-key', action='store', default='houdini', help='Static key to use in place of the deprecated random key') + client_group.add_argument('-kt', '--auth-ttl', action='store', type=int, default=3000, + help='Auth key TTL (seconds)') args = parser.parse_args() - database = { - 'Address': args.database_address, - 'Username': args.database_username, - 'Password': args.database_password, - 'Name': args.database_name - } + args.port = args.port if args.port else 9875 if args.type == 'world' else 6112 + args.name = args.name if args.name else 'World' if args.type == 'world' else 'Login' + args.lang = dict(en=Language.En, fr=Language.Fr, pt=Language.Pt, + es=Language.Es, de=Language.De, ru=Language.Ru).get(args.lang) + args.command_conflict_mode = dict(silent=ConflictResolution.Silent, append=ConflictResolution.Append, + exception=ConflictResolution.Exception).get(args.command_conflict_mode) + args.default_client = dict(legacy=ClientType.Legacy, vanilla=ClientType.Vanilla).get(args.default_client) - redis = { - 'Address': args.redis_address, - 'Port': args.redis_port - } - - commands = { - 'Prefix': args.command_prefix, - 'StringDelimiters': args.command_string_delimiters, - 'ConflictMode': getattr(ConflictResolution, args.command_conflict_mode) - } - - client = { - 'MultiClientSupport': True if args.multi_client_mode else False if args.single_client_mode - else config.client['MultiClientSupport'], - 'LegacyVersionChk': args.legacy_version, - 'VanillaVersionChk': args.vanilla_version, - - 'DefaultVersionChk': args.default_version, - 'DefaultClientType': getattr(ClientType, args.default_client), - - 'AuthStaticKey': args.auth_key - } - - server = { - 'Address': args.address or config.servers[args.server]['Address'], - 'Port': args.port or config.servers[args.server]['Port'], - 'World': True if args.world else False if args.login else None or config.servers[args.server]['World'], - 'Plugins': True if args.plugins and '*' in args.plugins - else args.plugins or config.servers[args.server]['Plugins'] - } - - logging = { - 'General': args.logging_general_path or config.servers[args.server]['Logging']['General'], - 'Errors': args.logging_error_path or config.servers[args.server]['Logging']['Errors'], - 'Level': args.logging_level or config.servers[args.server]['Logging']['Level'] - } - - if server['World']: - server.update({ - 'Id': args.id or config.servers[args.server]['Id'], - 'Language': getattr(Language, args.language) if args.language else config.servers[args.server]['Language'], - 'Capacity': args.capacity or config.servers[args.server]['Capacity'], - 'CacheExpiry': args.cache_expiry or config.servers[args.server]['CacheExpiry'] - }) - - server['Logging'] = logging - - factory_instance = Houdini(args.server, - database=database, - redis=redis, - commands=commands, - client=client, - server=server) + factory_instance = Houdini(args) try: asyncio.run(factory_instance.start()) except KeyboardInterrupt: diff --git a/config.sample.py b/config.sample.py deleted file mode 100644 index 6f36321..0000000 --- a/config.sample.py +++ /dev/null @@ -1,65 +0,0 @@ -from houdini.constants import ConflictResolution, Language, ClientType - -database = { - 'Address': 'localhost', - 'Username': 'postgres', - 'Password': 'password', - 'Name': 'houdini', -} - -redis = { - 'Address': '127.0.0.1', - 'Port': 6379 -} - -commands = { - 'Prefix': ['!', '?', '.'], - 'StringDelimiters': ['"', "'"], - 'ConflictMode': ConflictResolution.Silent -} - -client = { - 'MultiClientSupport': True, - 'LegacyVersionChk': 153, - 'VanillaVersionChk': 253, - - 'DefaultVersionChk': 253, - 'DefaultClientType': ClientType.Vanilla, - - 'AuthStaticKey': 'houdini' -} - -servers = { - 'Login': { - 'Address': '0.0.0.0', - 'Port': 6112, - 'World': False, - 'Plugins': [ - 'Example' - ], - 'Logging': { - 'General': 'logs/login.log', - 'Errors': 'logs/login-errors.log', - 'Level': 'DEBUG' - }, - 'LoginFailureLimit': 5, - 'LoginFailureTimer': 3600, - 'KeyTTL': 3000 - }, - 'Blizzard': { - 'Id': '100', - 'Address': '0.0.0.0', - 'Port': 9875, - 'Language': Language.En, - 'World': True, - 'Capacity': 200, - 'CacheExpiry': 3600, - 'Plugins': [ - ], - 'Logging': { - 'General': 'logs/blizzard.log', - 'Errors': 'logs/blizzard-errors.log', - 'Level': 'INFO' - } - } -} diff --git a/houdini/commands.py b/houdini/commands.py index c528741..4a9f3e6 100644 --- a/houdini/commands.py +++ b/houdini/commands.py @@ -1,5 +1,4 @@ import inspect -import config from houdini import handlers from houdini import plugins @@ -46,12 +45,12 @@ class _CommandGroup(_Command): def command(name=None, **kwargs): - return _listener(_Command, name, string_delimiter=config.commands['StringDelimiters'], + return _listener(_Command, name, string_delimiter=['"', "'"], string_separator=' ', **kwargs) def group(name=None, **kwargs): - return _listener(_CommandGroup, name, string_delimiter=config.commands['StringDelimiters'], + return _listener(_CommandGroup, name, string_delimiter=['"', "'"], string_separator=' ', **kwargs) @@ -59,7 +58,6 @@ cooldown = handlers.cooldown check = handlers.check player_attribute = handlers.player_attribute -player_data_attribute = handlers.player_data_attribute player_in_room = handlers.player_in_room @@ -84,13 +82,14 @@ class CommandManager(_AbstractManager): for name in command_object.alias: if name in parent_commands and len(parent_commands[name]): conflict_command = parent_commands[name][0] - if config.commands['ConflictMode'] == ConflictResolution.Exception: + conflict_resolution = self.server.config.command_conflict_mode + if conflict_resolution == ConflictResolution.Exception: raise NameError(f'Command name conflict: \'{name}\' from plugin \'{module.__class__.__name__}\' ' f'conflicts with \'{conflict_command.name}\' from ' f'module \'{conflict_command.instance.__class__.__name__}\'') - elif config.commands['ConflictMode'] == ConflictResolution.Append: + elif conflict_resolution == ConflictResolution.Append: parent_commands[name].append(command_object) - elif config.commands['ConflictMode'] == ConflictResolution.Silent: + elif conflict_resolution == ConflictResolution.Silent: module.server.logger.warning(f'Command \'{name}\' from module \'{module.__class__.__name__}\' ' f'disabled due to conflict with ' f'\'{conflict_command.instance.__class__.__name__}\'') @@ -102,25 +101,21 @@ def is_command(command_object): return issubclass(type(command_object), _Command) -if type(config.commands['Prefix']) == str: - config.commands['Prefix'] = [config.commands['Prefix']] - - -def has_command_prefix(command_string): - for prefix in config.commands['Prefix']: +def has_command_prefix(pre, command_string): + for prefix in pre: if command_string.startswith(prefix): return True return False -def get_command_prefix(command_string): - for prefix in config.commands['Prefix']: +def get_command_prefix(pre, command_string): + for prefix in pre: if command_string.startswith(prefix): return prefix async def invoke_command_string(commands, p, command_string): - prefix = get_command_prefix(command_string) + prefix = get_command_prefix(p.server.config.command_prefix, command_string) no_prefix = command_string[len(prefix):] data = no_prefix.split(' ') diff --git a/houdini/handlers/login/__init__.py b/houdini/handlers/login/__init__.py index 5ce7339..1adfbf7 100644 --- a/houdini/handlers/login/__init__.py +++ b/houdini/handlers/login/__init__.py @@ -1,5 +1,3 @@ -import config - from houdini import handlers from houdini.handlers import XMLPacket from houdini.converters import VersionChkConverter @@ -11,13 +9,13 @@ from houdini.data.buddy import BuddyList @handlers.handler(XMLPacket('verChk')) @handlers.allow_once async def handle_version_check(p, version: VersionChkConverter): - if config.client['MultiClientSupport']: - if config.client['LegacyVersionChk'] == version: + if not p.server.config.single_client_mode: + if p.server.config.legacy_version == version: p.client_type = ClientType.Legacy - elif config.client['VanillaVersionChk'] == version: + elif p.server.config.vanilla_version == version: p.client_type = ClientType.Vanilla - elif config.client['DefaultVersionChk'] == version: - p.client_type = config.client['DefaultClientType'] + elif p.server.config.default_version == version: + p.client_type = p.server.config.default_version if p.client_type is None: await p.send_xml({'body': {'action': 'apiKO', 'r': '0'}}) @@ -28,32 +26,31 @@ async def handle_version_check(p, version: VersionChkConverter): @handlers.handler(XMLPacket('rndK')) @handlers.allow_once -async def handle_random_key(p, data): - await p.send_xml({'body': {'action': 'rndK', 'r': '-1'}, 'k': config.client['AuthStaticKey']}) +async def handle_random_key(p, _): + await p.send_xml({'body': {'action': 'rndK', 'r': '-1'}, 'k': p.server.config.auth_key}) async def get_server_presence(p, pid): buddy_worlds = [] world_populations = [] - for server_name, server_config in config.servers.items(): - if server_config['World']: - server_population = await p.server.redis.hget('houdini.population', server_config['Id']) - server_population = (7 if int(server_population) == server_config['Capacity'] - else int(server_population) // (server_config['Capacity'] // 6)) \ - if server_population else 0 + pops = await p.server.redis.hgetall('houdini.population') + for server_id, server_population in pops.items(): + server_population = (7 if int(server_population) == p.server.config.capacity + else int(server_population) // (p.server.config.capacity // 6)) \ + if server_population else 0 - world_populations.append(f'{server_config["Id"]},{server_population}') + world_populations.append(f'{int(server_id)},{int(server_population)}') - server_key = f'houdini.players.{server_config["Id"]}' - if await p.server.redis.scard(server_key): - async with p.server.db.transaction(): - buddies = BuddyList.select('buddy_id').where(BuddyList.penguin_id == pid).gino.iterate() - tr = p.server.redis.multi_exec() - async for buddy_id, in buddies: - tr.sismember(server_key, buddy_id) - online_buddies = await tr.execute() - if any(online_buddies): - buddy_worlds.append(server_config['Id']) + server_key = f'houdini.players.{int(server_id)}' + if await p.server.redis.scard(server_key): + async with p.server.db.transaction(): + buddies = BuddyList.select('buddy_id').where(BuddyList.penguin_id == pid).gino.iterate() + tr = p.server.redis.multi_exec() + async for buddy_id, in buddies: + tr.sismember(server_key, buddy_id) + online_buddies = await tr.execute() + if any(online_buddies): + buddy_worlds.append(str(int(server_id))) return '|'.join(world_populations), '|'.join(buddy_worlds) diff --git a/houdini/handlers/login/login.py b/houdini/handlers/login/login.py index 48e4e7b..72b6e13 100644 --- a/houdini/handlers/login/login.py +++ b/houdini/handlers/login/login.py @@ -41,19 +41,19 @@ async def handle_login(p, credentials: Credentials): if await p.server.redis.exists(flood_key): tr = p.server.redis.multi_exec() tr.incr(flood_key) - tr.expire(flood_key, p.server.server_config['LoginFailureTimer']) + tr.expire(flood_key, p.server.config.login_failure_timer) failure_count, _ = await tr.execute() - if failure_count >= p.server.server_config['LoginFailureLimit']: + if failure_count >= p.server.config.login_failure_limit: return await p.send_error_and_disconnect(150) else: - await p.server.redis.setex(flood_key, p.server.server_config['LoginFailureTimer'], 1) + await p.server.redis.setex(flood_key, p.server.config.login_failure_timer, 1) return await p.send_error_and_disconnect(101) failure_count = await p.server.redis.get(flood_key) if failure_count: - max_attempts_exceeded = int(failure_count) >= p.server.server_config['LoginFailureLimit'] + max_attempts_exceeded = int(failure_count) >= p.server.config.login_failure_limit if max_attempts_exceeded: return await p.send_error_and_disconnect(150) @@ -98,8 +98,8 @@ async def handle_login(p, credentials: Credentials): confirmation_hash = Crypto.hash(os.urandom(24)) tr = p.server.redis.multi_exec() - tr.setex(f'{data.username}.lkey', p.server.server_config['KeyTTL'], login_key) - tr.setex(f'{data.username}.ckey', p.server.server_config['KeyTTL'], confirmation_hash) + tr.setex(f'{data.username}.lkey', p.server.config.auth_ttl, login_key) + tr.setex(f'{data.username}.ckey', p.server.config.auth_ttl, confirmation_hash) await tr.execute() world_populations, buddy_presence = await get_server_presence(p, data.id) diff --git a/houdini/handlers/login/world.py b/houdini/handlers/login/world.py index dd72734..9ae9043 100644 --- a/houdini/handlers/login/world.py +++ b/houdini/handlers/login/world.py @@ -1,5 +1,3 @@ -import config - from houdini import handlers from houdini.handlers import XMLPacket, login from houdini.converters import WorldCredentials, Credentials @@ -15,7 +13,7 @@ handle_random_key = login.handle_random_key async def world_login(p, data): - if len(p.server.penguins_by_id) >= p.server.server_config['Capacity']: + if len(p.server.penguins_by_id) >= p.server.config.capacity: return await p.send_error_and_disconnect(103) if data is None: @@ -53,7 +51,7 @@ async def handle_login(p, credentials: WorldCredentials): return await p.close() login_key = login_key.decode() - login_hash = Crypto.encrypt_password(login_key + config.client['AuthStaticKey']) + login_key + login_hash = Crypto.encrypt_password(login_key + p.server.config.auth_key) + login_key if credentials.client_key != login_hash: return await p.close() @@ -73,11 +71,11 @@ async def handle_login(p, credentials: WorldCredentials): async def handle_legacy_login(p, credentials: Credentials): tr = p.server.redis.multi_exec() tr.get(f'{credentials.username}.lkey') - tr.delete(f'{credentials.username}.lkey', '{credentials.username}.ckey') + tr.delete(f'{credentials.username}.lkey', f'{credentials.username}.ckey') login_key, _ = await tr.execute() login_key = login_key.decode() - login_hash = Crypto.encrypt_password(login_key + config.client['AuthStaticKey']) + login_key + login_hash = Crypto.encrypt_password(login_key + p.server.config.auth_key) + login_key if login_key is None or login_hash != credentials.password: return await p.close() diff --git a/houdini/handlers/play/message.py b/houdini/handlers/play/message.py index 804bee3..79af866 100644 --- a/houdini/handlers/play/message.py +++ b/houdini/handlers/play/message.py @@ -15,7 +15,8 @@ async def handle_send_message(p, penguin_id: int, message: str): await penguin.send_xt("mm", message, penguin_id) return - if has_command_prefix(message): + tokens = message.lower() + if has_command_prefix(p.server.config.command_prefix, message): await invoke_command_string(p.server.commands, p, message) else: await p.room.send_xt('sm', p.id, message) diff --git a/houdini/handlers/play/navigation.py b/houdini/handlers/play/navigation.py index 577a178..ca76b98 100644 --- a/houdini/handlers/play/navigation.py +++ b/houdini/handlers/play/navigation.py @@ -58,9 +58,9 @@ async def handle_join_server(p, penguin_id: int, login_key: str): p.login_timestamp = datetime.now() p.joined_world = True - server_key = f'houdini.players.{p.server.server_config["Id"]}' - await p.server.redis.sadd(server_key, p.data.id) - await p.server.redis.hincrby('houdini.population', p.server.server_config['Id'], 1) + server_key = f'houdini.players.{p.server.config.id}' + await p.server.redis.sadd(server_key, p.id) + await p.server.redis.hincrby('houdini.population', p.server.config.id, 1) @handlers.handler(XTPacket('j', 'jr')) @@ -127,6 +127,6 @@ async def handle_disconnect_room(p): del p.server.penguins_by_id[p.id] del p.server.penguins_by_username[p.username] - server_key = f'houdini.players.{p.server.server_config["Id"]}' - await p.server.redis.srem(server_key, p.data.id) - await p.server.redis.hincrby('houdini.population', p.server.server_config['Id'], -1) + server_key = f'houdini.players.{p.server.config.id}' + await p.server.redis.srem(server_key, p.id) + await p.server.redis.hincrby('houdini.population', p.server.config.id, -1) diff --git a/houdini/houdini.py b/houdini/houdini.py index 64f4e7a..dd0c5a2 100644 --- a/houdini/houdini.py +++ b/houdini/houdini.py @@ -6,7 +6,6 @@ import copy from houdini.spheniscidae import Spheniscidae from houdini.penguin import Penguin from houdini import PenguinStringCompiler -import config import logging from logging.handlers import RotatingFileHandler @@ -47,22 +46,14 @@ from houdini.handlers.play.music import SoundStudio class Houdini: - def __init__(self, server_name, **kwargs): + def __init__(self, config): self.server = None self.redis = None - self.config = None self.cache = None + self.config = config self.db = db self.peers_by_ip = {} - self.server_name = server_name - self.database_config_override = kwargs.get('database') - self.redis_config_override = kwargs.get('redis') - self.commands_config_override = kwargs.get('commands') - self.client_config_override = kwargs.get('client') - self.server_config_override = kwargs.get('server') - self.server_config = None - self.logger = None self.client_class = Spheniscidae @@ -105,18 +96,14 @@ class Houdini: self.music = None async def start(self): - self.config = config - self.server_config = copy.deepcopy(self.config.servers[self.server_name]) - self.server_config.update(self.server_config_override) - - self.config.database.update(self.database_config_override) - self.config.redis.update(self.redis_config_override) - self.config.commands.update(self.commands_config_override) - self.config.client.update(self.client_config_override) - - general_log_directory = os.path.dirname(self.server_config["Logging"]["General"]) - errors_log_directory = os.path.dirname(self.server_config["Logging"]["Errors"]) + async def start(self): + general_log_file = self.config.logging_general_path if self.config.logging_general_path \ + else f'logs/{self.config.name.lower()}.log' + errors_log_file = self.config.logging_error_path if self.config.logging_error_path \ + else f'logs/{self.config.name.lower()}-errors.log' + general_log_directory = os.path.dirname(general_log_file) + errors_log_directory = os.path.dirname(errors_log_file) if not os.path.exists(general_log_directory): os.mkdir(general_log_directory) @@ -125,10 +112,10 @@ class Houdini: os.mkdir(errors_log_directory) self.logger = logging.getLogger('houdini') - universal_handler = RotatingFileHandler(self.server_config['Logging']['General'], + universal_handler = RotatingFileHandler(general_log_file, maxBytes=2097152, backupCount=3, encoding='utf-8') - error_handler = logging.FileHandler(self.server_config['Logging']['Errors']) + error_handler = logging.FileHandler(errors_log_file) console_handler = logging.StreamHandler(stream=sys.stdout) log_formatter = logging.Formatter('%(asctime)s [%(levelname)-5.5s] %(message)s') @@ -141,35 +128,34 @@ class Houdini: self.logger.addHandler(console_handler) self.logger.addHandler(error_handler) - level = logging.getLevelName(self.server_config['Logging']['Level']) + level = logging.getLevelName(self.config.logging_level) self.logger.setLevel(level) self.server = await asyncio.start_server( - self.client_connected, self.server_config['Address'], - self.server_config['Port'] + self.client_connected, self.config.address, + self.config.port ) await self.db.set_bind('postgresql://{}:{}@{}/{}'.format( - self.config.database['Username'], self.config.database['Password'], - self.config.database['Address'], - self.config.database['Name'])) + self.config.database_username, self.config.database_password, + self.config.database_address, + self.config.database_name)) self.logger.info('Booting Houdini') self.redis = await aioredis.create_redis_pool('redis://{}:{}'.format( - self.config.redis['Address'], self.config.redis['Port']), + self.config.redis_address, self.config.redis_port), minsize=5, maxsize=10) - if self.server_config['World']: - await self.redis.delete(f'houdini.players.{self.server_config["Id"]}') - await self.redis.hdel(f'houdini.population', self.server_config["Id"]) + if self.config.type == 'world': + await self.redis.delete(f'houdini.players.{self.config.id}') + await self.redis.hset(f'houdini.population', self.config.id, 0) - caches.set_config({ - 'default': { - 'cache': SimpleMemoryCache, - 'namespace': 'houdini', - 'ttl': self.server_config['CacheExpiry'] - }}) + caches.set_config(dict(default=dict( + cache=SimpleMemoryCache, + namespace='houdini', + ttl=self.config.cache_expiry + ))) self.cache = caches.get('default') self.client_class = Penguin @@ -227,12 +213,13 @@ class Houdini: self.logger.info(f'Loaded {len(self.characters)} characters') self.permissions = await PermissionCollection.get_collection() + self.chat_filter_words = await ChatFilterRuleCollection.get_collection() self.logger.info(f'Multi-client support is ' - f'{"enabled" if self.config.client["MultiClientSupport"] else "disabled"}') - self.logger.info(f'Listening on {self.server_config["Address"]}:{self.server_config["Port"]}') + f'{"enabled" if not self.config.single_client_mode else "disabled"}') + self.logger.info(f'Listening on {self.config.address}:{self.config.port}') - if self.config.client['AuthStaticKey'] != 'houdini': + if self.config.auth_key != 'houdini': self.logger.warning('The static key has been changed from the default, ' 'this may cause authentication issues!') diff --git a/houdini/penguin.py b/houdini/penguin.py index c2c231a..0a4027c 100644 --- a/houdini/penguin.py +++ b/houdini/penguin.py @@ -55,8 +55,8 @@ class Penguin(Spheniscidae, penguin.Penguin): return self.server.penguin_string_compiler.compile(self) @property - def nickname(self): - return self.data.safe_nickname(self.server.server_config['Language']) + def safe_name(self): + return self.safe_nickname(self.server.config.lang) async def join_room(self, room): await room.add_penguin(self) diff --git a/houdini/spheniscidae.py b/houdini/spheniscidae.py index 66872c9..184bd36 100644 --- a/houdini/spheniscidae.py +++ b/houdini/spheniscidae.py @@ -34,6 +34,8 @@ class Spheniscidae: self.received_packets = set() + super().__init__() + @property def is_vanilla_client(self): return self.client_type == ClientType.Vanilla @@ -51,7 +53,7 @@ class Spheniscidae: async def send_policy_file(self): await self.send_line(f'') + f'{self.server.config.port}" />') await self.close() async def send_xt(self, handler_id, *data):