Esempio n. 1
0
class SpydGetPlayerInfoMessageHandler(object):
    msgtype = 'get_room_info'
    execute = Functionality(msgtype)

    @classmethod
    def handle_message(cls, spyd_server, gep_client, message):
        room_name = message['room']

        room = spyd_server.room_manager.get_room(name=room_name, fuzzy=False)

        if room is None:
            raise Exception("Unknown room.")

        room_info = {
            'is_paused': room.is_paused,
            'is_resuming': room.is_resuming,
            'timeleft': room.timeleft,
            'is_intermission': room.is_intermission,
            'resume_delay': room.resume_delay,
            'mode': room.mode_name,
            'map': room.map_name,
            'players': [player.uuid for player in room.players],
            'show_awards': room.show_awards,
            'mastermode': room.mastermode,
            'mastermask': room.mastermask,
            'temporary': room.temporary,
            'maxplayers': room.maxplayers
        }

        gep_client.send({'msgtype': 'room_info', 'room': room.name, 'room_info': room_info}, message.get('reqid'))
Esempio n. 2
0
class ResumeDelayCommand(CommandBase):
    name = "resumedelay"
    functionality = Functionality(
        "spyd.game.commands.resumedelay.execute",
        "You do not have permission to execute {action#command}",
        command=name)
    usage = "(seconds)"
    description = "View or set the amount of time to count down before starting or resuming a game."

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        if len(arguments):
            try:
                room.resume_delay = max(0, min(10, int(arguments[0])))
                room._broadcaster.server_message(
                    info(
                        "{name#client} has set the resume delay to {value#resume_delay} seconds.",
                        client=client,
                        resume_delay=room.resume_delay))
            except:
                raise UsageError("The resume delay must be an number.")
        else:
            client.send_server_message(
                info("The resume delay is {value#resume_delay} seconds.",
                     resume_delay=room.resume_delay))
Esempio n. 3
0
class FollowCommand(CommandBase):
    name = "follow"
    functionality = Functionality(
        "spyd.game.commands.room.execute",
        "You do not have permission to execute {action#command}",
        command=name)
    usage = ""
    description = "Follow the last player to leave this room."

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        room_name = room.last_destination_room

        if room_name is None:
            raise GenericError(
                "No players have left this room for another recently. Perhaps join another existing room with {action#room}.",
                room='room')

        target_room = room.manager.get_room(room_name, True)

        if target_room is None:
            raise GenericError(
                "Could not join {value#room_name}. Room no longer exists. Perhaps create it with {action#room_create}",
                room_name=room_name,
                room_create='room_create')

        room.manager.client_change_room(client, target_room)
Esempio n. 4
0
class SpydSetRoomPausedMessageHandler(object):
    msgtype = 'set_room_paused'
    execute = Functionality(msgtype)

    @classmethod
    def handle_message(cls, spyd_server, gep_client, message):
        room_name = message['room']
        pause = message['pause']
        room_message = message['message']

        target_room = spyd_server.room_manager.get_room(name=room_name,
                                                        fuzzy=False)

        if target_room is None:
            raise Exception("Unknown room.")
        try:
            if pause:
                target_room.pause()
            else:
                target_room.resume()

            if room_message:
                target_room.server_message(str(room_message))
        except:
            traceback.print_exc()

        gep_client.send({
            "msgtype": "status",
            "status": "success"
        }, message.get('reqid'))
Esempio n. 5
0
class GroupsCommand(CommandBase):
    name = "groups"
    functionality = Functionality(
        "spyd.game.commands.groups.execute",
        "You do not have permission to execute {action#command}",
        command=name)
    usage = "(cn)"
    description = "Displays the groups of the indicated player or yourself."

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        if len(arguments):
            target = room.get_client(int(arguments[0]))
        else:
            target = client

        formatted_groups = ", ".join([
            smf.format("{value#group}", group=group)
            for group in target._client_permissions.get_group_names()
        ])

        client.send_server_message(
            info("groups: {formatted_groups}",
                 formatted_groups=formatted_groups))
