def tournament_engine_real_time(self): while not self.shutdown: print("[WAIT - TOURNAMENT ENGINE REAL-TIME]") self.shutdown_event.wait(timeout=get_run_time() / 3) try: now_run_time = timezone.now() self.check_games(has_started=True, multi_day=False, all_games_completed=False) self.cache_games(has_started=True, multi_day=False, is_cache_dirty=True) except: log_exception() finally: finished_time = timezone.now() next_run = timezone.now() + datetime.timedelta( seconds=get_run_time() / 3) total_run_time = (finished_time - now_run_time).total_seconds() log( "RT Engine done running at {}, ran for a total of {} seconds. Next run at {}" .format(finished_time, total_run_time, next_run), LogLevel.engine) print( "RT Engine done running at {}, ran for a total of {} seconds. Next run at {}" .format(finished_time, total_run_time, next_run))
async def game_logs(self, ctx, game_id=0, num_logs=-1, page=-1): try: if is_clotadmin(ctx.message.author.id): if game_id != 0 and num_logs != -1 and page != -1: # good print( "Game Id: {}, num_logs per page: {}, page: {}".format( game_id, num_logs, page)) game_logs = ProcessGameLog.objects.filter( game__gameid=int(game_id)).order_by('id') print("Number game logs: {}".format(game_logs.count())) paginator = Paginator(game_logs, num_logs) page = paginator.get_page(page) for log in page: await ctx.message.author.send(log.msg[0:1900]) if len(log.msg) > 1900: await ctx.message.author.send(log.msg[1900:]) else: await ctx.send( "You must pass in all parameters to the command.") else: await ctx.send("You must be an admin to use this command") except: log_exception() await ctx.send( "An error has occurred and was unable to process the command.")
def is_multiday(self): try: settings_dict = json.loads('''{}'''.format(self.template_settings)) if 'Pace' in self.template_settings: return settings_dict['Pace'] == "MultiDay" except: log_exception()
async def bet(self, ctx, team="", wager=""): try: discord_user = await self.bot.bridge.getdiscordUsers(memberid=ctx.message.author.id) if not discord_user: discord_user = await self.bot.bridge.createDiscordUser(memberid=ctx.message.author.id) else: discord_user = discord_user[0] player = await self.bot.bridge.getPlayers(discord_member=discord_user) if not len(player): await ctx.send(self.bot.discord_link_text) return player = player[0] if not team.isnumeric(): await ctx.send("{} is not a valid team id. Please enter a valid teamid. Betting via typing in a player's name isn't supported yet.".format(team)) return team = int(team) team_odds = await self.bot.bridge.getBetTeamOdds(pk=team) if not len(team_odds): await ctx.send("{} is not a valid bet id.".format(team)) return team_odds = team_odds[0] if not wager.isnumeric() or int(wager) < 1: await ctx.send("{} is not a valid wager. Please enter a valid wager amount.".format(wager)) return # check to see if the player has enough coins to bet wager = int(wager) if player.bankroll < wager: await ctx.send("You only have {} coins to bet with. Please use a smaller wager.".format(player.bankroll)) return if not team_odds.bet_game.game.betting_open: await ctx.send("Betting is no longer open for game {}.".format(team_odds.bet_game.gameid)) return for players_team in team_odds.bet_game.players.split('-'): for token in players_team.split('.'): if player.token == token: await ctx.send("You cannot bet on a game you are playing in. Please choose a different bet.") return # we have the game, tournament team and player with the wager... # go ahead and create the bet cb = await self.bot.bridge.getCLOTBook() if cb.calculate_decimal_odds_winnings(team_odds.decimal_odds, wager) < 1: await ctx.send("You must bet enough to win at least 1 coin. Please enter a different wager amount.") return bet = cb.create_new_bet(wager, player, team_odds) team_players = await self.bot.bridge.get_team_data_no_clan_player_list(team_odds.players.split('.')) await ctx.send("{} placed a bet on {} in game {} for {} coins to win {} coins.".format( ctx.message.author.name, team_players, team_odds.bet_game.game.id, bet.wager, bet.winnings)) except: log_exception()
def update_player_profiles_routine(self): while not self.shutdown: try: # Updates every player's name and clan self.update_all_player_clans() except: log_exception() print("[WAIT - PLAYER PROFILE UPDATE]") # Run once a day self.shutdown_event.wait(timeout=get_run_time() * 480)
def worker_routine(self): while not self.shutdown: try: self.process_mdl_games() self.parse_and_update_clan_logo() #self.process_team_vacations() # for now do not process any team vacations...that takes too long except Exception: log_exception() print("[WAIT - WORKER]") self.shutdown_event.wait(timeout=get_run_time() * 20)
def handle(self, *args, **options): try: if settings.DEBUG: bot = WZBot() bot.run(os.environ['WZ_TEST_BOT_TOKEN']) else: bot = WZBot() bot.run(os.environ['WZ_BOT_TOKEN']) except SystemExit: pass except Exception: log_exception()
def is_correct_player(self, player_token, player_team): try: player = Player.objects.filter(token=player_token)[0] tt = TournamentTeam.objects.filter(pk=player_team)[0] if player.clan and player.clan.name == tt.clan_league_clan.clan.name: return True tplayers = TournamentPlayer.objects.filter(team=tt) for tplayer in tplayers: if tplayer.player.token == player_token: return True return False except: log_exception() return False
def check_games(self, **kwargs): log("Running check_games on thread {}".format(threading.get_ident()), LogLevel.engine) tournaments = Tournament.objects.filter(**kwargs) for tournament in tournaments: games_in_progress = 0 if self.shutdown: return # if we get this far, we actually need to check the tournament child_tournament = find_tournament_by_id(tournament.id, True) if child_tournament and child_tournament.should_process_in_engine( ): try: games = TournamentGame.objects.filter( is_finished=False, tournament=tournament) games_in_progress = games.count() log( "[PROCESS GAMES]: Processing {} games for tournament {}" .format(games.count(), tournament.name), LogLevel.engine) for game in games.iterator(): # process the game # query the game status child_tournament.process_game(game) # in case tournaments get stalled for some reason # for it to process new games based on current tournament data child_tournament.process_new_games() if hasattr(child_tournament, 'clan_league_template' ) and not child_tournament.multi_day: child_tournament.multi_day = True child_tournament.save() except Exception as e: log_exception() finally: child_tournament.update_in_progress = False child_tournament.save() # if we are finished, and there are no outstanding games in progress...we are deemed "all_games_completed" if child_tournament.is_finished and games_in_progress == 0: log( "[PROCESS GAMES]: Child tournament {} has all games completed." .format(tournament.name), LogLevel.engine) child_tournament.all_games_completed = True child_tournament.save() gc.collect()
def tournament_engine(self): while not self.shutdown: print("[WAIT - TOURNAMENT ENGINE]") self.shutdown_event.wait(timeout=get_run_time() * 10) try: engine = Engine.objects.all() if not engine or engine.count() == 0: # create the engine object! engine = Engine() engine.save() else: engine = engine[0] engine.last_run_time = timezone.now() engine.next_run_time = timezone.now() + datetime.timedelta( seconds=get_run_time()) engine.save() print("Process Games Starting...") # bulk of the logic, we handle all types of tournaments separately here # there must be logic for each tournament type, as the child class contains # the logic self.check_games(has_started=True, multi_day=True, all_games_completed=False) self.cache_games(has_started=True, multi_day=True, is_cache_dirty=True) self.cleanup_logs() except Exception as e: log_exception() finally: finished_time = timezone.now() next_run = timezone.now() + datetime.timedelta( seconds=get_run_time()) total_run_time = (finished_time - engine.last_run_time).total_seconds() log( "Engine done running at {}, ran for a total of {} seconds. Next run at {}" .format(finished_time, total_run_time, next_run), LogLevel.engine) print( "Engine done running at {}, ran for a total of {} seconds. Next run at {}" .format(finished_time, total_run_time, next_run)) engine.last_run_time = finished_time engine.next_run_time = next_run engine.save()
def cache_games(self, **kwargs): tournaments = Tournament.objects.filter(**kwargs) for tournament in tournaments: games_in_progress = 0 if self.shutdown: return child_tournament = find_tournament_by_id(tournament.id, True) if child_tournament: log( "[CACHE]: Checking games for tournament: {}, shutdown: {}". format(tournament.name, self.shutdown), LogLevel.engine) try: # we only need to cache if there are unfinished games games = TournamentGame.objects.filter( tournament=child_tournament, is_finished=False) games_in_progress = games.count() child_tournament.cache_data() except Exception as e: log_exception() finally: log( "[CACHE]: Child tournament {} update done.".format( tournament.name), LogLevel.engine) # if the tournament is finished and there are no more outstanding games that are in progress # the cache is no longer dirty and we should stop looking at it log( "[CACHE]: {} has {} games in progress, is_finished: {}". format(child_tournament.name, games_in_progress, child_tournament.is_finished), LogLevel.engine) if child_tournament.is_finished and games_in_progress == 0: log( "[CACHE]: Child tournament {} cache is no longer dirty." .format(tournament.name), LogLevel.engine) child_tournament.is_cache_dirty = False child_tournament.save() elif games_in_progress > 0: child_tournament.is_cache_dirty = True child_tournament.save() # cache is not dirty...let's get this on the next time around gc.collect()
async def status(self, ctx, server): try: url = "" if server == "clot" or server == "CLOT": url = 'http://wzclot.eastus.cloudapp.azure.com' r = requests.get(url) elif server == "wz" or server == "WZ": url = 'https://www.warzone.com/MultiPlayer/' r = requests.get(url) r.status_code if str(r.status_code) == "200": status = "{} - ONLINE".format(url) else: status = "{} - OFFLINE".format(url) await ctx.send("Server Status: {}".format(status)) except: log_exception() await ctx.send( "An error has occurred and was unable to process the command.")
async def on_ready(self): try: await self.bridge.log_bot_msg( f'[CONNECT] Logged in as:\n{self.user} (ID: {self.user.id})\n') # cache all the guilds we're in when we login and the real-time-ladder channels for guild in self.guilds: if guild.name == "-B's CLOT": print("Found -B's CLOT, caching...id: {}".format(guild.id)) self.clot_server = guild for channel in guild.channels: if channel.name == "real-time-ladder" or channel.name == "real_time_ladder": print("Found RTL Channel in guild: {}".format( guild.name)) elif channel.name == "monthly-template-circuit" or channel.name == "monthly_template_circuit": print("Caching MTC channel in guild: {}".format( guild.name)) self.mtc_channels.append(channel) elif channel.name == "clan-league-bot-chat" or channel.name == "clan_league_bot_chat": print("Caching CL channel in guild: {}".format( guild.name)) self.clan_league_channels.append(channel) elif channel.name == "critical-errors": print("Caching Critical Error Channel in guild: {}". format(guild.name)) self.critical_error_channels.append(channel) if not hasattr(self, 'uptime'): self.uptime = timezone.now() print("Creating communication thread...") self.shutdown_thread = threading.Thread( target=self.handle_shutdown) self.shutdown_thread.start() print("Creating flushing thread") self.flush_thread = threading.Thread(target=self.flush) self.flush_thread.start() except Exception as e: log_exception()
def process_team_vacations(self): try: start_time = datetime.datetime.utcnow() log("Starting process team vacation: {}".format(start_time), LogLevel.engine) tournaments = Tournament.objects.filter(is_finished=False, has_started=True) for t in tournaments: if self.shutdown: return gc.collect() t = find_tournament_by_id(t.id, True) teams = TournamentTeam.objects.filter(tournament=t) for team in teams: if self.shutdown: return team.on_vacation = t.is_team_on_vacation(team) team.save() end_time = datetime.datetime.utcnow() log( "End process team vacations. Total Time: {}".format( (end_time - start_time).total_seconds()), LogLevel.engine) except Exception: log_exception()
def api_create_fake_game_and_get_settings(self, templateid): # first, create the game ret = {} data = {} data['hostEmail'] = self.client_email data['hostAPIToken'] = self.client_token data['templateID'] = templateid data['gameName'] = "get template settings" data['players'] = [{ "token": "OpenSeat", "team": "None" }, { "token": "OpenSeat", "team": "None" }] gameID = 0 try: gameInfo = self.api_create_game(data) gameInfo = gameInfo.json() # the game has been posted, make sure we have a game id and then query the settings if 'gameID' in gameInfo: # great, query the settings gameID = gameInfo['gameID'] data = {} data['gameID'] = gameID data['GetSettings'] = 'true' gameSettings = self.api_query_game_settings(gameID) # if 'error' in gameSettings.json(): # return an error, and just delete the game # got the settings, now send this back as we want to display in the form # for the creator # delete the game first deleteGame = self.api_delete_game(int(gameID)) deleteGame = deleteGame.json() if 'success' in deleteGame: # game deleted successfully ret['success'] = 'true' # convert the gameSettings we need from here into readable text so that the client doesn't have to do # any conversion gameSettings = gameSettings.json() log( "Getting settings for template: {}".format( gameSettings), LogLevel.informational) if 'settings' in gameSettings: settings = gameSettings['settings'] # this is so we can cache the entire template settings if the tournament actually gets created ret['settings'] = settings if 'Pace' in settings: # convert into days directbootTimeMinutes = gameSettings['settings'][ 'DirectBoot'] autobootTimeMinutes = gameSettings['settings'][ 'AutoBoot'] ret['Pace'] = gameSettings['settings']['Pace'] fmt = "" if ret['Pace'] == 'RealTime': fmt = '{0.minutes} minutes {0.seconds} seconds' else: fmt = '{0.days} days {0.hours} hours' if directbootTimeMinutes is not 'none': ret['directBoot'] = fmt.format( rd(minutes=directbootTimeMinutes)) if autobootTimeMinutes is not 'none': ret['autoBoot'] = fmt.format( rd(minutes=autobootTimeMinutes)) else: # not good, error, TODO: Log??? if 'error' in gameInfo: ret['error'] = gameInfo['error'] except: # catch the error, if we have created the game delete it here log_exception() if gameID is not 0 and 'success' not in ret: data = {} data['gameID'] = gameID deleteGame = self.api_delete_game(int(gameID)) if 'error' in gameInfo and gameInfo[ 'error'] == 'GameTemplateKeyNotFound': ret['error'] = "The template id is invalid. Please enter a valid template id!" elif 'success' not in ret: ret['error'] = "There was a problem with getting the template settings. Please try again later." return ret
def create_initial_odds_for_game(self, game, ratings1, ratings2): try: # get the ratings from the players in the game probs = self.probability_to_win(ratings1, ratings2) probs1 = probs[0] probs2 = probs[1] log_cb_msg( "Initial probabilities for gameid {}: {}% to {}%".format( game.gameid, probs1, probs2)) probability = "{}!{}".format(probs1, probs2) decimal1 = self.prob_to_decimal_odds(probs1) decimal2 = self.prob_to_decimal_odds(probs2) log_cb_msg("Decimal odds for gameid {}: {} {}".format( game.gameid, decimal1, decimal2)) american1 = self.decimal_odds_to_american(decimal1) american2 = self.decimal_odds_to_american(decimal2) # round the american to the nearest 5 or 0, and change that back into decimal log_cb_msg( "American odds for gameid {} before rounding: {} {}".format( game.gameid, american1, american2)) american1 = self.round_to_nearest_multiple(american1) american2 = self.round_to_nearest_multiple(american2) american_odds = "{}!{}".format(american1, american2) log_cb_msg("American odds for gameid {}: {}".format( game.gameid, american_odds)) decimal1 = self.american_odds_to_decimal(american1) decimal2 = self.american_odds_to_decimal(american2) decimal_odds = "{}!{}".format(decimal1, decimal2) log_cb_msg("Decimal odds for gameid {}: {}".format( game.gameid, decimal_odds)) bet_game = BetGameOdds(gameid=game.id, game=game, players=game.players, initial=True, decimal_odds=decimal_odds, probability=probability, american_odds=american_odds) bet_game.save() players1 = game.players.split('-')[0] players2 = game.players.split('-')[1] team_odds1 = BetTeamOdds(bet_game=bet_game, players_index=0, decimal_odds=decimal1, american_odds=american1, players=players1) team_odds1.save() team_odds2 = BetTeamOdds(bet_game=bet_game, players_index=1, decimal_odds=decimal2, american_odds=american2, players=players2) team_odds2.save() log_cb_msg("Created initial odds for gameid {}".format( game.gameid)) except: log_exception()
async def cb(self, ctx, option="", arg="", coins=""): try: discord_user = await self.bot.bridge.getDiscordUsers(memberid=ctx.message.author.id) if not discord_user: await self.bot.bridge.createDiscordUser(memberid=ctx.message.author.id) else: discord_user = discord_user[0] if option == "": await ctx.send("You must specify an option with this command.") return if option == "stats": await ctx.send("This command is currently under construction.") elif option == "on": if ctx.message.author.guild_permissions.administrator or is_clotadmin(ctx.message.author.id): if arg == "results": # create a link for results only discord_channel_link = await self.bot.bridge.getDiscordChannelClotBookLinks( channelid=ctx.message.channel.id, results_only=True) if len(discord_channel_link.count) > 0: await ctx.send("There is already a CLOTBook results link to this channel.") return await self.bot.bridge.createChannelClotbookLink(channelid=ctx.message.channel.id, discord_user=discord_user, results_only=True) await ctx.send("The CLOTBook will start using this channel to send live betting results.") else: discord_channel_link = await self.bot.bridge.getDiscordChannelClotBookLinks(channelid=ctx.message.channel.id, results_only=True) if len(discord_channel_link.count) == 0: await self.bot.bridge.createChannelClotbookLink(channelid=ctx.message.channel.id, discord_user=discord_user) await ctx.send("The CLOTBook will start using this channel to send live betting updates.") else: await ctx.send("This channel is already registered to receive CLOTBook Updates") else: await ctx.send("You must be a server administrator to use this command.") elif option == "off": if ctx.message.author.guild_permissions.administrator or is_clotadmin(ctx.message.author.id): if arg == "results": discord_channel_link = await self.bot.bridge.getDiscordChannelClotBookLinks(channelid=ctx.message.channel.id, results_only=True) if discord_channel_link: await self.bot.bridge.deleteObject(discord_channel_link[0]) await ctx.send("The CLOTBook will no longer use this channel for sending results.") else: await ctx.send("This channel is not hooked up to receive CLOTBook updates.") else: discord_channel_link = await self.bot.bridge.getDiscordChannelClotBookLinks(channelid=ctx.message.channel.id, results_only=False) if discord_channel_link: await self.bot.bridge.deleteObject(discord_channel_link[0]) await ctx.send("The CLOTBook will no longer use this channel for updates.") else: await ctx.send("This channel is not hooked up to receive CLOTBook updates.") else: await ctx.send("You must be a server administrator to use this command.") elif option == "me": player = await self.bot.bridge.getPlayers(discord_member=discord_user) if not player: await ctx.send(self.bot.discord_link_text) return player = player[0] user = self.bot.get_user(discord_user.memberid) emb = self.bot.get_embed(user) emb.title = "{}'s last 10 bets".format(user.name) bets = await self.bot.bridge.getBetsOrderByCreatedTime(player=player) total_bets = len(bets) bets = bets[:10] bet_text = "" for bet in bets: if bet.game.is_finished: bet_text += "[Game Link]({}) - Bet {} coins, ".format(bet.game.game_link, bet.wager) if bet.winnings == 0: bet_text += "and lost bet\n" else: bet_text += "and won {} coins\n".format(bet.winnings) else: bet_text += "Bet {} coins on [Game]({}) to win {}\n".format(bet.wager, bet.game.game_link, bet.winnings) if len(bet_text) > 0: emb.add_field(name="Bets", value=bet_text) info_text = "Total Bets: {}\nBankroll: {} coins".format(total_bets, player.bankroll) emb.add_field(name="Info", value=info_text) await ctx.send(embed=emb) elif option == "initial": if not is_clotadmin(ctx.message.author.id): await ctx.send("Only CLOT admins can use this command.") return if arg.isnumeric(): game = await self.bot.bridge.getGames(gameid=arg) if not len(game): game = await self.bot.bridge.getGames(pk=int(arg)) if not len(game): await ctx.send("You must specify a valid game id to use with this command.") return game = game[0] odds = await self.bot.bridge.getBetGameOdds(game=game) for odd in odds: odd.delete() game.create_initial_lines() await ctx.send("Updated initial lines for game {}".format(game.gameid)) return elif option == "br": if not is_clotadmin(ctx.message.author.id): await ctx.send("Only CLOT admins can use this command.") return player = await self.bot.bridge.getPlayers(token=arg) if not len(player): await ctx.send("Player with token {} cannot be found in the CLOT database.") return if coins.isnumeric(): player[0].bankroll += float(coins) player[0].save() elif option.isnumeric(): # try to look up the game id game = int(option) else: await ctx.send("You must specify an option with this command.") except: log_exception()