mirror of
https://github.com/solero/houdini.git
synced 2024-11-09 20:58:20 +00:00
198 lines
6.8 KiB
Python
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()
|