Esempio n. 6
0
class RoomCommand(CommandBase):
    name = "room"
    functionality = Functionality(
        "spyd.game.commands.room.execute",
        "You do not have permission to execute {action#command}",
        command=name)
    usage = "<room name>"
    description = "Join a specified room."

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        if len(arguments) < 1:
            raise GenericError("Please specify a room name.")

        room_name = arguments[0]

        target_room = room.manager.get_room(room_name, True)

        if target_room is None:
            raise GenericError(
                "Could not resolve {value#room_name} to a room. Perhaps create it with {action#room_create}",
                room_name=room_name,
                room_create='room_create')

        room.manager.client_change_room(client, target_room)
Esempio n. 7
0
class SpydSetPlayerRoomMessageHandler(object):
    msgtype = 'set_player_room'
    execute = Functionality(msgtype)

    @classmethod
    def handle_message(cls, spyd_server, gep_client, message):
        room_name = message['room']
        player_uuid = message['player']
        player_message = message['message']

        player = Player.instances_by_uuid.get(player_uuid, None)

        if player is None:
            raise Exception("Unknown player.")

        client = player.client

        target_room = spyd_server.room_manager.get_room(name=room_name, fuzzy=False)

        if target_room is None:
            room_factory = spyd_server.room_manager.room_factory
            target_room = room_factory.build_room(room_name, 'temporary')
            target_room.temporary = True

        spyd_server.room_manager.client_change_room(client, target_room, False)

        if player_message:
            client.send_server_message(str(player_message))

        gep_client.send({"msgtype": "status", "status": "success"}, message.get('reqid'))
Esempio n. 8
0
 def test_master_overrides_player_denies_noobishness(self):
     be_a_noob_functionality = Functionality("server.be_n00b")
     self.assertTrue(
         self.permission_resolver.groups_allow(["local.player"],
                                               be_a_noob_functionality))
     self.assertFalse(
         self.permission_resolver.groups_allow(
             ["local.player", "local.master"], be_a_noob_functionality))
Esempio n. 9
0
class SpydGetPlayerInfoMessageHandler(object):
    msgtype = 'get_player_info'
    execute = Functionality(msgtype)

    @classmethod
    def handle_message(cls, spyd_server, gep_client, message):
        player_uuid = message['player']

        player = Player.instances_by_uuid.get(player_uuid, None)

        if player is None:
            raise Exception("Unknown player.")

        state = player.state

        player_game_state = {
            'is_spectator': state.is_spectator,
            'is_alive': state.is_alive,
            'has_quad': state.has_quad,
            'frags': state.frags,
            'deaths': state.deaths,
            'suicides': state.suicides,
            'teamkills': state.teamkills,
            'damage_dealt': state.damage_dealt,
            'damage_spent': state.damage_spent,
            'flags': state.flags,
            'flag_returns': state.flag_returns,
            'health': state.health,
            'maxhealth': state.maxhealth,
            'armour': state.armour,
            'armourtype': state.armourtype,
            'gunselect': state.gunselect,
            'ammo': state.ammo
        }

        player_info = {
            'cn': player.cn,
            'name': player.name,
            'team': player.team_name,
            'room': player.room.name,
            'host': player.client.host,
            'model': player.playermodel,
            'isai': player.isai,
            'groups': tuple(player.client.get_group_names()),
            'game_state': player_game_state
        }

        gep_client.send(
            {
                'msgtype': 'player_info',
                'player': player.uuid,
                'player_info': player_info
            }, message.get('reqid'))
Esempio n. 10
0
class SpydGetServerInfoMessageHandler(object):
    msgtype = 'get_server_info'
    execute = Functionality(msgtype)

    @classmethod
    def handle_message(cls, spyd_server, gep_client, message):
        room_manager = spyd_server.room_manager

        server_info = {
            "rooms": list(room_manager.rooms.keys())
        }

        gep_client.send({'msgtype': 'server_info', 'server_info': server_info}, message.get('reqid'))
Esempio n. 11
0
class PauseCommand(CommandBase):
    name = "pause"
    functionality = Functionality(
        "spyd.game.commands.pause.execute",
        "You do not have permission to execute {action#command}",
        command=name)
    usage = ""
    description = "Pause the game."

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        room.handle_client_event('pause_game', client, 1)
Esempio n. 12
0
class InfoCommand(CommandBase):
    name = "info"
    functionality = Functionality(
        "spyd.game.commands.info.execute",
        "You do not have permission to execute {action#command}",
        command=name)
    usage = ""
    description = "Displays the server info message."

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        client.send_server_message(info(spyd_server.server_info_model.value))
Esempio n. 13
0
class SpydPingMessageHandler(object):
    msgtype = 'ping'
    execute = Functionality(msgtype)

    @classmethod
    def handle_message(cls, spyd_server, gep_client, message):
        server_time = int(time.time() * 1000000)
        client_time = message['time']
        gep_client.send(
            {
                'msgtype': 'pong',
                'client_time': client_time,
                'server_time': server_time
            }, message.get('reqid'))
