Esempio n. 1
0
def gameOver(jsn):
    """Recieved when the game ends for a pair of players."""
    game_id = jsn["gameId"]

    ### Make sure that the game is either in the live games, or has an entry
    # in the database already.

    db.write_connection_event(request.sid, "Game Ended Normally")

    if game_id in live_games:
        logger.debug('game over (ID: ' + str(game_id) + ')')

        db.write_final_turn(game_id, jsn["time"])
        db.write_game_end(game_id, jsn["score"])

        live_games.pop(game_id)
        kill_agent(game_id)
    else:
        # If it's not, make sure that the score has been set and accurately
        # reflects what was in the database already.
        expected_score = db.get_game_score(game_id)

        if not expected_score == jsn["score"]:
            logger.warn("Didn't find game " + game_id +
                        " in live games, but the score was not "
                        "expected! (database) " + str(expected_score) +
                        "; (client) " + str(jsn["score"]))
Esempio n. 2
0
def finished_command(jsn):
    """Received when the follower finishes an instruction."""
    character = jsn['character']
    if character == 'Human':
        raise ValueError('Human should not be finishing commands!')
    game_id = jsn['gameId']
    logger.debug('(game ID: ' + game_id + ') follower finished a command')

    emit('finishedCommand', jsn, room=partner_room(character, game_id))

    db.write_finished_command(jsn)
Esempio n. 3
0
def card_set(jsn):
    """Recieved when one player makes a set. Logs this in the database"""
    game_id = jsn['gameId']
    logger.debug("(game ID: " + game_id + ") set made: " + str(jsn))

    db.write_set(jsn['gameId'], jsn['moveId'], jsn['score'], jsn['cards'])

    game = get_game(game_id)
    if not game:
        raise ValueError('Game not found: ' + str(game_id))
    if game.using_agent:
        my_partner_room = partner_room(jsn['character'], game_id)
        emit('set', jsn, room=my_partner_room)
Esempio n. 4
0
def switch_turn(jsn):
    """Recieved when one player ends their turn. Logs this in the database and
    sends in to the player's partner to give them the turn."""
    character = jsn["character"]
    game_id = jsn["gameId"]
    db.write_turn_switch(jsn)

    logger.debug("(game ID: " + str(game_id) + ") " + character +
                 " ending turn " + str(jsn["turnId"]))

    game = get_game(game_id)
    if not game:
        raise ValueError('Game not found: ' + str(game_id))
    emit('yourTurn', room=partner_room(character, game_id))
Esempio n. 5
0
def instruction(jsn):
    """Recieved when one leader sends an instruction to their follower."""
    character = jsn['character']
    if character == 'Agent':
        raise ValueError('Agent should not be sending commands!')

    game_id = jsn['gameId']

    db.write_instruction(game_id, jsn['moveId'], jsn['instructionId'],
                         jsn['content'], jsn['time'], jsn['turnId'])

    game = get_game(game_id)
    if not game:
        raise ValueError('Game not found: ' + str(game_id))
    my_partner_room = partner_room(character, game_id)
    emit('instruction', jsn, room=my_partner_room)
    logger.debug('(game ID: ' + game_id + ') instruction sent to room ' +
                 str(my_partner_room) + ': ' + jsn['content'])
Esempio n. 6
0
def remove_ghost_sessions():
    cur_age = sys.maxsize
    ghost_start_time = time.time() - SERVER_START_TIME
    while cur_age > TIMEOUT_AGE and not lobby_clients.empty():
        client_entered_time, client = lobby_clients.get()

        client_age = ghost_start_time - client_entered_time

        if client_age <= TIMEOUT_AGE:
            # If hasn't been waiting long, put it back and break
            lobby_clients.put((client_entered_time, client))
        else:
            lobby_clients_active[client.sid] = False

            socketio.emit('reset', room=client.sid)
            logger.debug('marked inactive client ' + str(client) + '; waited for ' + str(client_age) + ' s')
            db.write_connection_event(client.sid, "Removed Ghost Session")

        cur_age = client_age
