def createGame(the_players, templateID, tourney_id): """This calls the WarLight.net API to create a game, and then creates the Game and GamePlayer rows in the local DB""" gameName = ' vs '.join([p.name for p in the_players])[:50] #game names are limited to %) characters by the api config = main.getClotConfig(tourney_id) apiRetStr = main.postToApi('/API/CreateGame', json.dumps( { 'hostEmail': config.adminEmail, 'hostAPIToken': config.adminApiToken, 'templateID': templateID, 'gameName': gameName, 'personalMessage': 'a game from one of unknwonsoldiers tourneys', 'players': [ { 'token': p.inviteToken, 'team': 'None' } for p in the_players] })) apiRet = json.loads(apiRetStr) gid = int(apiRet.get('gameID', -1)) if gid == -1: raise Exception("CreateGame returned error: " + apiRet.get('error', apiRetStr)) g = Game(wlnetGameID=gid, name=gameName, tourney_id=tourney_id) g.save() for p in the_players: gameplayer = games.GamePlayer(playerID = p.key().id(), gameID = g.key().id(), tourney_id=tourney_id) gameplayer.save() logging.info("Created game " + str(g.key().id()) + " '" + gameName + "'") return g
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 get(self): cache = memcache.get('home') #if cache is not None: # return self.response.write(cache) #Check if we need to do first-time setup if getClotConfig() is None: return self.redirect('/setup') html = get_template('home.html').render({ 'lots': list(lot.LOT.query()) }) if not memcache.add('home', html): logging.info("Memcache add failed") self.response.write(html)
def get(self): cache = memcache.get('home') #if cache is not None: # return self.response.write(cache) #Check if we need to do first-time setup if getClotConfig() is None: return self.redirect('/setup') html = get_template('home.html').render( {'lots': list(lot.LOT.query())}) if not memcache.add('home', html): logging.info("Memcache add failed") self.response.write(html)
def go(request, tourney_id, playerID): tourney_id = int(tourney_id) tourney_clotconfig = main.getClotConfig(tourney_id) playerID = int(playerID) p = players.Player.get_by_id(playerID) gameIDs = set([g.gameID for g in games.GamePlayer.all().filter("tourney_id =", int(tourney_id)).filter('playerID =', playerID)]) ###.run(batch_size=1000)]) the_games = [g for g in games.Game.all() if g.key().id() in gameIDs] if not main.doesTourneyExist(tourney_id, tourney_clotconfig): logging.info('tourney does not exist') return shortcuts.render_to_response('tourney_does_not_exist.html') return shortcuts.render_to_response('player_does_not_exist_in_this_tourney.html') return shortcuts.render_to_response('viewplayer.html', {'player': p, 'games': the_games, 'tourney_id': tourney_id, 'tourney_name': main.getTourneyName(int(tourney_id), tourney_clotconfig), 'tourney_path': '/tourneys/' + str(tourney_id) })
def go(request): """Create a player. GET shows a blank form, POST processes it.""" logging.info('in join.go') form = JoinForm(data=request.POST or None) #now deal with the form etc if not request.POST: return shortcuts.render_to_response('join.html', {'form': form}) if not form.is_valid(): return shortcuts.render_to_response('join.html', {'form': form}) #see if we are letting more players join. tourney_id = int(form.clean_data['tourney_id']) tourney_clotconfig = main.getClotConfig(tourney_id)#.run(batch_size=1000) if not tourney_clotconfig: form.errors['tourney_id'] = 'tourney_id is invalid.' return shortcuts.render_to_response('join.html', {'form': form}) players_are_gated_q = False if main.arePlayersGated(tourney_id, tourney_clotconfig): players_are_gated_q = True logging.info('players_are_gated_q = '+str(players_are_gated_q)) return http.HttpResponseRedirect('/players_are_gated') if players.numPlayersParticipating(tourney_id) >= main.getMaximumNumberOfPlayers(tourney_id, tourney_clotconfig): logging.info('too many players') return http.HttpResponseRedirect('/cannot_join') inviteToken = form.clean_data['inviteToken'] #Call the warlight API to get the name, color, and verify that the invite token is correct apiret = main.hitapi('/API/ValidateInviteToken', { 'Token': inviteToken }) if not "tokenIsValid" in apiret: form.errors['inviteToken'] = 'The supplied invite token is invalid. Please ensure you copied it from WarLight.net correctly.' return shortcuts.render_to_response('join.html', {'form': form}) tourney_password = str(form.clean_data['tourney_password']) if main.getIfRequirePasswordToJoin(tourney_id, tourney_clotconfig): if tourney_password != main.getTourneyPassword(tourney_id, tourney_clotconfig): form.errors['tourney_password'] = '******' return shortcuts.render_to_response('join.html', {'form': form}) #Ensure this invite token doesn't already exist existing = players.Player.all().filter('inviteToken =', inviteToken).filter("tourney_id =", tourney_id).get() if existing: #If someone tries to join when they're already in the DB, just set their isParticipating flag back to true existing.isParticipating = True existing.save() return http.HttpResponseRedirect('tourneys/' + str(tourney_id) + '/player/' + str(existing.key().id())) data = json.loads(apiret) player_name = data['name'] if type(data['name']) is unicode: logging.info('dealing with unicode player name ...') player_name = player_name.encode('ascii','ignore') #this deals with special characters that would mess up our code, by removing them. logging.info('player_name:') logging.info(player_name) logging.info('player-name looks ok or not?') player = players.Player(inviteToken=inviteToken, name=player_name, color=data['color'], isMember=data['isMember'].lower() == 'true') if main.getIsMembersOnly(tourney_id, tourney_clotconfig) and not player.isMember: form.errors['inviteToken'] = 'This site only allows members to join. See the Membership tab on WarLight.net for information about memberships.' return shortcuts.render_to_response('join.html', {'form': form}) player.put() player.player_id = str(player.key().id()) player.tourney_id = tourney_id player.save() logging.info("Created player") logging.info(player) return http.HttpResponseRedirect('tourneys/' + str(tourney_id) + '/player/' + str(player.key().id()))
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'])
def hitapi(api, params): config = getClotConfig() return hitapiwithauth(api, params, config.adminEmail, config.adminApiToken)
def index_new(request,tourney_id): """Request / """ logging.info('in index_new(' +str(tourney_id)+ ')') tourney_id = int(tourney_id) logging.info('tourney_id = '+str(tourney_id)) tourney_clotconfig = main.getClotConfig(tourney_id) if not main.doesTourneyExist(tourney_id, tourney_clotconfig): logging.info('tourney does not exist, redirecting user to tourneys info instead') return shortcuts.render_to_response('tourney_does_not_exist.html' ) #arrange players by rank the_players = players.Player.all().filter("tourney_id =", tourney_id)#.run(batch_size=1000) the_players = sorted(the_players, key=lambda z: z.currentRank) gamePlayers = main.group(games.GamePlayer.all().filter("tourney_id =", tourney_id), lambda z: z.gameID) #.run(batch_size=1000) #arrange games by reverse of created date the_games = games.Game.all().filter("tourney_id =", tourney_id)#.run(batch_size=1000) the_games = sorted(the_games, key=lambda z: z.dateCreated, reverse=True) #for game in the_games: # logging.info('game: '+str(game)) # logging.info('game.winningTeamName = '+str(game.winningTeamName)) #do the head-to-head table biggermat, head_to_head_2d = new_utility_functions.getHeadToHeadTable(tourney_id) biggermat_str = deepcopy(biggermat) for i in range(1,len(biggermat_str)): for j in range(1,len(biggermat_str[i])): if i==j: biggermat_str[i][j] = "---" else: biggermat_str[i][j] = str(biggermat_str[i][j][0]) + "-" + str(biggermat_str[i][j][1]) #see if players are gated players_gated_string = "players may join or leave" if main.arePlayersGated(tourney_id, tourney_clotconfig): players_gated_string = "players may NOT join or leave" #get tourney_status_string tourney_status_string = 'Tourney Not Yet Started' if main.isTourneyInPlay(tourney_id, tourney_clotconfig): if str(main.getTourneyType(tourney_id, tourney_clotconfig)) == 'swiss': tourney_status_string = 'Tourney In Progress. Round '+str(main.getRoundNumber(tourney_id, tourney_clotconfig))+' of '+str(main.getNumRounds(tourney_id, tourney_clotconfig)) else: tourney_status_string = 'Tourney In Progress.' elif main.hasTourneyFinished(tourney_id, tourney_clotconfig): winner = the_players[0] winner_name = winner.name tourney_status_string = 'Tourney has finished. Congratulations to '+str(winner_name)+'!' minNumPlayersString= 'minNumPlayers: '+str(main.getMinimumNumberOfPlayers(tourney_id, tourney_clotconfig)) maxNumPlayersString= 'maxNumPlayers: '+str(main.getMaximumNumberOfPlayers(tourney_id, tourney_clotconfig)) starttimeString = 'starttime will be: '+str(main.getStarttime(tourney_id, tourney_clotconfig))+' provided we have minimum number of players.' currentTimeString = 'current time = '+str(main.getCurrentTime()) tourney_type_string = str(main.getTourneyType(tourney_id, tourney_clotconfig)) + ' tourney' how_long_you_have_to_join_games_string = 'You have '+str(main.getHowLongYouHaveToJoinGames(tourney_id, tourney_clotconfig))+' minutes to join your auto-created games. After that you may lose that game!!' template_id = main.getTemplateID(tourney_id, tourney_clotconfig) #things for specific tourney types if main.getTourneyType(tourney_id, tourney_clotconfig)=='swiss': swiss_games_info_table = tournament_swiss.getTourneyRoundsAndGameInfo(tourney_id) else: swiss_games_info_table = 0 #end of things for specific tourney types return shortcuts.render_to_response('tourney_home.html',{'players': the_players, 'config': tourney_clotconfig, 'games': the_games, 'biggermat':biggermat_str, 'players_gated_string':players_gated_string, 'minNumPlayersString':minNumPlayersString, 'maxNumPlayersString':maxNumPlayersString, 'tourney_status_string':tourney_status_string, 'starttimeString':starttimeString, 'currentTimeString':currentTimeString, 'tourney_type_string':tourney_type_string, 'how_long_you_have_to_join_games_string':how_long_you_have_to_join_games_string, 'template_title_string':'Game Template', 'template_id':template_id, 'swiss_games_info_table':swiss_games_info_table, 'join_url':'/tourneys/'+str(tourney_id)+'/join', 'leave_url':'/tourneys/'+str(tourney_id)+'/leave', 'tourney_id':str(tourney_id) })