async def refresh_channel_queue(self, channel: TextChannel, restart: bool): """ Deletes the previous queue message and sends a new one in the channel If channel is supplied instead of a context (in the case of a bot reboot), send the reboot message instead """ rows = [] # Creating the queue visualisation requires getting the Player objects from the DB to have the names queue = game_queue.GameQueue(channel.id) for role, role_queue in queue.queue_players_dict.items(): rows.append(f"{get_role_emoji(role)} " + ", ".join(qp.player.short_name for qp in role_queue)) # Create the queue embed embed = Embed(colour=embeds_color) embed.add_field(name="Queue", value="\n".join(rows)) embed.set_footer( text= "Use !queue [role] to queue | All non-queue messages in this channel are deleted" ) # We save the message object in our local cache new_queue = await channel.send( "The bot was restarted and all players in ready-check have been put back in queue\n" "The matchmaking process will restart once anybody queues or re-queues" if channel else None, embed=embed, ) self.latest_queue_message_ids[channel.id] = new_queue.id
async def refresh_channel_queue(self, channel: TextChannel, restart: bool): """ Deletes the previous queue message and sends a new one in the channel If channel is supplied instead of a context (in the case of a bot reboot), send the reboot message instead """ # Creating the queue visualisation requires getting the Player objects from the DB to have the names new_queue = game_queue.GameQueue(channel.id) # If the new queue is the same as the cache, we simple return if new_queue == self._queue_cache.get(channel.id): return else: # Else, we update our cache (useful to not send too many messages) self._queue_cache[channel.id] = new_queue rows = [] for role, role_queue in new_queue.queue_players_dict.items(): rows.append(f"{get_role_emoji(role)} " + ", ".join(qp.player.short_name for qp in role_queue)) # Create the queue embed embed = Embed(colour=embeds_color) embed.add_field(name="Queue", value="\n".join(rows)) embed.set_footer( text= "Use !queue [role] to join or !leave to leave | All non-queue messages are deleted" ) message_text = "" if restart: message_text += ( "\nThe bot was restarted and all players in ready-check have been put back in queue\n" "The matchmaking process will restart once anybody queues or re-queues" ) # We save the message object in our local cache new_queue_message = await channel.send( message_text, embed=embed, ) self.latest_queue_message_ids[channel.id] = new_queue_message.id
async def run_matchmaking_logic( self, ctx: commands.Context, ): """ Runs the matchmaking logic in the channel defined by the context Should only be called inside guilds """ queue = game_queue.GameQueue(ctx.channel.id) game = matchmaking_logic.find_best_game(queue) if not game: return elif game and game.matchmaking_score < 0.2: embed = game.get_embed(embed_type="GAME_FOUND", validated_players=[], bot=self.bot) # We notify the players and send the message ready_check_message = await ctx.send(content=game.players_ping, embed=embed, delete_after=60 * 15) # We mark the ready check as ongoing (which will be used to the queue) game_queue.start_ready_check( player_ids=game.player_ids_list, channel_id=ctx.channel.id, ready_check_message_id=ready_check_message.id, ) # We update the queue in all channels await queue_channel_handler.update_queue_channels( bot=self.bot, server_id=ctx.guild.id) # And then we wait for the validation try: ready, players_to_drop = await checkmark_validation( bot=self.bot, message=ready_check_message, validating_players_ids=game.player_ids_list, validation_threshold=10, game=game, ) # We catch every error here to make sure it does not become blocking except Exception as e: self.bot.logger.error(e) game_queue.cancel_ready_check( ready_check_id=ready_check_message.id, ids_to_drop=game.player_ids_list, server_id=ctx.guild.id, ) await ctx.send( "There was a bug with the ready-check message, all players have been dropped from queue\n" "Please queue again to restart the process") await queue_channel_handler.update_queue_channels( bot=self.bot, server_id=ctx.guild.id) return if ready is True: # We drop all 10 players from the queue game_queue.validate_ready_check(ready_check_message.id) # We commit the game to the database (without a winner) with session_scope() as session: session.expire_on_commit = False game = session.merge(game) # This gets us the game ID queue_channel_handler.mark_queue_related_message( await ctx.send(embed=game.get_embed("GAME_ACCEPTED"), )) elif ready is False: # We remove the player who cancelled game_queue.cancel_ready_check( ready_check_id=ready_check_message.id, ids_to_drop=players_to_drop, channel_id=ctx.channel.id, ) await ctx.send( f"A player cancelled the game and was removed from the queue\n" f"All other players have been put back in the queue", ) # We restart the matchmaking logic await self.run_matchmaking_logic(ctx) elif ready is None: # We remove the timed out players from *all* channels (hence giving server id) game_queue.cancel_ready_check( ready_check_id=ready_check_message.id, ids_to_drop=players_to_drop, server_id=ctx.guild.id, ) await ctx.send( "The check timed out and players who did not answer have been dropped from all queues", ) # We restart the matchmaking logic await self.run_matchmaking_logic(ctx) elif game and game.matchmaking_score >= 0.2: # One side has over 70% predicted winrate, we do not start anything await ctx.send( f"The best match found had a side with a {(.5 + game.matchmaking_score)*100:.1f}%" f" predicted winrate and was not started")
async def refresh_channel_queue(self, channel: TextChannel, restart: bool): """ Deletes the previous queue message and sends a new one in the channel If channel is supplied instead of a context (in the case of a bot reboot), send the reboot message instead """ # Creating the queue visualisation requires getting the Player objects from the DB to have the names queue = game_queue.GameQueue(channel.id) # If the new queue is the same as the cache, we simple return if queue == self._queue_cache.get(channel.id): return else: # Else, we update our cache (useful to not send too many messages) self._queue_cache[channel.id] = queue # Create the queue embed embed = Embed(colour=embeds_color) # Adding queue field queue_rows = [] for role, role_queue in queue.queue_players_dict.items(): queue_rows.append( f"{get_role_emoji(role)} " + ", ".join(qp.player.short_name for qp in role_queue) ) embed.add_field(name="Queue", value="\n".join(queue_rows)) # Adding duos field if it’s not empty if queue.duos: duos_strings = [] for duo in queue.duos: duos_strings.append( " + ".join(f"{qp.player.short_name} {get_role_emoji(qp.role)}" for qp in duo) ) embed.add_field(name="Duos", value=", ".join(duos_strings)) embed.description = "" embed.add_field(name="Gamers Club", value="[**PARTICIPE DO GC RIFT BY RAZER E DISPUTE 5000 REAIS EM PREMIAÇÃO. INSCREVA-SE AGORA!**](https://bit.ly/37AqphB)", inline=False) embed.set_image(url="https://cdn.discordapp.com/attachments/796818933255766056/813598337793261599/ezgif.com-gif-maker_2.gif") embed.set_footer( text=f"Use {PREFIX}queue [role] para entrar ou !leave para sair" ) message_text = "" if restart: message_text += ( "\nThe bot was restarted and all players in ready-check have been put back in queue\n" "The matchmaking process will restart once anybody queues or re-queues" ) # We save the message object in our local cache new_queue_message = await channel.send(message_text, embed=embed,) self.latest_queue_message_ids[channel.id] = new_queue_message.id
async def run_matchmaking_logic( self, ctx: commands.Context, ): """ Runs the matchmaking logic in the channel defined by the context Should only be called inside guilds """ queue = game_queue.GameQueue(ctx.channel.id) game = matchmaking_logic.find_best_game(queue) if not game: return elif game and game.matchmaking_score < 0.2: embed = Embed( title="📢 Game found 📢", description= f"Blue side expected winrate is {game.blue_expected_winrate * 100:.1f}%\n" "If you are ready to play, press ✅\n" "If you cannot play, press �", ) embed = game.add_game_field(embed, []) # We notify the players and send the message ready_check_message = await ctx.send( content= f"||{' '.join([f'<@{discord_id}>' for discord_id in game.player_ids_list])}||", embed=embed, ) # Because it still takes some time, we *directly* add it to the *no delete* list # That’s dirty and should likely be handled in a better way (maybe by *not* using purge # and choosing what to delete instead, but it also has its issues) # TODO HIGH PRIO Think about saving a "messages to not delete list" in the queue handler memory and # use it in the cog listener, and automatically delete any other one after 5s? should work better (less bugs) queue_channel_handler.mark_queue_related_message( ready_check_message) # We mark the ready check as ongoing (which will be used to the queue) game_queue.start_ready_check( player_ids=game.player_ids_list, channel_id=ctx.channel.id, ready_check_message_id=ready_check_message.id, ) # We update the queue in all channels await queue_channel_handler.update_server_queues( bot=self.bot, server_id=ctx.guild.id) # And then we wait for the validation ready, players_to_drop = await checkmark_validation( bot=self.bot, message=ready_check_message, validating_players_ids=game.player_ids_list, validation_threshold=10, timeout=3 * 60, game=game, ) if ready is True: # We drop all 10 players from the queue game_queue.validate_ready_check(ready_check_message.id) # We commit the game to the database (without a winner) with session_scope() as session: session.add(game) embed = Embed( title="📢 Game accepted 📢", description= f"Game {game.id} has been validated and added to the database\n" f"Once the game has been played, one of the winners can score it with `!won`\n" f"If you wish to cancel the game, use `!cancel`", ) embed = game.add_game_field(embed) queue_channel_handler.mark_queue_related_message( await ctx.send(embed=embed, )) elif ready is False: # We remove the player who cancelled game_queue.cancel_ready_check( ready_check_id=ready_check_message.id, ids_to_drop=players_to_drop, channel_id=ctx.channel.id, ) queue_channel_handler.mark_queue_related_message(await ctx.send( f"A player cancelled the game and was removed from the queue\n" f"All other players have been put back in the queue")) # We restart the matchmaking logic await self.run_matchmaking_logic(ctx) elif ready is None: # We remove the timed out players from *all* channels (hence giving server id) game_queue.cancel_ready_check( ready_check_id=ready_check_message.id, ids_to_drop=players_to_drop, server_id=ctx.guild.id, ) queue_channel_handler.mark_queue_related_message(await ctx.send( "The check timed out and players who did not answer have been dropped from all queues" )) # We restart the matchmaking logic await self.run_matchmaking_logic(ctx) elif game and game.matchmaking_score >= 0.2: # One side has over 70% predicted winrate, we do not start anything await ctx.send( f"The best match found had a side with a {(.5 + game.matchmaking_score)*100:.1f}%" f" predicted winrate and was not started")