Example #1
0
        def can_send_message(self, client: ClientManager.Client) -> bool:
            """Check if a client can send an IC message in this area.
            Args:
                client (ClientManager.Client): sender
            Returns:
                bool: True is client can send a message, False if not
            """

            if self.cannot_ic_interact(client):
                client.send_ooc('This is a locked area - ask the CM to speak.')
                return False
            return (time.time() * 1000.0 - self.next_message_time) > 0
Example #2
0
    def send_error_report(self, client: ClientManager.Client, cmd: str,
                          args: List[str], ex: Exception):
        """
        In case of an error caused by a client packet, send error report to user, notify moderators
        and have full traceback available on console and through /lasterror
        """

        # Send basic logging information to user
        info = (
            '=========\nThe server ran into a Python issue. Please contact the server owner '
            'and send them the following logging information:')
        etype, evalue, etraceback = sys.exc_info()
        tb = traceback.extract_tb(tb=etraceback)
        current_time = Constants.get_time()
        file, line_num, module, func = tb[-1]
        file = file[file.rfind('\\') + 1:]  # Remove unnecessary directories
        version = self.version
        info += '\r\n*Server version: {}'.format(version)
        info += '\r\n*Server time: {}'.format(current_time)
        info += '\r\n*Packet details: {} {}'.format(cmd, args)
        info += '\r\n*Client status: {}'.format(client)
        info += '\r\n*Area status: {}'.format(client.area)
        info += '\r\n*File: {}'.format(file)
        info += '\r\n*Line number: {}'.format(line_num)
        info += '\r\n*Module: {}'.format(module)
        info += '\r\n*Function: {}'.format(func)
        info += '\r\n*Error: {}: {}'.format(type(ex).__name__, ex)
        info += '\r\nYour help would be much appreciated.'
        info += '\r\n========='
        client.send_ooc(info)
        client.send_ooc_others(
            'Client {} triggered a Python error through a client packet. '
            'Do /lasterror to take a look at it.'.format(client.id),
            pred=lambda c: c.is_mod)

        # Print complete traceback to console
        info = 'TSUSERVERDR HAS ENCOUNTERED AN ERROR HANDLING A CLIENT PACKET'
        info += '\r\n*Server time: {}'.format(current_time)
        info += '\r\n*Packet details: {} {}'.format(cmd, args)
        info += '\r\n*Client status: {}'.format(client)
        info += '\r\n*Area status: {}'.format(client.area)
        info += '\r\n\r\n{}'.format("".join(
            traceback.format_exception(etype, evalue, etraceback)))
        logger.log_print(info)
        self.last_error = [info, etype, evalue, etraceback]

        # Log error to file
        logger.log_error(info, server=self, errortype='C')

        if self.in_test:
            raise ex
Example #3
0
 def start_testimony(self, client: ClientManager.Client, title: str) -> bool:
     """
     Start a new testimony in this area.
     Args:
         client (ClientManager.Client): requester
         title (str): title of the testimony
     Returns:
         bool: whether the testimony was started
     """
     if client not in self.owners and (self.evidence_mod == "HiddenCM" or self.evidence_mod == "Mods"):
         # some servers don't utilise area owners, so we use evidence_mod to determine behavior
         client.send_ooc('You don\'t have permission to start a new testimony in this area!')
         return False
     elif self.is_testifying:
         client.send_ooc('You can\'t start a new testimony until you finish this one!')
         return False
     elif self.is_examining:
         client.send_ooc('You can\'t start a new testimony during an examination!')
         return False
     elif title == '':
         client.send_ooc('You can\'t start a new testimony without a title!')
         return False
     self.testimony = self.Testimony(title, self.testimony_limit)
     self.broadcast_ooc('Began testimony: ' + title)
     self.is_testifying = True
     self.send_command('RT', 'testimony1')
     return True