Esempio n. 14
0
class RoomsCommand(CommandBase):
    name = "rooms"
    functionality = Functionality(
        "spyd.game.commands.rooms.execute",
        "You do not have permission to execute {action#command}",
        command=name)
    usage = "<room name>"
    description = "Displays the rooms on the server, their player counts, modes, and maps."

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        for room in room.manager.rooms.values():
            if room.empty: continue
            client.send_server_message(info(room_info_msg, room=room))
Esempio n. 15
0
class AuthCommand(CommandBase):
    name = "auth"
    description = "Authenticate as admin"
    functionality = Functionality(
        "spyd.game.commands.authpass.execute",
        "You do not have permission to execute {action#command}",
        command=name)

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        if not arguments:
            raise UsageError("You must provide a password")

        room.handle_client_event('auth_pass', client, arguments)
Esempio n. 16
0
class StatsCommand(CommandBase):
    name = "stats"
    functionality = Functionality("spyd.game.commands.stats.execute", "You do not have permission to execute {action#command}", command=name)
    usage = "(cn)"
    description = "Displays the stats of the indicated player or yourself."

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments, raw_args):
        if len(arguments):
            player = room.get_player(int(arguments[0]))
        else:
            player = client.get_player()

        time_online_str = shortDurationString(player.client.time_online)
        client.send_server_message(info(stats_msg, player=player, time_online_str=time_online_str))
Esempio n. 17
0
class TimeleftCommand(CommandBase):
    name = "timeleft"
    functionality = Functionality(
        "spyd.game.commands.timeleft.execute",
        "You do not have permission to execute {action#command}",
        command=name)
    usage = "(time string)"
    description = "View or set the amount of time left in the match. Valid time strings could be; +2m -30s 10m 2y"

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        if len(arguments):
            if room.temporary:
                if not client.allowed(set_temporary_room_timeleft):
                    raise InsufficientPermissions(
                        set_temporary_room_timeleft.denied_message)
            else:
                if not client.allowed(set_permanent_room_timeleft):
                    raise InsufficientPermissions(
                        set_permanent_room_timeleft.denied_message)

            try:
                modifier, value = timestring.parseTimeString(raw_args)

                if modifier == '+':
                    new_timeleft = min(MAXTIMELEFT,
                                       max(0, room.timeleft + value))
                elif modifier == '-':
                    new_timeleft = min(MAXTIMELEFT,
                                       max(0, room.timeleft - value))
                elif modifier == '=':
                    new_timeleft = min(MAXTIMELEFT, max(0, value))

                timeleft = prettytime.createDurationString(new_timeleft)
                room._broadcaster.server_message(
                    info(timeleft_set_str, client=client, timeleft=timeleft))

                room.timeleft = new_timeleft

            except timestring.MalformedTimeString:
                raise GenericError("Invalid time string specified.")
        else:
            timeleft = prettytime.createDurationString(room.timeleft)
            client.send_server_message(
                info(timeleft_get_str, timeleft=timeleft))
Esempio n. 18
0
class CommandsCommand(CommandBase):
    name = "commands"
    functionality = Functionality(
        "spyd.game.commands.room.execute",
        "You do not have permission to execute {action#command}",
        command=name)
    usage = ""
    description = "Displays the list of commands you are permitted to execute."

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        available_commands = room.command_executer.get_available_commands(
            client)

        formatted_command_list = list(map(format_cmd, available_commands))

        client.send_server_message("\f7Commands: " +
                                   " | ".join(formatted_command_list))