Esempio n. 7
0
def kill_agent(game_id):
    agent_id = db.get_agent_id_for_game(game_id)
    logger.debug('Trying to kill agent ' + str(agent_id))

    if not agent_id:
        logger.debug('Could not find agent ID for game ' + str(game_id))
    elif agent_id in agent_processes:
        # Kill the process
        process = agent_processes[agent_id]
        logger.debug('Killing process associated with agent=' + agent_id +
                     ', pid=' + str(process.pid))
        process.kill()
        agent_processes.pop(agent_id)
    else:
        logger.debug('Could not find agent ' + agent_id + ' process')
Esempio n. 8
0
def init(jsn):
    """Record game information in initialInfo and logging initial states
    of both players.
    """
    seed = int(jsn['seed'])
    db.write_initial_info(seed, str(jsn['hexCellInfo']),
                          str(jsn['propPlacementInfo']), str(jsn['cardInfo']))

    game_id = jsn['gameId']

    # If using a human-agent game, record this debugrmation to the agent.
    try:
        game = live_games[game_id]
    except KeyError:
        logger.error('Game ' + str(game_id) + ' not found in live games')
        return

    logger.debug('Received init! game using agent? ' + str(game.using_agent))
    if game.using_agent:
        # Send to the other player
        logger.debug('Sending initial debug to agent!')
        emit('initialMapInfo', jsn, room=game.agent_room())

    initial_pos = jsn["propPlacementInfo"][-1]["posV3"]
    initial_rot = float(
        jsn["propPlacementInfo"][-1]["rotV3"].split(",")[1].strip())

    database = sqlite3.connect(DATABASE_NAME)
    c = database.cursor()

    q = ('INSERT INTO movements (gameId, moveId, character, action, position, '
         'rotation, gameTime, serverTime, turnId) VALUES (?,?,?,?,?,?,?,?,?)')
    t = (game_id, -1, jsn["character"], "initial", initial_pos, initial_rot,
         "0", db.get_current_time(), -1)
    c.execute(q, t)
    database.commit()
    database.close()
Esempio n. 9
0
def start_gameplay(jsn):
    """Recieved when one player's game is loaded, so they are ready to start
    playing. Gameplay starts after both players send this message.
    """
    game_id = jsn["gameId"]
    requester_sid = request.sid
    logger.debug("player: " + requester_sid + " loaded the game " + game_id)

    db.write_connection_event(requester_sid, 'Game Loaded')

    try:
        game = live_games[game_id]
    except KeyError:
        logger.error('Game ' + str(game_id) + ' not found in live games')
        return

    if jsn['character'] == 'Human':
        game.set_human_loaded()
        partner_room = game.agent_room()
    elif jsn['character'] == 'Agent':
        game.set_agent_loaded()
        partner_room = game.human_room()
    else:
        raise ValueError('Unrecognized character type: ' + jsn['character'])

    if game.both_loaded():
        # need both players to be in the same room so we can send the
        # start msg in one emit, to get each player to recieve the message
        # as close to the same time as possible

        join_room(partner_room)
        logger.debug('sending start game play to my partner')
        emit('startGamePlay', room=partner_room)
        leave_room(partner_room)

        db.write_first_turn(game_id)
Esempio n. 10
0
def ready_pressed(jsn):
    """Recieved when player presses button to indicate they are ready to start.
    Game actually starts loading after both lobby_clients send this message, i.e. they
    are both ready.
    """
    logger.debug("%s from %s pressed ready", jsn["character"], jsn["gameId"])

    game_id = jsn["gameId"]
    try:
        game = live_games[game_id]
    except KeyError as e:
        logger.warn('Game ' + str(game_id) + ' not found in live games')
        return

    # Set ready, and also join the room actually corresponding to the in-play
    # game
    if jsn["character"] == "Human":
        game.set_human_ready()
        logger.debug('human joined room: ' + game.human_room())
        join_room(game.human_room())
        db.write_connection_event(request.sid, "Pressed Ready (Leader)")

    elif jsn["character"] == "Agent":
        game.set_agent_ready()
        logger.debug('agent joined room: ' + game.agent_room())
        join_room(game.agent_room())
        db.write_connection_event(request.sid, "Pressed Ready (Follower)")

    else:
        raise ValueError('Unrecognized character name: ' + jsn['character'])

    if game.both_ready():
        emit('startGame', room=game.human_room())
        emit('startGame', room=game.agent_room())

        # Mark the assignment IDs as used
        db.mark_assignment_id_used(game.human_id(), game.human_assignment_id())
        db.mark_assignment_id_used(game.agent_id(), game.agent_assignment_id())