Example #4
0
        def remove_jukebox_vote(self, client: ClientManager.Client, silent: bool):
            """Removes a vote on the jukebox.
            Args:
                client (ClientManager.Client): client whose vote should be removed
                silent (bool): do not notify client
            """

            if not self.jukebox:
                return
            for current_vote in self.jukebox_votes:
                if current_vote.client.id == client.id:
                    self.jukebox_votes.remove(current_vote)
            if not silent:
                client.send_ooc(
                    'You removed your song from the jukebox.')
Example #5
0
 def add_jukebox_vote(self, client: ClientManager.Client, music_name: str, length: int = -1, showname: str = ''):
     """Cast a vote on the jukebox.
     Args:
         client (ClientManager.Client): Client that is requesting
         music_name (str): track name
         length (int, optional): length of track. Defaults to -1.
         showname (str, optional): showname of voter. Defaults to ''.
     """
     if not self.jukebox:
         return
     if length <= 0:
         self.remove_jukebox_vote(client, False)
     else:
         self.remove_jukebox_vote(client, True)
         self.jukebox_votes.append(
             self.JukeboxVote(client, music_name, length, showname))
         client.send_ooc('Your song was added to the jukebox.')
         if len(self.jukebox_votes) == 1:
             self.start_jukebox()
Example #6
0
        def new_client(self, client: ClientManager.Client):
            """Add a client to the area."""
            self.clients.add(client)
            self.server.area_manager.send_arup_players()
            if client.char_id != -1:
                database.log_room('area.join', client, self)

            # Update the timers
            timer = self.server.area_manager.timer
            if timer.set:
                s = int(not timer.started)
                current_time = timer.static
                if timer.started:
                    current_time = timer.target - arrow.get()
                int_time = int(current_time.total_seconds()) * 1000
                # Unhide the timer
                client.send_command('TI', 0, 2)
                # Start the timer
                client.send_command('TI', 0, s, int_time)
            else:
                # Stop the timer
                client.send_command('TI', 0, 3, 0)
                # Hide the timer
                client.send_command('TI', 0, 1)

            for timer_id, timer in enumerate(self.timers):
                # Send static time if applicable
                if timer.set:
                    s = int(not timer.started)
                    current_time = timer.static
                    if timer.started:
                        current_time = timer.target - arrow.get()
                    int_time = int(current_time.total_seconds()) * 1000
                    # Start the timer
                    client.send_command('TI', timer_id + 1, s, int_time)
                    # Unhide the timer
                    client.send_command('TI', timer_id + 1, 2)
                    client.send_ooc(f'Timer {timer_id+1} is at {current_time}')
                else:
                    # Stop the timer
                    client.send_command('TI', timer_id + 1, 1, 0)
                    # Hide the timer
                    client.send_command('TI', timer_id + 1, 3)
Example #7
0
        def _remove_player(self, user: ClientManager.Client):
            if user not in self._players:
                raise ZoneError.PlayerNotInZoneError(
                    'User {} is not a player of zone {}.'.format(user, self))

            self._players.remove(user)
            self._cleanup_removed_player(user)

            # If no more watchers nor players, delete the zone
            if not self._watchers and not self._players:
                self._server.zone_manager.delete_zone(self._zone_id)
                user.send_ooc(
                    '(X) Zone `{}` that you were in was automatically ended as no one '
                    'was in an area part of it or was watching it anymore.'.
                    format(self._zone_id),
                    is_staff=True)
                user.send_ooc_others(
                    'Zone `{}` was automatically ended as no one was in an '
                    'area part of it or was watching it anymore.'.format(
                        self._zone_id),
                    is_officer=True)
