def createGame(request, container, players, templateID): """This calls the WarLight.net API to create a game, and then creates the Game rows in the local DB""" gameName = ' vs '.join([p.name for p in players])[:50] config = getClotConfig() apiRetStr = postToApi('/API/CreateGame', json.dumps( { 'hostEmail': config.adminEmail, 'hostAPIToken': config.adminApiToken, 'templateID': templateID, 'gameName': gameName, 'personalMessage': 'Created by the CLOT at http://' + urlparse.urlparse(request.url).netloc, 'players': [ { 'token': p.inviteToken, 'team': 'None' } for p in players] })) apiRet = json.loads(apiRetStr) gid = long(apiRet.get('gameID', -1)) if gid == -1: raise Exception("CreateGame returned error: " + apiRet.get('error', apiRetStr)) g = Game(lotID=container.lot.key.id(), wlnetGameID=gid, name=gameName) g.players = [p.key.id() for p in players] g.put() #Ensure we update the container with the new game. The players may already be there, but put them in in case they're not container.games.append(g) for p in players: container.players[p.key.id()] = p logging.info("Created game " + str(g.key.id()) + " '" + gameName + "', wlnetGameID=" + str(gid)) return g
def checkInProgressGames(container): """This is called periodically to look for games that are finished. If we find a finished game, we record the winner""" #Find all games that we think aren't finished activeGames = [g for g in container.games if g.winner is None] for g in activeGames: #call WarLight's GameFeed API so that it can tell us if it's finished or not apiret = hitapi('/API/GameFeed?GameID=' + str(g.wlnetGameID), {}) data = json.loads(apiret) state = data.get('state', 'err') if state == 'err': raise Exception("GameFeed API failed. Message = " + data.get('error', apiret)) if state == 'Finished': #It's finished. Record the winner and save it back. winner = findWinner(container, data) logging.info('Identified the winner of game ' + str(g.wlnetGameID) + ' is ' + unicode(winner)) g.winner = winner.key.id() g.dateEnded = datetime.datetime.now() g.put() elif state == 'WaitingForPlayers': #It's in the lobby still. Check if it's been too long. elapsed = datetime.datetime.now() - g.dateCreated if not clot.gameFailedToStart(elapsed): logging.info("Game " + str(g.wlnetGameID) + " is in the lobby for " + str(elapsed.days) + " days.") else: logging.info('Game ' + str(g.wlnetGameID) + " is stuck in the lobby. Marking it as a loss for anyone who didn't join and deleting it.") #Delete it over at warlight.net so that players know we no longer consider it a real game config = getClotConfig() deleteRet = postToApi('/API/DeleteLobbyGame', json.dumps( { 'Email': config.adminEmail, 'APIToken': config.adminApiToken, 'gameID': g.wlnetGameID })) #If the API doesn't return success, just ignore this game on this run. This can happen if the game just started between when we checked its status and when we told it to delete. if 'success' not in deleteRet: logging.info("DeleteLobbyGame did not return success. Ignoring this game for this run. Return=" + deleteRet) else: #We deleted the game. Mark it as deleted and finished g.deleted = True g.winner = findWinnerOfDeletedGame(container, data).key.id() g.put() #Also remove anyone that declines or fails to join from the ladder. This is important for real-time ladders since we don't want idle people staying in forever, but you may not want this for your situation for playerID in [getPlayerByInviteToken(container, p['id']).key.id() for p in data['players'] if p['state'] != 'Playing']: if playerID in container.lot.playersParticipating: container.lot.playersParticipating.remove(playerID) logging.info("Removed " + str(playerID) + " from ladder since they did not join game " + str(g.wlnetGameID)) else: #It's still going. logging.info('Game ' + str(g.wlnetGameID) + ' is not finished, state=' + state + ', numTurns=' + data['numberOfTurns'])
def checkInProgressGames(container): """This is called periodically to look for games that are finished. If we find a finished game, we record the winner""" #Find all games that we think aren't finished activeGames = [g for g in container.games if g.winner is None] for g in activeGames: #call WarLight's GameFeed API so that it can tell us if it's finished or not apiret = hitapi('/API/GameFeed?GameID=' + str(g.wlnetGameID), {}) data = json.loads(apiret) state = data.get('state', 'err') if state == 'err': raise Exception("GameFeed API failed. Message = " + data.get('error', apiret)) if state == 'Finished': #It's finished. Record the winner and save it back. winner = findWinner(container, data) logging.info('Identified the winner of game ' + str(g.wlnetGameID) + ' is ' + unicode(winner)) g.winner = winner.key.id() g.dateEnded = datetime.datetime.now() g.put() elif state == 'WaitingForPlayers': #It's in the lobby still. Check if it's been too long. elapsed = datetime.datetime.now() - g.dateCreated players = data.get('players', 'err') if players == 'err' : raise Exception("GameFeed API failed. Message = " + data.get('error', apiret)) hasEitherPlayerDeclined = False for p in players: playerState = p.get('state', 'err') if playerState =='err' : raise Exception("GameFeed API failed. Message = " + data.get('error', apiret)) if playerState == 'Declined': hasEitherPlayerDeclined = True break if clot.gameFailedToStart(elapsed) or hasEitherPlayerDeclined == True: logging.info('Game ' + str(g.wlnetGameID) + " is stuck in the lobby. Marking it as a loss for anyone who didn't join and deleting it.") #Delete it over at warlight.net so that players know we no longer consider it a real game config = getClotConfig() deleteRet = postToApi('/API/DeleteLobbyGame', json.dumps( { 'Email': config.adminEmail, 'APIToken': config.adminApiToken, 'gameID': g.wlnetGameID })) #If the API doesn't return success, just ignore this game on this run. This can happen if the game just started between when we checked its status and when we told it to delete. if 'success' not in deleteRet: logging.info("DeleteLobbyGame did not return success. Ignoring this game for this run. Return=" + deleteRet) else: #We deleted the game. Mark it as deleted and finished g.deleted = True g.winner = findWinnerOfDeletedGame(container, data).key.id() g.put() #Also remove anyone that declines or fails to join from the ladder. This is important for real-time ladders since we don't want idle people staying in forever, but you may not want this for your situation for playerID in [getPlayerByInviteToken(container, p['id']).key.id() for p in data['players'] if p['state'] != 'Playing']: if playerID in container.lot.playersParticipating: container.lot.playersParticipating.remove(playerID) logging.info("Removed " + str(playerID) + " from ladder since they did not join game " + str(g.wlnetGameID)) else : logging.info("Game " + str(g.wlnetGameID) + " is in the lobby for " + str(elapsed.days) + " days.") else: #It's still going. logging.info('Game ' + str(g.wlnetGameID) + ' is not finished, state=' + state + ', numTurns=' + data['numberOfTurns'])