Esempio n. 11
0
def join_lobby(jsn):
    """Player joins lobby for partner matchmaking. 'lobby_clients' holds all
    players currently in queue to find a partner.
    """
    # Just put them in the lobby.
    worker_id = jsn['worker_id']

    my_request = CerealRequest(request.remote_addr, request.sid, worker_id,
                               jsn['assignment_id'])

    if worker_id.startswith('agent'):
        agent_clients.put((time.time() - SERVER_START_TIME, my_request))
        agent_clients_active[request.sid] = True

    else:
        lobby_clients.put((time.time() - SERVER_START_TIME, my_request))
        lobby_clients_active[request.sid] = True

        logger.info('MATCHING WITH HUMAN? ' +
                    str(CURRENT_MATCH_MODE.use_human))
        if not CURRENT_MATCH_MODE.use_human:
            # Spawn an agent client
            logger.debug('Spawning an agent client...')
            agent_uuid = 'agent_' + str(uuid.uuid4().hex)
            process = subprocess.Popen(
                ['python3', '-m', 'webapp.agent', agent_uuid])
            agent_processes[agent_uuid] = process
            logger.debug('Spawned agent=' + agent_uuid + ', pid=' +
                         str(process.pid))

    logger.debug("player joined lobby: " + str(my_request))

    db.write_connection_event(request.sid, "Join Lobby")

    # Each player's room is just their unique request debugrmation for now
    # Later on, when they are ready, they will enter their game's room
    join_room(my_request.sid)
Esempio n. 12
0
def parse_credentials(jsn):
    # This is a hashed worker ID. Look it up against the hash.
    worker_id = jsn['worker_id']
    if db.is_qualified(worker_id):
        # Check if the assignment ID is already used.
        if db.assignment_id_used(worker_id, jsn['assignment_id']):
            db.update_client_info(request.sid, worker_id, jsn['assignment_id'],
                                  'Already Used Assignment ID')
            logger.debug(
                'identified worker using assignment ID another time; SID=' +
                request.sid)
            emit('assignmentIdUsed')
        else:
            # Check for worker ID in list of currently-connected workers
            if db.worker_connected(worker_id):
                db.update_client_info(request.sid, worker_id,
                                      jsn['assignment_id'],
                                      'Already Connected to Game')
                logger.debug('identified already-connected worker ' +
                             jsn['worker_id'] + '; SID=' + request.sid)
                emit('alreadyConnected')

            else:
                db.update_client_info(request.sid, worker_id,
                                      jsn['assignment_id'],
                                      'Validated Connection')
                logger.debug('recognizing connected worker ' +
                             jsn['worker_id'] + '; SID=' + request.sid)
                db.write_connection_event(request.sid,
                                          'Connected and Validated Identity')
                emit('recognizedWorker')
    elif worker_id.startswith('agent'):
        db.update_client_info(request.sid, worker_id, jsn['assignment_id'],
                              'Agent Connected')
        logger.debug('recognized agent; SID=' + request.sid + '; ID=' +
                     str(worker_id))
        emit('recognizedAgent')
        db.write_connection_event(request.sid, 'Connected with Agent ID')
    else:
        if worker_id:
            db.update_client_info(request.sid, worker_id, jsn['assignment_id'],
                                  'Non-Recognized Worker')
            logger.debug(
                'did not recognize connector as qualified worker; SID=' +
                request.sid)
            emit('unqualifiedWorker')
            db.write_connection_event(request.sid,
                                      'Connected with Unrecognized Worker ID')
        else:
            db.update_client_info(request.sid, worker_id, jsn['assignment_id'],
                                  'No-credentials Connection')
            logger.debug('did not recognize connector; SID=' + request.sid)
            db.write_connection_event(request.sid,
                                      'Connected with No Credentials')
Esempio n. 13
0
def result(jsn):
    """Recieved when one player collects a card. Logs this in the database"""
    logger.debug("(game ID: " + jsn["gameId"] + ") card result: " + str(jsn))
    db.write_card_selection(jsn['gameId'], jsn['moveId'], jsn['card'],
                            jsn['result'])