Example #8
0
 def end_testimony(self, client: ClientManager.Client) -> bool:
     """
     End the current testimony or examination.
     Args:
         client (ClientManager.Client): requester
     Returns:
         bool: if the current testimony or examination was ended
     """
     if client not in self.owners and (self.evidence_mod == "HiddenCM" or self.evidence_mod == "Mods"):
         client.send_ooc('You don\'t have permission to end testimonies or examinations in this area!')
         return False
     elif self.is_testifying:
         if len(self.testimony.statements) <= 1:
             client.send_ooc('Please add at least one statement before ending your testimony.')
             return False
         self.is_testifying = False
         self.broadcast_ooc('Recording stopped.')
         return True
     elif self.is_examining:
         self.is_examining = False
         self.broadcast_ooc('Examination stopped.')
         return True
     else:
         client.send_ooc('No testimony or examination in progress.')
         return False
Example #9
0
 def insert_testimony(self, client: ClientManager.Client, index: int,
                      statement: list) -> bool:
     """
     Insert into the testimony a new <statement> after the statement at <index>.
     Args:
         client (ClientManager.Client): requester
         index (int): index of the statement to insert AFTER
         statement (list): the affected statement
     Returns:
         bool: whether the insert was successful
     """
     if client not in self.owners and (self.evidence_mod == "HiddenCM"
                                       or self.evidence_mod == "Mods"):
         client.send_ooc(
             'You don\'t have permission to amend testimony in this area!'
         )
         return False
     if self.testimony.insert_statement(index, statement):
         client.send_ooc('Inserted a new statement after statement ' +
                         str(index) + ' successfully.')
         return True
     else:
         client.send_ooc('Couldn\'t find statement ' + str(index) +
                         '. Are you sure it exists?')
         return False
Example #10
0
 def amend_testimony(self, client: ClientManager.Client, index: int,
                     statement: list) -> bool:
     """
     Replace the statement at <index> with a new <statement>.
     Args:
         client (ClientManager.Client): requester
         index (int): index of the statement to amend
         statement (list): the new statement
     Returns:
         bool: whether the statement was amended
     """
     if client not in self.owners and (self.evidence_mod == "HiddenCM"
                                       or self.evidence_mod == "Mods"):
         client.send_ooc(
             'You don\'t have permission to amend testimony in this area!'
         )
         return False
     if self.testimony.amend_statement(index, statement):
         client.send_ooc('Amended statement ' + str(index) +
                         ' successfully.')
         return True
     else:
         client.send_ooc('Couldn\'t amend statement ' + str(index) +
                         '. Are you sure it exists?')
         return False
Example #11
0
 def start_examination(self, client: ClientManager.Client) -> bool:
     """
     Start an examination of this area's testimony.
     Args:
         client (ClientManager.Client): requester
     Returns:
         bool: whether the examination was started
     """
     if client not in self.owners and (self.evidence_mod == "HiddenCM"
                                       or self.evidence_mod == "Mods"):
         client.send_ooc(
             'You don\'t have permission to start a new examination in this area!'
         )
         return False
     elif self.is_testifying:
         client.send_ooc(
             'You can\'t start an examination during a testimony! (Hint: Say \'/end\' to stop recording!)'
         )
         return False
     elif self.is_examining:
         client.send_ooc(
             'You can\'t start an examination until you finish this one!'
         )
         return False
     self.examine_index = 0
     self.is_examining = True
     self.send_command('RT', 'testimony2')
     return True
Example #12
0
 def navigate_testimony(self,
                        client: ClientManager.Client,
                        command: str,
                        index: int = None) -> bool:
     """
     Navigate the current testimony using the commands >, <, =, and [>|<]<index>.
     Args:
         client (ClientManager.Client): requester
         command (str): either >, <, or =
         index (int): index of the statement to move to, or None
     Returns:
         bool: if the navigation was successful
     """
     if len(self.testimony.statements) <= 1:
         client.send_ooc('Testimony is empty, can\'t navigate!'
                         )  # should never happen
         return False
     if index == None:
         if command == '=':
             if self.examine_index == 0:
                 self.examine_index = 1
         elif command == '>':
             if len(self.testimony.statements
                    ) <= self.examine_index + 1:
                 self.broadcast_ooc(
                     'Reached end of testimony, looping...')
                 self.examine_index = 1
             else:
                 self.examine_index = self.examine_index + 1
         elif command == '<':
             if self.examine_index <= 1:
                 client.send_ooc(
                     'Can\'t go back, already on the first statement!')
                 return False
             else:
                 self.examine_index = self.examine_index - 1
     else:
         try:
             self.examine_index = int(index)
         except ValueError:
             client.send_ooc(
                 "That does not look like a valid statement number!")
             return False
     self.send_command('MS',
                       *self.testimony.statements[self.examine_index])
     return True