Esempio n. 19
0
class ChangeMapCommand(CommandBase):
    name = "<mode>"
    functionality = Functionality("spyd.game.commands.resume.execute", "You do not have permission to execute {action#command}", command=name)
    usage = "<map>"
    description = "Change the mode and map."

    @classmethod
    def handles(cls, room, client, command_string):
        return command_string in gamemodes

    @classmethod
    @defer.inlineCallbacks
    def execute(cls, spyd_server, room, client, command_string, arguments, raw_args):
        if not client.allowed(set_map_mode_functionality):
            raise InsufficientPermissions(set_map_mode_functionality.denied_message)

        mode_name = command_string
        map_name = arguments[0]

        map_name = yield resolve_map_name(room, map_name)

        room.change_map_mode(map_name, mode_name)
Esempio n. 20
0
class GiveMasterCommand(CommandBase):
    name = "givemaster"
    description = "Give master to a client"
    functionality = Functionality(
        "spyd.game.commands.givemaster.execute",
        "You do not have permission to execute {action#command}",
        command=name)

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        player_name = arguments[0] if arguments else ''
        players = dict(
            map(lambda player: (player.name, player.client), room.players))

        if not player_name:
            raise UsageError("You must provide a player")

        if player_name not in players.keys():
            raise GenericError('The player doesn\'t exist')

        room.handle_client_event('give_master', client, players[player_name])
Esempio n. 21
0
class RoomCreateCommand(CommandBase):
    name = "room_create"
    functionality = Functionality(
        "spyd.game.commands.room_create.execute",
        "You do not have permission to execute {action#command}",
        command=name)
    usage = "<room name>"
    description = "Create a room."

    @classmethod
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        if len(arguments) < 1:
            raise GenericError("Please specify a room name.")

        room_name = filtertext(arguments[0], True, MAXROOMLEN)

        target_room = room.manager.get_room(room_name, False)

        if target_room is not None:
            raise GenericError(
                "Room {room#room} already exists, use {action#command} to enter it.",
                room=target_room.name,
                command="room")

        if duel_room_pattern.match(room_name):
            raise GenericError(
                "Room {room#room_name} cannot be created for you because room names with the pattern '#x#' are reserved for 1v1 games.",
                room_name=room_name)

        room_factory = room.manager.room_factory
        target_room = room_factory.build_room(room_name, 'temporary')

        target_room.temporary = True

        target_room.masters.add(client)

        room.manager.client_change_room(client, target_room)
Esempio n. 22
0
class DuelCommand(CommandBase):
    name = "duel"
    functionality = Functionality(
        "spyd.game.commands.duel.execute",
        "You do not have permission to execute {action#command}",
        command=name)
    usage = "(cn) (mode) (map) | (mode) (map)"
    description = "Indicate you are looking for a duel or challenge a specific player."

    @classmethod
    @defer.inlineCallbacks
    def execute(cls, spyd_server, room, client, command_string, arguments,
                raw_args):
        try:
            cn, mode_name, map_name = parse_arguments(raw_args)

            if mode_name is not None:
                valid_mode_names = list(gamemodes.keys())
                mode_name_match = match_fuzzy(str(mode_name), valid_mode_names)

                if mode_name_match is None:
                    raise GenericError(
                        'Could not resolve mode name {value#mode_name} to valid mode. Please try again.',
                        mode_name=mode_name)

                mode_name = mode_name_match

            if map_name is not None:
                map_name = yield resolve_map_name(room, map_name)

            duel_command_msg = duel_command.format(client=client)
            challenge_details = get_challenge_details(mode_name, map_name)

            if cn is not None:
                target = room.get_client(int(cn))
                if target is client:
                    raise GenericError("You can't duel yourself.")

                existing_challenge = get_existing_challenge(target, client)

                if existing_challenge is not None:
                    begin_duel(room, client, target, existing_challenge)

                else:
                    save_specific_challenge(client, target, mode_name,
                                            map_name)
                    target.send_server_message(
                        info(cn_chall_msg,
                             client=client,
                             challenge_details=challenge_details,
                             duel_command=duel_command_msg))
                    client.send_server_message(info(chall_sent_msg))

            else:
                save_general_challenge(client, mode_name, map_name)
                room.server_message(info(looking_msg,
                                         client=client,
                                         challenge_details=challenge_details,
                                         duel_command=duel_command_msg),
                                    exclude=(client, ))
                client.send_server_message(info(chall_sent_msg))
        except:
            traceback.print_exc()
Esempio n. 23
0
 def test_functionality(self):
     f = Functionality('test', 'No access to test.')
     self.assertEqual(repr(f), "<Functionality: 'test'>")