Esempio n. 14
0
def match_human_players():
    if lobby_clients.qsize() >= 2:
        try:
            client_1 = lobby_clients.get()
        except queue.Empty as e:
            logger.debug("Couldn't get client 1 in human-human match, " + str(e))
            return

        try:
            client_2 = lobby_clients.get()
        except queue.Empty as e:
            logger.debug("Couldn't get client 2 in human-human match, " + str(e))
            lobby_clients.put(client_1)
            return

        # If one of them isn't there anymore, remove (put the other one back)
        if not (lobby_clients_active[client_1[1].sid] and lobby_clients_active[client_2[1].sid]):
            logger.debug("Pair between " + client_1[1].sid + " and " + client_2[1].sid +
                         " didn't work; removing one or both of them")
            if lobby_clients_active[client_1[1].sid]:
                lobby_clients.put(client_1)
            elif lobby_clients_active[client_2[1].sid]:
                lobby_clients.put(client_2)
            return

        if client_1[1].sid == client_2[1].sid:
            # It is possible they can match with themselves in the case
            # that they time out and restart from the same page. Avoid this
            # by removing a client if it has the same sid.

            # This only happens because the player joins the lobby twice from the
            # same sid (we don't make them reload the page to return to the
            # lobby). lobby_clients_active is updated to True for the second
            # time they join the lobby, so for both clients in the lobby, they
            # are considered active (the only thing different between the two
            # clients is the time they entered, which we don't want to require
            # for lookups in lobby_clients_active). Return the one to the
            # queue that has waited shorter (i.e., the one that just joined).
            lobby_clients.put(client_2)
            return

        client_1_waittime = time.time() - client_1[0] - SERVER_START_TIME
        client_2_waittime = time.time() - client_2[0] - SERVER_START_TIME

        client_1 = client_1[1]
        client_2 = client_2[1]

        lobby_clients_active[client_1.sid] = False
        lobby_clients_active[client_2.sid] = False

        db.write_connection_event(client_1.sid, "Matched With Partner")
        db.write_connection_event(client_2.sid, "Matched With Partner")

        # pair them up
        # guaranteed to be free of collisions and we don't need ordering on
        # game IDs so just use uuid
        game_id = str(uuid.uuid4().hex)
        game_seed = random.randint(0, pow(2, 30))
        print('game seed: ' + str(game_seed))
        logger.debug('game seed: ' + str(game_seed))

        num_cards = 21

        character_1 = "Human" if game_seed % 2 == 0 else "Agent"
        character_2 = "Agent" if character_1 == "Human" else "Human"
        if character_1 == "Human":
            game = GameData(game_seed,
                            game_id,
                            num_cards,
                            human=client_1,
                            agent=client_2,
                            using_agent=False)
        else:
            game = GameData(game_seed,
                            game_id,
                            num_cards,
                            human=client_2,
                            agent=client_1,
                            using_agent=False)
        live_games[game_id] = game
        logger.debug("starting game #" + str(game_id) + " with seed " + str(game_seed) + " and worker ids "
                     + client_1.worker_id + " / " + client_2.worker_id)
        logger.debug("client 1 (" + str(client_1) + " waited for " + str(client_1_waittime) + " s")
        logger.debug("client 2 (" + str(client_2) + " waited for " + str(client_2_waittime) + " s")

        # Initialize the game for both players, and also say that the lobby
        # is ready (players matched) -- this will play the audio reminder

        # For now, each player is in a room corresponding to their sid.
        # But later they will go into a room corresponding to the game, so
        # movement communication is easier.
        socketio.emit('initGame',
                      {'character': character_1,
                       'gameId': game_id,
                       'seed': game_seed,
                       'num_cards': num_cards},
                      room=client_1.sid)
        socketio.emit('lobbyReady',
                      room=client_1.sid)

        socketio.emit('initGame',
                      {'character': character_2,
                       'gameId': game_id,
                       'seed': game_seed,
                       'num_cards': num_cards},
                      room=client_2.sid)
        socketio.emit('lobbyReady',
                      room=client_2.sid)

        db.write_game_start(game)

        # Switch the mode
        if MATCH_MODE == MatchMode.HUMAN_AND_AGENT:
            CURRENT_MATCH_MODE.use_human = False
            logger.debug('Switching to matching with human: ' + str(CURRENT_MATCH_MODE.use_human))
