Priority update for listeners

pull/147/head
bobloy 4 years ago
parent 06af229a62
commit a2eaf55515

@ -9,10 +9,10 @@ import discord
from redbot.core import commands
from redbot.core.bot import Red
from .builder import parse_code
from .player import Player
from .role import Role
from .votegroup import VoteGroup
from werewolf.builder import parse_code
from werewolf.player import Player
from werewolf.role import Role
from werewolf.votegroup import VoteGroup
log = logging.getLogger("red.fox_v3.werewolf.game")
@ -480,7 +480,7 @@ class Game:
async def _notify(self, event, **kwargs):
for i in range(1, 7): # action guide 1-6 (0 is no action)
tasks = []
for event in self.listeners.get(event, []):
for event in self.listeners.get(event, {}).get(i, []):
tasks.append(asyncio.ensure_future(event(**kwargs), loop=self.loop))
await asyncio.gather(*tasks)
@ -912,26 +912,19 @@ class Game:
# Optional dynamic channels/categories
def add_listener(self, func, name=None):
"""The non decorator alternative to :meth:`.listen`.
def add_ww_listener(self, func, priority=0, name=None):
"""Adds a listener from the pool of listeners.
Parameters
-----------
func: :ref:`coroutine <coroutine>`
The function to call.
priority: Optional[:class:`int`]
Priority of the listener. Defaults to 0 (no-action)
name: Optional[:class:`str`]
The name of the event to listen for. Defaults to ``func.__name__``.
Example
--------
.. code-block:: python3
async def on_ready(): pass
async def my_message(message): pass
bot.add_listener(on_ready)
bot.add_listener(my_message, 'on_message')
do_sort: Optional[:class:`bool`]
Whether or not to sort listeners after. Skip sorting during mass appending
"""
name = func.__name__ if name is None else name
@ -940,26 +933,32 @@ class Game:
raise TypeError('Listeners must be coroutines')
if name in self.listeners:
self.listeners[name].append(func)
if priority in self.listeners[name]:
self.listeners[name][priority].append(func)
else:
self.listeners[name][priority] = [func]
else:
self.listeners[name] = [func]
def remove_listener(self, func, name=None):
"""Removes a listener from the pool of listeners.
self.listeners[name] = {priority: [func]}
Parameters
-----------
func
The function that was used as a listener to remove.
name: :class:`str`
The name of the event we want to remove. Defaults to
``func.__name__``.
"""
# self.listeners[name].sort(reverse=True)
name = func.__name__ if name is None else name
if name in self.listeners:
try:
self.listeners[name].remove(func)
except ValueError:
pass
# def remove_wolf_listener(self, func, name=None):
# """Removes a listener from the pool of listeners.
#
# Parameters
# -----------
# func
# The function that was used as a listener to remove.
# name: :class:`str`
# The name of the event we want to remove. Defaults to
# ``func.__name__``.
# """
#
# name = func.__name__ if name is None else name
#
# if name in self.listeners:
# try:
# self.listeners[name].remove(func)
# except ValueError:
# pass