Esempio n. 24
0
 def test_ban_denies_connect(self):
     server_connect_functionality = Functionality("server.connect")
     self.assertFalse(
         self.permission_resolver.groups_allow(
             ["local.ban"], server_connect_functionality))
Esempio n. 25
0
 def test_ban_allows_chat(self):
     server_chat_functionality = Functionality("server.chat")
     self.assertTrue(
         self.permission_resolver.groups_allow(
             ["local.player", "local.ban"], server_chat_functionality))
Esempio n. 26
0
from twisted.internet import defer

from spyd.game.client.exceptions import InsufficientPermissions
from spyd.game.gamemode import get_mode_name_from_num
from spyd.game.map.resolve_map_name import resolve_map_name
from spyd.permissions.functionality import Functionality
from spyd.registry_manager import register

set_map_mode_functionality = Functionality(
    "spyd.game.room.set_map_mode",
    'Insufficient permissions to force a map/mode change.')


@register('room_client_event_handler')
class MapVoteHandler(object):
    event_type = 'map_vote'

    @staticmethod
    @defer.inlineCallbacks
    def handle(room, client, map_name, mode_num):
        if not client.allowed(set_map_mode_functionality):
            raise InsufficientPermissions(
                set_map_mode_functionality.denied_message)

        mode_name = get_mode_name_from_num(mode_num)

        map_name = yield resolve_map_name(room, map_name)

        room.change_map_mode(map_name, mode_name)
Esempio n. 27
0
 def test_master_overrides_ban_allows_connect(self):
     server_connect_functionality = Functionality("server.connect")
     self.assertTrue(
         self.permission_resolver.groups_allow(
             ["local.player", "local.master", "local.ban"],
             server_connect_functionality))
Esempio n. 28
0
 def test_master_inherits_from_player(self):
     server_connect_functionality = Functionality("server.connect")
     self.assertTrue(
         self.permission_resolver.groups_allow(
             ["local.master"], server_connect_functionality))
Esempio n. 29
0
from spyd.game.client.exceptions import InsufficientPermissions, StateError
from spyd.game.server_message_formatter import info
from spyd.permissions.functionality import Functionality
from spyd.registry_manager import register

pause_resume_functionality = Functionality(
    "spyd.game.room.pause_resume",
    'Insufficient permissions to pause or resume the game.')


@register('room_client_event_handler')
class PauseGameHandler(object):
    event_type = 'pause_game'

    @staticmethod
    def handle(room, client, pause):
        if not client.allowed(pause_resume_functionality):
            raise InsufficientPermissions(
                pause_resume_functionality.denied_message)

        if pause:
            if room.is_paused and not room.is_resuming:
                raise StateError('The game is already paused.')
            room.pause()
            room._broadcaster.server_message(
                info(f"{client.get_player().name} has paused the game."))
        elif not pause:
            if not room.is_paused:
                raise StateError('The game is already resumed.')
            room.resume()
            room._broadcaster.server_message(
Esempio n. 30
0
from spyd.game.client.client_permissions import ClientPermissions
from spyd.game.client.client_player_collection import ClientPlayerCollection
from spyd.game.client.exceptions import InsufficientPermissions, StateError, UsageError, GenericError
from spyd.game.client.message_handlers import get_message_handlers
from spyd.game.client.room_group_provider import RoomGroupProvider
from spyd.game.player.player import Player
from spyd.game.room.exceptions import RoomEntryFailure
from spyd.game.server_message_formatter import error, smf, denied, state_error, usage_error
from spyd.permissions.functionality import Functionality
from spyd.protocol import swh
from spyd.utils.constrain import ConstraintViolation
from spyd.utils.filtertext import filtertext
from spyd.utils.ping_buffer import PingBuffer


bypass_ban = Functionality("spyd.game.client.bypass_ban")

logger = logging.getLogger(__name__)

class Client(object):
    '''
    Handles the per client networking, and distributes the messages out to the players (main, bots).
    '''
    def __init__(self, protocol, clientnum_handle, room, auth_world_view, permission_resolver, event_subscription_fulfiller, servinfo_domain, punitive_model):

        self.cn_handle = clientnum_handle
        self.cn = clientnum_handle.cn
        self.room = room
        self.connection_sequence_complete = False

        self._client_player_collection = ClientPlayerCollection(self.cn)