Example #13
0
 def remove_statement(self, client: ClientManager.Client, index: int) -> bool:
     """
     Remove the statement at <index>.
     Args:
         client (ClientManager.Client): requester
         index (int): index of the statement to remove
     Returns:
         bool: whether the statement was removed
     """
     if client not in self.owners and (self.evidence_mod == "HiddenCM" or self.evidence_mod == "Mods"):
         client.send_ooc('You don\'t have permission to amend testimony in this area!')
         return False
     if self.testimony.remove_statement(index):
         client.send_ooc('Removed statement ' + str(index) + ' successfully.')
         return True
     else:
         client.send_ooc('Couldn\'t remove statement ' + str(index) + '. Are you sure it exists?')
         return True
Example #14
0
        def change_lights(self,
                          new_lights: bool,
                          initiator: ClientManager.Client = None,
                          area: AreaManager.Area = None):
            """
            Change the light status of the area and send related announcements.

            This also updates the light status for parties.

            Parameters
            ----------
            new_lights: bool
                New light status
            initiator: server.ClientManager.Client, optional
                Client who triggered the light status change.
            area: server.AreaManager.Area, optional
                Broadcasts light change messages to chosen area. Used if
                the initiator is elsewhere, such as in /zone_lights.
                If not None, the initiator will receive no notifications of
                light status changes.

            Raises
            ------
            AreaError
                If the new light status matches the current one.
            """

            status = {True: 'on', False: 'off'}
            if self.lights == new_lights:
                raise AreaError('The lights are already turned {}.'.format(
                    status[new_lights]))

            # Change background to match new status
            if new_lights:
                if self.background == self.server.config[
                        'blackout_background']:
                    intended_background = self.background_backup
                else:
                    intended_background = self.background
            else:
                if self.background != self.server.config['blackout_background']:
                    self.background_backup = self.background
                intended_background = self.background

            self.lights = new_lights
            self.change_background(
                intended_background,
                validate=False)  # Allow restoring custom bg.

            # Announce light status change
            if initiator:  # If a player initiated the change light sequence, send targeted messages
                if area is None:
                    if not initiator.is_blind:
                        initiator.send_ooc('You turned the lights {}.'.format(
                            status[new_lights]))
                    elif not initiator.is_deaf:
                        initiator.send_ooc('You hear a flicker.')
                    else:
                        initiator.send_ooc(
                            'You feel a light switch was flipped.')

                initiator.send_ooc_others('The lights were turned {}.'.format(
                    status[new_lights]),
                                          is_zstaff_flex=False,
                                          in_area=area if area else True,
                                          to_blind=False)
                initiator.send_ooc_others('You hear a flicker.',
                                          is_zstaff_flex=False,
                                          in_area=area if area else True,
                                          to_blind=True,
                                          to_deaf=False)
                initiator.send_ooc_others(
                    '(X) {} [{}] turned the lights {}.'.format(
                        initiator.displayname, initiator.id,
                        status[new_lights]),
                    is_zstaff_flex=True,
                    in_area=area if area else True)
            else:  # Otherwise, send generic message
                self.broadcast_ooc('The lights were turned {}.'.format(
                    status[new_lights]))

            # Notify the parties in the area that the lights have changed
            for party in self.parties:
                party.check_lights()

            for c in self.clients:
                found_something = c.area_changer.notify_me_rp(
                    self, changed_visibility=True, changed_hearing=False)
                if found_something and new_lights:
                    c.send_ic_attention()