Esempio n. 15
0
def match_human_with_agent():
    # Don't allow more than N concurrent games
    if len(live_games) >= 30:
        if lobby_clients.qsize() > LOGGED_OVER_CAPACITY.num_connected:
            logger.debug("New maximum connections reached: %r" % lobby_clients.qsize())
            LOGGED_OVER_CAPACITY.num_connected = lobby_clients.qsize()
        elif lobby_clients.qsize() < LOGGED_OVER_CAPACITY.num_connected:
            logger.debug("Number of connections lowered: %r" % lobby_clients.qsize())
            LOGGED_OVER_CAPACITY.num_connected = lobby_clients.qsize()

        return

    if lobby_clients.qsize() >= 1 and agent_clients.qsize() >= 1:
        try:
            human_client = lobby_clients.get()
        except queue.Empty as e:
            logger.debug("Couldn't get human in human-agent match, " + str(e))
            return

        try:
            agent_client = agent_clients.get()
        except queue.Empty as e:
            logger.debug("Couldn't get agent in human-agent match, " + str(e))
            lobby_clients.put(human_client)
            return

        # If one of them isn't there anymore, remove (put the other one back)
        if not (lobby_clients_active[human_client[1].sid] and agent_clients_active[agent_client[1].sid]):
            logger.debug("Pair between " + human_client[1].sid + " and " + agent_client[1].sid +
                         " didn't work; removing one or both of them")
            if lobby_clients_active[human_client[1].sid]:
                lobby_clients.put(human_client)
            elif agent_clients_active[agent_client[1].sid]:
                agent_clients.put(agent_client)
            return

        if human_client[1].sid == agent_client[1].sid:
            raise ValueError('Agent and human client sid should never be the same!' + str(human_client[1].sid))

        client_1_waittime = time.time() - human_client[0] - SERVER_START_TIME
        client_2_waittime = time.time() - agent_client[0] - SERVER_START_TIME

        human_client = human_client[1]
        agent_client = agent_client[1]

        lobby_clients_active[human_client.sid] = False
        agent_clients_active[agent_client.sid] = False

        db.write_connection_event(human_client.sid, "Matched With Partner")
        db.write_connection_event(agent_client.sid, "Matched With Partner")

        # pair them up
        # guaranteed to be free of collisions and we don't need ordering on
        # game IDs so just use uuid
        game_id = str(uuid.uuid4().hex)
        game_seed = random.randint(0, pow(2, 30))
        num_cards = 21

        game = GameData(game_seed,
                        game_id,
                        num_cards,
                        human=human_client,
                        agent=agent_client,
                        using_agent=True)
        live_games[game_id] = game
        logger.debug("starting game #" + str(game_id) + " with seed " + str(game_seed) + " and worker ids "
                     + human_client.worker_id + " / " + agent_client.worker_id)
        logger.debug("client 1 (" + str(human_client) + " waited for " + str(client_1_waittime) + " s")
        logger.debug("client 2 (" + str(agent_client) + " waited for " + str(client_2_waittime) + " s")

        # Initialize the game for both players, and also say that the lobby
        # is ready (players matched) -- this will play the audio reminder

        # For now, each player is in a room corresponding to their sid.
        # But later they will go into a room corresponding to the game, so
        # movement communication is easier.
        socketio.emit('initGame',
                      {'character': 'Human',
                       'gameId': game_id,
                       'seed': game_seed,
                       'num_cards': num_cards},
                      room=human_client.sid)
        socketio.emit('lobbyReady',
                      room=human_client.sid)

        socketio.emit('initGame',
                      {'character': 'Agent',
                       'gameId': game_id,
                       'seed': game_seed,
                       'num_cards': num_cards},
                      room=agent_client.sid)
        socketio.emit('lobbyReady',
                      room=agent_client.sid)

        db.write_game_start(game)

        # Switch the mode
        if MATCH_MODE == MatchMode.HUMAN_AND_AGENT:
            CURRENT_MATCH_MODE.use_human = True
            logger.debug('Switching to matching with human: ' + str(CURRENT_MATCH_MODE.use_human))
