def __init__(self, user_id, game_name): db = DBSession() self.user_name = db.query(User.name).filter(User.id == user_id).one()[0] self.game_name = game_name self.connections = [] self.game = None self.mud = MudClient() self.mud.on_connected = self.mud_connected self.mud.on_failed_to_connect = self.mud_failed_to_connect self.mud.on_disconnected = self.mud_disconnected self.mud.on_line_received = self.mud_line self.mud.on_gmcp_message_received = self.mud_gmcp_message self.processor = None self._loaded_processors = {}
class ConsoleSession(object): """ A session of the user with the engine. User can be connected to the engine through one or more physical consoles, which all share the same output and can be treated as one abstract console. The connection between such abstract console and the engine is what this class represents. """ def __init__(self, user_id, game_name): db = DBSession() self.user_name = db.query(User.name).filter(User.id == user_id).one()[0] self.game_name = game_name self.connections = [] self.game = None self.mud = MudClient() self.mud.on_connected = self.mud_connected self.mud.on_failed_to_connect = self.mud_failed_to_connect self.mud.on_disconnected = self.mud_disconnected self.mud.on_line_received = self.mud_line self.mud.on_gmcp_message_received = self.mud_gmcp_message self.processor = None self._loaded_processors = {} def close(self): if self.mud.connecting or self.mud.connected: self.mud.disconnect() self.game = None if self.processor: self.processor.shutdown() self.processor = None def send(self, message): """Send a raw text message to the console.""" for c in self.connections: c.send(message) def to_console(self, message): """Send a JSON serialized message to the console.""" serialized_message = json.dumps(message) self.send(serialized_message) def to_mud(self, message, type='raw'): try: encoded_message = str(message) except UnicodeEncodeError: return self.system_message("Text messages containing non-ANSI " "characters are not allowed.") if type == 'raw': self.mud.send(encoded_message + '\n') elif type == 'gmcp': self.mud.send_gmcp(encoded_message) def system_message(self, text): self.to_console(dict(type='system', text=text)) def mud_connected(self): self.system_message("Connected to the mud.") # @@ Check if GMCP is enabled # @@ Move the hardcoded values out # @@ Probably move the whole line somewhere more suitable self.mud.send_gmcp('Core.Hello { "client": "mudwyrm", "version": "0.3" }') def mud_failed_to_connect(self): self.system_message("Couldn't connect to the mud.") def mud_disconnected(self): self.system_message("Disconnected from the mud.") def mud_line(self, line): self.processor.from_mud(line, 'raw') def mud_gmcp_message(self, message): self.processor.from_mud(message, 'gmcp') def handle_message(self, message): message = json.loads(message) if message['type'] == 'text': s = message['text'] if s.startswith('/'): a = s[1:].split(' ') self.execute_command(a[0], *a[1:]) return if self.mud.connected: self.processor.from_console(message) else: self.system_message("Not connected to the mud.") def execute_command(self, name, *args): """Execute a console command.""" try: f = self.__getattribute__(name) except AttributeError: self.system_message("No such command.") return try: ConsoleCommand.check(f, args) except ConsoleCommand.NotACommand: self.system_message("No such command.") return except ConsoleCommand.ArgsMismatch: self.system_message("Invalid command arguments provided.") return f(*args) def _create_processor(self, user_name, game_name): from processor import load_processor Processor = load_processor(user_name, game_name, reload=True) if Processor is None: return None return Processor(self.to_mud, self.to_console) def _get_processor(self, user_name, game_name): key = (user_name, game_name) processor = self._loaded_processors.get(key, None) if not processor: processor = self._create_processor(user_name, game_name) self._loaded_processors[key] = processor else: processor.reload() return processor @ConsoleCommand('command') def help(self, command): """Show a help message about a command.""" try: f = self.__getattribute__(command) except AttributeError: self.system_message("No such command.") try: ConsoleCommand.check(f) except ConsoleCommand.NotACommand: self.system_message("No such command.") self.system_message(ConsoleCommand.help_message(f)) @ConsoleCommand() def connect(self): """Open a game session and connect to the mud server.""" if self.mud.connected or self.mud.connecting: return self.system_message("Close the current session first.") db = DBSession() game = db.query(Game).filter(Game.name == self.game_name).first() if game is None: return self.system_message("Game named '%s' does not exist." % self.game_name) self.system_message("Loading game session '%s'..." % game.name) self.processor = self._get_processor(self.user_name, game.name) if self.processor is None: return self.system_message("Couldn't load a processor for that session.") self.game = game self.mud.connect(self.game.address, self.game.port) self.system_message("Game session '%s' has been opened." % game.name) self.system_message("Trying to connect to the mud...") @ConsoleCommand() def disconnect(self): """Disconnect from the mud server and close the current game session.""" if not self.mud.connecting and not self.mud.connected: return self.system_message("Not connected to the mud.") if self.mud.connecting: self.system_message("Aborting a connection attempt.") self.close() self.system_message("Game session '%s' has been closed." % self.game_name) @ConsoleCommand() def reload(self): """Reload the scripts for the current game session.""" if self.game is None: return self.system_message("There is no active game session to reload.") self.system_message("Reloading scripts...") self.processor.reload() self.system_message("Scripts have been reloaded.")