From 15945d839c167039e8db1133b40853750ae284d8 Mon Sep 17 00:00:00 2001 From: Elnath Date: Sat, 12 Jun 2021 19:07:26 +0200 Subject: [PATCH] Game: using asyncio tasks to run in parallel operation that do not need to be sequential --- GameFiles/Game.py | 76 ++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/GameFiles/Game.py b/GameFiles/Game.py index e443d3d..235aac5 100644 --- a/GameFiles/Game.py +++ b/GameFiles/Game.py @@ -1,9 +1,10 @@ +import asyncio import logging import random -from typing import Dict, Callable, List, Union -from functools import wraps from collections import defaultdict from enum import Enum +from functools import wraps +from typing import Dict, Callable, List, Union import discord @@ -174,6 +175,8 @@ class Game: if self.is_started(): raise ValueError("Game already started") logger.info(f"[{self.guild.name}] Starting game") + tasks = [] # Asyncio tasks scheduled to run in parallel (e.g. channel creation), so that we can wait them all at the end of the function + self.config["game_started"] = True self.config["gm_role"] = gm_role.id self.config["player_role"] = player_role.id self.config["players"] = [member.id for member in player_role.members] @@ -185,51 +188,62 @@ class Game: self.config["drawn"] = None self.config["enacted"] = [] - permissions = { + category_permissions = { self.guild.default_role: discord.PermissionOverwrite(send_messages = False), gm_role: discord.PermissionOverwrite(send_messages = True), player_role: discord.PermissionOverwrite(send_messages = True), } - game_category = await self.guild.create_category("In-game", overwrites = permissions) + game_category = await self.guild.create_category("In-game", overwrites = category_permissions) self.config["category"] = game_category.id logger.debug(f"[{self.guild.name}] Created game category") - permissions = { - self.guild.default_role: discord.PermissionOverwrite(read_messages = False), - gm_role: discord.PermissionOverwrite(read_messages = True), - } - self.config["admin_chan"] = (await game_category.create_text_channel("admin", overwrites = permissions)).id - logger.debug(f"[{self.guild.name}] Created admin channel") + async def create_admin_chan(): + perms = { + self.guild.default_role: discord.PermissionOverwrite(read_messages = False), + gm_role: discord.PermissionOverwrite(read_messages = True), + } + self.config["admin_chan"] = (await game_category.create_text_channel("admin", overwrites = perms, position = 0)).id + logger.debug(f"[{self.guild.name}] Created admin channel") + tasks.append(asyncio.create_task(create_admin_chan())) - permissions = { - self.guild.default_role: discord.PermissionOverwrite(send_messages = False), - gm_role: discord.PermissionOverwrite(send_messages = True), - } - self.config["announce_chan"] = (await game_category.create_text_channel("announce", overwrites = permissions)).id - self.config["votes_chan"] = (await game_category.create_text_channel("votes", overwrites = permissions)).id - logger.debug(f"[{self.guild.name}] Created announcements and votes channels") + async def create_announcements_and_vote_chans(): + perms = { + self.guild.default_role: discord.PermissionOverwrite(send_messages = False), + gm_role: discord.PermissionOverwrite(send_messages = True), + } + channels = await asyncio.gather( + game_category.create_text_channel("announcements", overwrites = perms, position = 1), + game_category.create_text_channel("votes", overwrites = perms, position = 2) + ) + self.config["announce_chan"] = channels[0].id + self.config["votes_chan"] = channels[1].id + logger.debug(f"[{self.guild.name}] Created announcements and votes channels") + tasks.append(asyncio.create_task(create_announcements_and_vote_chans())) - self.config["discussion_chan"] = (await game_category.create_text_channel("discussion")).id # Permissions are inherited from the category - logger.debug(f"[{self.guild.name}] Created discussion channel") + async def create_discussion_chan(): + # Permissions are inherited from the category + self.config["discussion_chan"] = (await game_category.create_text_channel("discussion", position = 3)).id # Permissions are inherited from the category + logger.debug(f"[{self.guild.name}] Created discussion channel") + tasks.append(asyncio.create_task(create_discussion_chan())) - for player in player_role.members: - channel_permissions = { + async def create_player_channel(player: discord.Member, position: int): + perms = { self.guild.default_role: discord.PermissionOverwrite(read_messages = False), player: discord.PermissionOverwrite(read_messages = True), gm_role: discord.PermissionOverwrite(read_messages = True), } - player_channel = await game_category.create_text_channel(player.name, overwrites = channel_permissions) - self.config["player_info"][str(player.id)]["channel"] = player_channel.id - logger.debug(f"[{self.guild.name}] Created player channels") + self.config["player_info"][str(player.id)]["channel"] = (await game_category.create_text_channel(player.name, overwrites = perms, position = position)).id + logger.debug(f"[{self.guild.name}] Created channel for player {player.name}") + for i, player in enumerate(player_role.members): + tasks.append(asyncio.create_task(create_player_channel(player, 4+i))) - self.config["game_started"] = True + await asyncio.wait(tasks) @game_started @save_on_success async def delete(self): category = self.get_game_category() - for channel in category.channels: - await channel.delete() + await asyncio.wait([channel.delete() for channel in category.channels]) await category.delete() self.config.clear() self.config.update(self.new_dict()) @@ -292,10 +306,11 @@ class Game: @save_on_success async def stop_vote(self): logging.debug(f"[{self.guild.name}] Stopping the vote") + tasks = [] passed = self.is_vote_passing() self.config["vote"]["revealed"] = True await self.update_vote_message() - await self.get_votes_channel().send("**The vote has ended**") + tasks.append(asyncio.create_task(self.get_votes_channel().send("**The vote has ended**"))) announcement_content = [ f"{self.get_player_role().mention} the vote has ended!", f"{':green_square:' if passed else ':red_square:'} The vote has **{'' if passed else 'not '}passed**" @@ -304,7 +319,8 @@ class Game: president = self.config["vote"]["president"] chancellor = self.config["vote"]["chancellor"] announcement_content.append(f"Congratulations to president <@{president}> and chancellor <@{chancellor}>!") - await self.get_announcements_channel().send("\n".join(announcement_content), allowed_mentions = discord.AllowedMentions(roles = True)) + tasks.append(asyncio.create_task(self.get_announcements_channel().send("\n".join(announcement_content), allowed_mentions = discord.AllowedMentions(roles = True)))) + await asyncio.wait(tasks) self.config["vote"] = None @game_started @@ -345,7 +361,7 @@ class Game: message_content = [ f"{self.get_player_role().mention} A **{last_enacted.name}** policy {last_enacted.square_emoji()} has been enacted!", f"In total, **{enacted_count[Policy.LIBERAL]} {Policy.LIBERAL.name}** policies and **{enacted_count[Policy.FASCIST]} {Policy.FASCIST.name}** policies have been enacted", - " ".join([Policy.LIBERAL.square_emoji()]*enacted_count[Policy.LIBERAL] + [":black_small_square:"]*(5-enacted_count[Policy.LIBERAL])), + " ".join([Policy.LIBERAL.square_emoji()] * enacted_count[Policy.LIBERAL] + [":black_small_square:"] * (5 - enacted_count[Policy.LIBERAL])), " ".join([Policy.FASCIST.square_emoji()] * enacted_count[Policy.FASCIST] + [":black_small_square:"] * (6 - enacted_count[Policy.FASCIST])), ] await self.get_announcements_channel().send("\n".join(message_content), allowed_mentions = discord.AllowedMentions(roles = True))