Esempio n. 16
0
def disconnectEvent():
    """Recieved when a client exits from their game."""
    db.disconnect_client(request.sid, 'Disconnected')
    db.write_connection_event(request.sid, "Disconnected")

    if request.sid in lobby_clients_active and lobby_clients_active[
            request.sid]:  # If was in the lobby,
        logger.debug('Lobby client ' + request.sid + ' disconnected')
        db.write_connection_event(request.sid, "Disconnected from Lobby")
        db.disconnect_client(request.sid, 'Disconnected from Lobby')
        lobby_clients_active[request.sid] = False
        return

    # Find the game that this request was connected to
    request_is_human = False
    found_game = None
    for game_id, game in live_games.items():
        if game.human.sid == request.sid:
            request_is_human = True
            found_game = game
            logger.debug('Requester ' + request.sid + ' was human in game ' +
                         str(game_id))
            break
        elif not game.using_agent and game.agent.sid == request.sid:
            found_game = game
            logger.debug('Requester ' + request.sid + ' was agent in game ' +
                         str(game_id))
            break

    if not found_game:
        return

    # Log that they exited prematurely
    game_id = found_game.game_id

    if request_is_human:
        if found_game.using_agent:
            logger.debug('Removing game ' + str(game_id) +
                         ' from live games; human from agent-human game.')
            db.disconnect_client(request.sid, 'Disconnected After Game')
            db.write_connection_event(request.sid, "Quit Game")

            # Check if in live games first -- might not be anymore if the partner
            # concurrently ended the game
            kill_agent(game_id)
            if game_id in live_games:
                # Get the agent ID
                live_games.pop(game_id)
        else:
            if found_game.agent_quit:
                logger.debug('Removing game ' + str(game_id) +
                             ' from live games; both people quit.')
                db.disconnect_client(request.sid, 'Disconnected After Game')
                db.write_connection_event(request.sid, "Quit Game")

                # Check if in live games first -- might not be anymore if the partner
                # concurrently ended the game
                if game_id in live_games:
                    live_games.pop(game_id)
            else:
                logger.debug('Agent from game ' + str(game_id) +
                             ' is still there.')
                found_game.set_human_quit()

                # Notify the agent that their partner left. Use the sid, rather than
                # the game room, because they may not have pressed that they are
                # ready yet.
                emit('partnerLeft', room=found_game.agent.sid)

                # If the game hasn't started, remove it.
                if not found_game.both_loaded():
                    logger.debug(
                        "Completely removed game " + str(game_id) +
                        " because it has not started or loaded for both players."
                    )
                    live_games.pop(game_id)
                    db.disconnect_client(request.sid,
                                         'Disconnected Before Loading Game')
                    db.write_connection_event(
                        request.sid, "Quit Game Prematurely (Before Loading)")
                else:
                    db.disconnect_client(request.sid,
                                         'Disconnected During Game')
                    db.write_connection_event(
                        request.sid, "Quit Game Prematurely (Ongoing Game)")
    else:
        if found_game.using_agent:
            raise ValueError(
                '(game ID: ' + str(game_id) +
                ' When using the agent, the requester who disconnects should be a human.'
            )
        if found_game.human_quit:
            logger.debug('Removing game ' + str(game_id) +
                         ' from live games; both people quit.')
            db.disconnect_client(request.sid, 'Disconnected After Game')
            db.write_connection_event(request.sid, "Quit Game")

            # Check if in live games first -- might not be anymore if the partner
            # concurrently ended the game
            if game_id in live_games:
                live_games.pop(game_id)
        else:
            logger.debug('Human from game ' + str(game_id) +
                         ' is still there.')
            found_game.set_agent_quit()

            # Notify the agent that their partner left.
            emit('partnerLeft', room=found_game.human.sid)

            # If the game hasn't started, remove it.
            if not found_game.both_loaded():
                logger.debug(
                    "Completely removed game " + str(game_id) +
                    " because it has not started or loaded for both players.")
                live_games.pop(game_id)
                db.disconnect_client(request.sid,
                                     'Disconnected Before Loading Game')
                db.write_connection_event(
                    request.sid, "Quit Game Prematurely (Before Loading)")
            else:
                db.disconnect_client(request.sid, 'Disconnected During Game')
                db.write_connection_event(
                    request.sid, "Quit Game Prematurely (Ongoing Game)")