@ -1,7 +1,7 @@
import inspect
def wolflistener(name=None):
def wolflistener(name=None, priority=0):
"""A decorator that marks a function as a listener.
This is the werewolf.Game equivalent of :meth:`.Cog.listener`.
@ -11,6 +11,22 @@ def wolflistener(name=None):
name: :class:`str`
The name of the event being listened to. If not provided, it
defaults to the function's name.
priority: :class:`int`
The priority of the listener.
Priority guide as follows:
_at_night_start
0. No Action
1. Detain actions (Jailer/Kidnapper)
2. Group discussions and choose targets
_at_night_end
0. No Action
1. Self actions (Veteran)
2. Target switching and role blocks (bus driver, witch, escort)
3. Protection / Preempt actions (bodyguard/framer)
4. Non-disruptive actions (seer/silencer)
5. Disruptive actions (Killing)
6. Role altering actions (Cult / Mason / Shifter)
Raises
--------
@ -32,12 +48,12 @@ def wolflistener(name=None):
actual = actual.__func__
if not inspect.iscoroutinefunction(actual):
raise TypeError("Listener function must be a coroutine function.")
actual.__wolf_listener__ = True
actual.__wolf_listener__ = priority
to_assign = name or actual.__name__
try:
actual.__wolf_listener_names__.append(to_assign)
actual.__wolf_listener_names__.append((priority, to_assign))
except AttributeError:
actual.__wolf_listener_names__ = [to_assign]
actual.__wolf_listener_names__ = [(priority, to_assign)]
# we have to return `func` instead of `actual` because
# we need the type to be `staticmethod` for the metaclass
# to pick it up but the metaclass unfurls the function and
@ -51,7 +67,6 @@ class WolfListenerMeta(type):
def __new__(mcs, cls, *args, **kwargs):
name, bases = args
commands = {}
listeners = {}
need_at_msg = "Listeners must start with at_ (in method {0.__name__}.{1})"
@ -76,10 +91,10 @@ class WolfListenerMeta(type):
listeners_as_list = []
for listener in listeners.values():
for listener_name in listener.__wolf_listener_names__:
for priority, listener_name in listener.__wolf_listener_names__:
# I use __name__ instead of just storing the value so I can inject
# the self attribute when the time comes to add them to the bot
listeners_as_list.append((listener_name, listener.__name__))
listeners_as_list.append((priority, listener_name, listener.__name__))
new_cls.__wolf_listeners__ = listeners_as_list
return new_cls
@ -87,5 +102,5 @@ class WolfListenerMeta(type):
class WolfListener(metaclass=WolfListenerMeta):
def __init__(self, game):
for name, method_name in self.__wolf_listeners__:
game.add_listener(getattr(self, method_name), name)
for priority, name, method_name in self.__wolf_listeners__:
game.add_ww_listener(getattr(self, method_name), priority, name)

@ -1,6 +1,6 @@
import logging
from .role import Role
from werewolf.role import Role
log = logging.getLogger("red.fox_v3.werewolf.night_powers")

@ -1,6 +1,6 @@
from ..listener import wolflistener
from ..night_powers import pick_target
from ..role import Role
from werewolf.listener import wolflistener
from werewolf.night_powers import pick_target
from werewolf.role import Role
class Seer(Role):
@ -27,17 +27,17 @@ class Seer(Role):
# self.blocked = False
# self.properties = {} # Extra data for other roles (i.e. arsonist)
self.see_target = None
self.action_list = [
(self._at_game_start, 1), # (Action, Priority)
(self._at_day_start, 0),
(self._at_voted, 0),
(self._at_kill, 0),
(self._at_hang, 0),
(self._at_day_end, 0),
(self._at_night_start, 2),
(self._at_night_end, 4),
(self._at_visit, 0),
]
# self.action_list = [
# (self._at_game_start, 1), # (Action, Priority)
# (self._at_day_start, 0),
# (self._at_voted, 0),
# (self._at_kill, 0),
# (self._at_hang, 0),
# (self._at_day_end, 0),
# (self._at_night_start, 2),
# (self._at_night_end, 4),
# (self._at_visit, 0),
# ]
async def see_alignment(self, source=None):
"""
@ -60,7 +60,7 @@ class Seer(Role):
"""
return "Villager"
@wolflistener("at_night_start")
@wolflistener("at_night_start", priority=2)
async def _at_night_start(self, data=None):
if not self.player.alive:
return
@ -68,7 +68,7 @@ class Seer(Role):
await self.game.generate_targets(self.player.member)
await self.player.send_dm("**Pick a target to see tonight**")
@wolflistener("at_night_end")
@wolflistener("at_night_end", priority=4)
async def _at_night_end(self, data=None):
if self.see_target is None:
if self.player.alive:

@ -1,7 +1,6 @@
from ..listener import wolflistener
from ..role import Role
from ..votegroups.wolfvote import WolfVote
from werewolf.listener import wolflistener
from werewolf.role import Role
from werewolf.votegroups.wolfvote import WolfVote
class VanillaWerewolf(Role):

@ -1,4 +1,4 @@
from ..role import Role
from werewolf.role import Role
class Villager(Role):

@ -0,0 +1 @@
from .wolfvote import WolfVote

@ -1,6 +1,6 @@
import random
from ..votegroup import VoteGroup
from werewolf.votegroup import VoteGroup
class WolfVote(VoteGroup):

@ -6,14 +6,14 @@ from redbot.core.bot import Red
from redbot.core.commands import Cog
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu
from .builder import (
from werewolf.builder import (
GameBuilder,
role_from_alignment,
role_from_category,
role_from_id,
role_from_name,
)
from .game import Game
from werewolf.game import Game
log = logging.getLogger("red.fox_v3.werewolf")
@ -81,8 +81,8 @@ class Werewolf(Cog):
"""
Lists current guild settings
"""
success, role, category, channel, log_channel = await self._get_settings(ctx)
if not success:
valid, role, category, channel, log_channel = await self._get_settings(ctx)
if not valid:
await ctx.send("Failed to get settings")
return None
@ -362,13 +362,15 @@ class Werewolf(Cog):
return None
if guild.id not in self.games or self.games[guild.id].game_over:
await ctx.send("Starting a new game...")
success, role, category, channel, log_channel = await self._get_settings(ctx)
valid, role, category, channel, log_channel = await self._get_settings(ctx)
if not success:
if not valid:
await ctx.send("Cannot start a new game")
return None
self.games[guild.id] = Game(self.bot, guild, role, category, channel, log_channel, game_code)
self.games[guild.id] = Game(
self.bot, guild, role, category, channel, log_channel, game_code
)
return self.games[guild.id]

Loading…
Cancel
Save