Game: using asyncio tasks to run in parallel operation that do not need to be sequential

This commit is contained in:
Elnath 2021-06-12 19:07:26 +02:00
parent 867f7c48eb
commit 15945d839c
1 changed files with 46 additions and 30 deletions

View File

@ -1,9 +1,10 @@
import asyncio
import logging import logging
import random import random
from typing import Dict, Callable, List, Union
from functools import wraps
from collections import defaultdict from collections import defaultdict
from enum import Enum from enum import Enum
from functools import wraps
from typing import Dict, Callable, List, Union
import discord import discord
@ -174,6 +175,8 @@ class Game:
if self.is_started(): if self.is_started():
raise ValueError("Game already started") raise ValueError("Game already started")
logger.info(f"[{self.guild.name}] Starting game") 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["gm_role"] = gm_role.id
self.config["player_role"] = player_role.id self.config["player_role"] = player_role.id
self.config["players"] = [member.id for member in player_role.members] self.config["players"] = [member.id for member in player_role.members]
@ -185,51 +188,62 @@ class Game:
self.config["drawn"] = None self.config["drawn"] = None
self.config["enacted"] = [] self.config["enacted"] = []
permissions = { category_permissions = {
self.guild.default_role: discord.PermissionOverwrite(send_messages = False), self.guild.default_role: discord.PermissionOverwrite(send_messages = False),
gm_role: discord.PermissionOverwrite(send_messages = True), gm_role: discord.PermissionOverwrite(send_messages = True),
player_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 self.config["category"] = game_category.id
logger.debug(f"[{self.guild.name}] Created game category") logger.debug(f"[{self.guild.name}] Created game category")
permissions = { async def create_admin_chan():
perms = {
self.guild.default_role: discord.PermissionOverwrite(read_messages = False), self.guild.default_role: discord.PermissionOverwrite(read_messages = False),
gm_role: discord.PermissionOverwrite(read_messages = True), gm_role: discord.PermissionOverwrite(read_messages = True),
} }
self.config["admin_chan"] = (await game_category.create_text_channel("admin", overwrites = permissions)).id 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") logger.debug(f"[{self.guild.name}] Created admin channel")
tasks.append(asyncio.create_task(create_admin_chan()))
permissions = { async def create_announcements_and_vote_chans():
perms = {
self.guild.default_role: discord.PermissionOverwrite(send_messages = False), self.guild.default_role: discord.PermissionOverwrite(send_messages = False),
gm_role: discord.PermissionOverwrite(send_messages = True), gm_role: discord.PermissionOverwrite(send_messages = True),
} }
self.config["announce_chan"] = (await game_category.create_text_channel("announce", overwrites = permissions)).id channels = await asyncio.gather(
self.config["votes_chan"] = (await game_category.create_text_channel("votes", overwrites = permissions)).id 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") 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 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") logger.debug(f"[{self.guild.name}] Created discussion channel")
tasks.append(asyncio.create_task(create_discussion_chan()))
for player in player_role.members: async def create_player_channel(player: discord.Member, position: int):
channel_permissions = { perms = {
self.guild.default_role: discord.PermissionOverwrite(read_messages = False), self.guild.default_role: discord.PermissionOverwrite(read_messages = False),
player: discord.PermissionOverwrite(read_messages = True), player: discord.PermissionOverwrite(read_messages = True),
gm_role: 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"] = (await game_category.create_text_channel(player.name, overwrites = perms, position = position)).id
self.config["player_info"][str(player.id)]["channel"] = player_channel.id logger.debug(f"[{self.guild.name}] Created channel for player {player.name}")
logger.debug(f"[{self.guild.name}] Created player channels") 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 @game_started
@save_on_success @save_on_success
async def delete(self): async def delete(self):
category = self.get_game_category() category = self.get_game_category()
for channel in category.channels: await asyncio.wait([channel.delete() for channel in category.channels])
await channel.delete()
await category.delete() await category.delete()
self.config.clear() self.config.clear()
self.config.update(self.new_dict()) self.config.update(self.new_dict())
@ -292,10 +306,11 @@ class Game:
@save_on_success @save_on_success
async def stop_vote(self): async def stop_vote(self):
logging.debug(f"[{self.guild.name}] Stopping the vote") logging.debug(f"[{self.guild.name}] Stopping the vote")
tasks = []
passed = self.is_vote_passing() passed = self.is_vote_passing()
self.config["vote"]["revealed"] = True self.config["vote"]["revealed"] = True
await self.update_vote_message() 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 = [ announcement_content = [
f"{self.get_player_role().mention} the vote has ended!", 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**" 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"] president = self.config["vote"]["president"]
chancellor = self.config["vote"]["chancellor"] chancellor = self.config["vote"]["chancellor"]
announcement_content.append(f"Congratulations to president <@{president}> and chancellor <@{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 self.config["vote"] = None
@game_started @game_started
@ -345,7 +361,7 @@ class Game:
message_content = [ message_content = [
f"{self.get_player_role().mention} A **{last_enacted.name}** policy {last_enacted.square_emoji()} has been enacted!", 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", 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])), " ".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)) await self.get_announcements_channel().send("\n".join(message_content), allowed_mentions = discord.AllowedMentions(roles = True))