示例#1
0
文件: server.py 项目: sunfall/giles
    def __init__(self, name="Giles", source_url=None, admin_password=None,
                 config_filename=None):

        if not source_url:
            print("Nice try setting source_url to nothing.  Bailing.")
            sys.exit(1)

        self.name = name
        self.source_url = source_url
        self.config_filename = config_filename
        self.log = Log(name)
        self.players = []
        self.spaces = []
        self.should_run = True
        self.startup_datetime = None
        self.timestamp = None
        self.current_day = None
        self.update_timestamp()
        self.update_day()

        # Initialize the various workers.
        self.die_roller = DieRoller()
        self.configurator = Configurator()
        self.account_manager = AccountManager(self)
        self.channel_manager = ChannelManager(self)
        self.game_master = GameMaster(self)
        self.chat = Chat(self)
        self.login = Login(self)

        # The admin manager needs the channel manager.
        self.admin_manager = AdminManager(self, admin_password)

        # No telnet server yet; that needs instantiate().
        self.telnet = None

        # Set up the global channel for easy access.
        self.wall = self.channel_manager.channels[0]
        self.log.log("Server started up.")
示例#2
0
class Server(object):
    """The Giles server itself.  Tracks all players, games in progress,
    and so on.
    """

    def __init__(self, name="Giles", source_url=None, admin_password=None,
                 config_filename=None):

        if not source_url:
            print("Nice try setting source_url to nothing.  Bailing.")
            sys.exit(1)

        self.name = name
        self.source_url = source_url
        self.config_filename = config_filename
        self.log = Log(name)
        self.players = []
        self.spaces = []
        self.should_run = True
        self.timestamp = None
        self.current_day = None
        self.update_timestamp()
        self.update_day()

        # Initialize the various workers.
        self.die_roller = DieRoller()
        self.configurator = Configurator()
        self.channel_manager = ChannelManager(self)
        self.game_master = GameMaster(self)
        self.chat = Chat(self)
        self.login = Login(self)

        # The admin manager needs the channel manager.
        self.admin_manager = AdminManager(self, admin_password)

        # No telnet server yet; that needs instantiate().
        self.telnet = None

        # Set up the global channel for easy access.
        self.wall = self.channel_manager.channels[0]
        self.log.log("Server started up.")

    def instantiate(self, port=9435, timeout=.05):
        self.telnet = TelnetServer(
           port=port,
           address='',
           on_connect=self.connect_client,
           on_disconnect=self.disconnect_client,
           timeout=timeout)
        self.update_timestamp()

    def update_timestamp(self):
        old_timestamp = self.timestamp
        self.timestamp = time.strftime("%H:%M")
        return (old_timestamp != self.timestamp)

    def update_day(self):
        old_day = self.current_day
        self.current_day = time.strftime("%A, %B %d, %Y")
        return (old_day != self.current_day)

    def loop(self):

        cleanup_time = keepalive_time = gametick_time = time.time()
        cleanup_ticker = keepalive_ticker = gametick_ticker = 0
        while self.should_run:
            self.telnet.poll()
            self.handle_players()

            # Handle time and the tickers.
            curr_time = time.time()

            cleanup_ticker += 1
            if ((cleanup_time + CLEANUP_INTERVAL_SECONDS <= curr_time) or
             ((cleanup_ticker % CLEANUP_INTERVAL_TICKS) == 0)):
                self.cleanup()
                self.channel_manager.cleanup()
                self.game_master.cleanup()
                cleanup_time = curr_time
                cleanup_ticker = 0

            keepalive_ticker += 1
            if ((keepalive_time + KEEPALIVE_INTERVAL_SECONDS <= curr_time) or
             ((keepalive_ticker % KEEPALIVE_INTERVAL_TICKS) == 0)):
                self.keepalive()
                keepalive_time = curr_time
                keepalive_ticker = 0

            gametick_ticker += 1
            if ((gametick_time + GAMEINTERVAL_TICKS_SECONDS <= curr_time) or
             ((gametick_ticker % GAMETICK_INTERVAL_TICKS) == 0)):
                self.game_master.tick()
                gametick_time = curr_time
                gametick_ticker = 0

                # Since this is more than once a second, abuse it to update
                # the timestamp as well. If the timestamp actually changed
                # then update the prompts for all players.
                if self.update_timestamp():
                    if self.update_day():
                        self.announce_midnight()
                    self.update_prompts()

        self.log.log("Server shutting down.")

    def connect_client(self, client):

        # Log the connection and instantiate a new player for this connection.
        self.log.log("New client connection on port %s." % client.addrport())
        new_player = Player(client, self)
        self.players.append(new_player)

        # Now set their state to the name entry screen.
        new_player.state = State("login")

        # Enable echo/char mode on the client connection
        client.request_will_echo()
        client.request_will_sga()

    def disconnect_client(self, client):
        self.log.log("Client disconnect on port %s." % client.addrport())

        for player in self.players:
            if client == player.client:
                self.admin_manager.remove_player(player)
                self.channel_manager.remove_player(player)
                self.game_master.remove_player(player)
                self.players.remove(player)
                if player.location:
                    player.location.remove_player(player, "^!%s^. has disconnected from the server.\n" % player)

    def handle_players(self):
        for player in self.players:
            curr_state = player.state.get()
            if curr_state == "login":
                try:
                    self.login.handle(player)
                except Exception as e:
                    player.tell_cc("^RSomething went horribly awry with login.  Logging.^~\n")
                    self.log.log("The login module bombed with player %s: %s\n%s" % (player.name, e, traceback.format_exc()))
            elif curr_state == "chat":
                try:
                    self.chat.handle(player)
                except Exception as e:
                    player.tell_cc("^RSomething went horribly awry with chat.  Logging.^~\n")
                    self.log.log("The chat module bombed with player %s: %s\n%s" % (player.name, e, traceback.format_exc()))
                    player.prompt()

    def announce_midnight(self):
        for player in self.players:
            player.tell_cc("It is now ^C%s^~.\n" % self.current_day)

    def update_prompts(self):
        for player in self.players:
            if player.state.get() == "chat" and player.config["timestamps"]:
                player.prompt()

    def add_player(self, player):
        if player not in self.players:
            self.players.append(player)

    def remove_player(self, player):
        if player in self.players:
            self.players.remove(player)

    def get_space(self, space_name):

        for space in self.spaces:
            if space.name == space_name:
                return space

        # Didn't find the space.
        new_space = Location(space_name)
        self.spaces.append(new_space)
        return new_space

    def get_player(self, player_name):

        lower_name = player_name.lower()
        for player in self.players:
            if player.name == lower_name:
                return player

        return None

    def cleanup(self):

        for space in self.spaces:
            if len(space.players) == 0:
                self.log.log("Deleting stale space %s." % space.name)
                self.spaces.remove(space)
                del space

    def keepalive(self):

        # For now, just request a window size negotiation.  Unexciting,
        # but it /is/ traffic over the TCP connection.
        for player in self.players:
            player.client.request_naws()