houdini/houdini/houdini.py
2020-02-14 21:57:26 +00:00

198 lines
6.8 KiB
Python

import asyncio
import os
import sys
from houdini.spheniscidae import Spheniscidae
from houdini.penguin import Penguin
from houdini import PenguinStringCompiler
import logging
from logging.handlers import RotatingFileHandler
import aioredis
from aiocache import SimpleMemoryCache, caches
from houdini.data import db
from houdini.data.permission import PermissionCollection
try:
import uvloop
uvloop.install()
except ImportError:
uvloop = None
import houdini.handlers
import houdini.plugins
from houdini.handlers import XTListenerManager, XMLListenerManager, DummyEventListenerManager
from houdini.plugins import PluginManager
from houdini.commands import CommandManager
from houdini.handlers.play.player import server_heartbeat, server_egg_timer
from houdini.handlers.play.pet import decrease_stats
from houdini.handlers.play.music import SoundStudio
from houdini.handlers.games.dance import DanceFloor
class Houdini:
def __init__(self, config):
self.server = None
self.redis = None
self.cache = None
self.config = config
self.db = db
self.peers_by_ip = {}
self.logger = None
self.client_class = Spheniscidae
self.penguin_string_compiler = None
self.anonymous_penguin_string_compiler = None
self.penguins_by_id = {}
self.penguins_by_username = {}
self.penguins_by_character_id = {}
self.igloos_by_penguin_id = {}
self.open_igloos_by_penguin_id = {}
self.xt_listeners = XTListenerManager(self)
self.xml_listeners = XMLListenerManager(self)
self.dummy_event_listeners = DummyEventListenerManager(self)
self.commands = CommandManager(self)
self.plugins = PluginManager(self)
self.permissions = None
self.chat_filter_words = None
self.items = None
self.igloos = None
self.furniture = None
self.locations = None
self.flooring = None
self.rooms = None
self.stamps = None
self.cards = None
self.postcards = None
self.puffles = None
self.puffle_items = None
self.puffle_food_treasure = None
self.puffle_furniture_treasure = None
self.puffle_clothing_treasure = None
self.characters = None
self.dance_songs = None
self.heartbeat = None
self.egg_timer = None
self.puffle_killer = None
self.music = None
self.dance_floor = None
self.puck = (0, 0)
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)
if not os.path.exists(errors_log_directory):
os.mkdir(errors_log_directory)
self.logger = logging.getLogger('houdini')
universal_handler = RotatingFileHandler(general_log_file,
maxBytes=2097152, backupCount=3, encoding='utf-8')
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')
error_handler.setLevel(logging.ERROR)
universal_handler.setFormatter(log_formatter)
console_handler.setFormatter(log_formatter)
self.logger.addHandler(universal_handler)
self.logger.addHandler(console_handler)
self.logger.addHandler(error_handler)
level = logging.getLevelName(self.config.logging_level)
self.logger.setLevel(level)
self.server = await asyncio.start_server(
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.logger.info('Booting Houdini')
self.redis = await aioredis.create_redis_pool('redis://{}:{}'.format(
self.config.redis_address, self.config.redis_port),
minsize=5, maxsize=10)
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(dict(default=dict(
cache=SimpleMemoryCache,
namespace='houdini',
ttl=self.config.cache_expiry
)))
self.cache = caches.get('default')
self.client_class = Penguin
self.penguin_string_compiler = PenguinStringCompiler()
self.anonymous_penguin_string_compiler = PenguinStringCompiler()
PenguinStringCompiler.setup_default_builder(self.penguin_string_compiler)
PenguinStringCompiler.setup_anonymous_default_builder(self.anonymous_penguin_string_compiler)
await self.xml_listeners.setup(houdini.handlers, exclude_load='houdini.handlers.login.login')
await self.xt_listeners.setup(houdini.handlers)
self.logger.info('World server started')
else:
await self.xml_listeners.setup(houdini.handlers, 'houdini.handlers.login.login')
self.logger.info('Login server started')
await self.dummy_event_listeners.setup(houdini.handlers)
await self.dummy_event_listeners.fire('boot', self)
self.permissions = await PermissionCollection.get_collection()
self.logger.info(f'Multi-client support is '
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.auth_key != 'houdini':
self.logger.warning('The static key has been changed from the default, '
'this may cause authentication issues!')
await self.plugins.setup(houdini.plugins)
self.heartbeat = asyncio.create_task(server_heartbeat(self))
self.egg_timer = asyncio.create_task(server_egg_timer(self))
self.puffle_killer = asyncio.create_task(decrease_stats(self))
self.music = SoundStudio(self)
async with self.server:
await self.server.serve_forever()
async def client_connected(self, reader, writer):
client_object = self.client_class(self, reader, writer)
await client_object.run()