Priority update for listeners
This commit is contained in:
parent
06af229a62
commit
a2eaf55515
@ -9,10 +9,10 @@ import discord
|
|||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
|
|
||||||
from .builder import parse_code
|
from werewolf.builder import parse_code
|
||||||
from .player import Player
|
from werewolf.player import Player
|
||||||
from .role import Role
|
from werewolf.role import Role
|
||||||
from .votegroup import VoteGroup
|
from werewolf.votegroup import VoteGroup
|
||||||
|
|
||||||
log = logging.getLogger("red.fox_v3.werewolf.game")
|
log = logging.getLogger("red.fox_v3.werewolf.game")
|
||||||
|
|
||||||
@ -480,7 +480,7 @@ class Game:
|
|||||||
async def _notify(self, event, **kwargs):
|
async def _notify(self, event, **kwargs):
|
||||||
for i in range(1, 7): # action guide 1-6 (0 is no action)
|
for i in range(1, 7): # action guide 1-6 (0 is no action)
|
||||||
tasks = []
|
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))
|
tasks.append(asyncio.ensure_future(event(**kwargs), loop=self.loop))
|
||||||
await asyncio.gather(*tasks)
|
await asyncio.gather(*tasks)
|
||||||
|
|
||||||
@ -912,26 +912,19 @@ class Game:
|
|||||||
|
|
||||||
# Optional dynamic channels/categories
|
# Optional dynamic channels/categories
|
||||||
|
|
||||||
def add_listener(self, func, name=None):
|
def add_ww_listener(self, func, priority=0, name=None):
|
||||||
"""The non decorator alternative to :meth:`.listen`.
|
"""Adds a listener from the pool of listeners.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
-----------
|
-----------
|
||||||
func: :ref:`coroutine <coroutine>`
|
func: :ref:`coroutine <coroutine>`
|
||||||
The function to call.
|
The function to call.
|
||||||
|
priority: Optional[:class:`int`]
|
||||||
|
Priority of the listener. Defaults to 0 (no-action)
|
||||||
name: Optional[:class:`str`]
|
name: Optional[:class:`str`]
|
||||||
The name of the event to listen for. Defaults to ``func.__name__``.
|
The name of the event to listen for. Defaults to ``func.__name__``.
|
||||||
|
do_sort: Optional[:class:`bool`]
|
||||||
Example
|
Whether or not to sort listeners after. Skip sorting during mass appending
|
||||||
--------
|
|
||||||
|
|
||||||
.. 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')
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
name = func.__name__ if name is None else name
|
name = func.__name__ if name is None else name
|
||||||
@ -940,26 +933,32 @@ class Game:
|
|||||||
raise TypeError('Listeners must be coroutines')
|
raise TypeError('Listeners must be coroutines')
|
||||||
|
|
||||||
if name in self.listeners:
|
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:
|
else:
|
||||||
self.listeners[name] = [func]
|
self.listeners[name] = {priority: [func]}
|
||||||
|
|
||||||
def remove_listener(self, func, name=None):
|
# self.listeners[name].sort(reverse=True)
|
||||||
"""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
|
# def remove_wolf_listener(self, func, name=None):
|
||||||
|
# """Removes a listener from the pool of listeners.
|
||||||
if name in self.listeners:
|
#
|
||||||
try:
|
# Parameters
|
||||||
self.listeners[name].remove(func)
|
# -----------
|
||||||
except ValueError:
|
# func
|
||||||
pass
|
# 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
|
import inspect
|
||||||
|
|
||||||
|
|
||||||
def wolflistener(name=None):
|
def wolflistener(name=None, priority=0):
|
||||||
"""A decorator that marks a function as a listener.
|
"""A decorator that marks a function as a listener.
|
||||||
|
|
||||||
This is the werewolf.Game equivalent of :meth:`.Cog.listener`.
|
This is the werewolf.Game equivalent of :meth:`.Cog.listener`.
|
||||||
@ -11,6 +11,22 @@ def wolflistener(name=None):
|
|||||||
name: :class:`str`
|
name: :class:`str`
|
||||||
The name of the event being listened to. If not provided, it
|
The name of the event being listened to. If not provided, it
|
||||||
defaults to the function's name.
|
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
|
Raises
|
||||||
--------
|
--------
|
||||||
@ -32,12 +48,12 @@ def wolflistener(name=None):
|
|||||||
actual = actual.__func__
|
actual = actual.__func__
|
||||||
if not inspect.iscoroutinefunction(actual):
|
if not inspect.iscoroutinefunction(actual):
|
||||||
raise TypeError("Listener function must be a coroutine function.")
|
raise TypeError("Listener function must be a coroutine function.")
|
||||||
actual.__wolf_listener__ = True
|
actual.__wolf_listener__ = priority
|
||||||
to_assign = name or actual.__name__
|
to_assign = name or actual.__name__
|
||||||
try:
|
try:
|
||||||
actual.__wolf_listener_names__.append(to_assign)
|
actual.__wolf_listener_names__.append((priority, to_assign))
|
||||||
except AttributeError:
|
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 have to return `func` instead of `actual` because
|
||||||
# we need the type to be `staticmethod` for the metaclass
|
# we need the type to be `staticmethod` for the metaclass
|
||||||
# to pick it up but the metaclass unfurls the function and
|
# to pick it up but the metaclass unfurls the function and
|
||||||
@ -51,7 +67,6 @@ class WolfListenerMeta(type):
|
|||||||
def __new__(mcs, cls, *args, **kwargs):
|
def __new__(mcs, cls, *args, **kwargs):
|
||||||
name, bases = args
|
name, bases = args
|
||||||
|
|
||||||
commands = {}
|
|
||||||
listeners = {}
|
listeners = {}
|
||||||
need_at_msg = "Listeners must start with at_ (in method {0.__name__}.{1})"
|
need_at_msg = "Listeners must start with at_ (in method {0.__name__}.{1})"
|
||||||
|
|
||||||
@ -76,10 +91,10 @@ class WolfListenerMeta(type):
|
|||||||
|
|
||||||
listeners_as_list = []
|
listeners_as_list = []
|
||||||
for listener in listeners.values():
|
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
|
# 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
|
# 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
|
new_cls.__wolf_listeners__ = listeners_as_list
|
||||||
return new_cls
|
return new_cls
|
||||||
@ -87,5 +102,5 @@ class WolfListenerMeta(type):
|
|||||||
|
|
||||||
class WolfListener(metaclass=WolfListenerMeta):
|
class WolfListener(metaclass=WolfListenerMeta):
|
||||||
def __init__(self, game):
|
def __init__(self, game):
|
||||||
for name, method_name in self.__wolf_listeners__:
|
for priority, name, method_name in self.__wolf_listeners__:
|
||||||
game.add_listener(getattr(self, method_name), name)
|
game.add_ww_listener(getattr(self, method_name), priority, name)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from .role import Role
|
from werewolf.role import Role
|
||||||
|
|
||||||
log = logging.getLogger("red.fox_v3.werewolf.night_powers")
|
log = logging.getLogger("red.fox_v3.werewolf.night_powers")
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from ..listener import wolflistener
|
from werewolf.listener import wolflistener
|
||||||
from ..night_powers import pick_target
|
from werewolf.night_powers import pick_target
|
||||||
from ..role import Role
|
from werewolf.role import Role
|
||||||
|
|
||||||
|
|
||||||
class Seer(Role):
|
class Seer(Role):
|
||||||
@ -27,17 +27,17 @@ class Seer(Role):
|
|||||||
# self.blocked = False
|
# self.blocked = False
|
||||||
# self.properties = {} # Extra data for other roles (i.e. arsonist)
|
# self.properties = {} # Extra data for other roles (i.e. arsonist)
|
||||||
self.see_target = None
|
self.see_target = None
|
||||||
self.action_list = [
|
# self.action_list = [
|
||||||
(self._at_game_start, 1), # (Action, Priority)
|
# (self._at_game_start, 1), # (Action, Priority)
|
||||||
(self._at_day_start, 0),
|
# (self._at_day_start, 0),
|
||||||
(self._at_voted, 0),
|
# (self._at_voted, 0),
|
||||||
(self._at_kill, 0),
|
# (self._at_kill, 0),
|
||||||
(self._at_hang, 0),
|
# (self._at_hang, 0),
|
||||||
(self._at_day_end, 0),
|
# (self._at_day_end, 0),
|
||||||
(self._at_night_start, 2),
|
# (self._at_night_start, 2),
|
||||||
(self._at_night_end, 4),
|
# (self._at_night_end, 4),
|
||||||
(self._at_visit, 0),
|
# (self._at_visit, 0),
|
||||||
]
|
# ]
|
||||||
|
|
||||||
async def see_alignment(self, source=None):
|
async def see_alignment(self, source=None):
|
||||||
"""
|
"""
|
||||||
@ -60,7 +60,7 @@ class Seer(Role):
|
|||||||
"""
|
"""
|
||||||
return "Villager"
|
return "Villager"
|
||||||
|
|
||||||
@wolflistener("at_night_start")
|
@wolflistener("at_night_start", priority=2)
|
||||||
async def _at_night_start(self, data=None):
|
async def _at_night_start(self, data=None):
|
||||||
if not self.player.alive:
|
if not self.player.alive:
|
||||||
return
|
return
|
||||||
@ -68,7 +68,7 @@ class Seer(Role):
|
|||||||
await self.game.generate_targets(self.player.member)
|
await self.game.generate_targets(self.player.member)
|
||||||
await self.player.send_dm("**Pick a target to see tonight**")
|
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):
|
async def _at_night_end(self, data=None):
|
||||||
if self.see_target is None:
|
if self.see_target is None:
|
||||||
if self.player.alive:
|
if self.player.alive:
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
from ..listener import wolflistener
|
from werewolf.listener import wolflistener
|
||||||
from ..role import Role
|
from werewolf.role import Role
|
||||||
|
from werewolf.votegroups.wolfvote import WolfVote
|
||||||
from ..votegroups.wolfvote import WolfVote
|
|
||||||
|
|
||||||
|
|
||||||
class VanillaWerewolf(Role):
|
class VanillaWerewolf(Role):
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from ..role import Role
|
from werewolf.role import Role
|
||||||
|
|
||||||
|
|
||||||
class Villager(Role):
|
class Villager(Role):
|
||||||
|
1
werewolf/votegroups/__init__.py
Normal file
1
werewolf/votegroups/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .wolfvote import WolfVote
|
@ -1,6 +1,6 @@
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from ..votegroup import VoteGroup
|
from werewolf.votegroup import VoteGroup
|
||||||
|
|
||||||
|
|
||||||
class WolfVote(VoteGroup):
|
class WolfVote(VoteGroup):
|
||||||
|
@ -6,14 +6,14 @@ from redbot.core.bot import Red
|
|||||||
from redbot.core.commands import Cog
|
from redbot.core.commands import Cog
|
||||||
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu
|
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu
|
||||||
|
|
||||||
from .builder import (
|
from werewolf.builder import (
|
||||||
GameBuilder,
|
GameBuilder,
|
||||||
role_from_alignment,
|
role_from_alignment,
|
||||||
role_from_category,
|
role_from_category,
|
||||||
role_from_id,
|
role_from_id,
|
||||||
role_from_name,
|
role_from_name,
|
||||||
)
|
)
|
||||||
from .game import Game
|
from werewolf.game import Game
|
||||||
|
|
||||||
log = logging.getLogger("red.fox_v3.werewolf")
|
log = logging.getLogger("red.fox_v3.werewolf")
|
||||||
|
|
||||||
@ -81,8 +81,8 @@ class Werewolf(Cog):
|
|||||||
"""
|
"""
|
||||||
Lists current guild settings
|
Lists current guild settings
|
||||||
"""
|
"""
|
||||||
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("Failed to get settings")
|
await ctx.send("Failed to get settings")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -362,13 +362,15 @@ class Werewolf(Cog):
|
|||||||
return None
|
return None
|
||||||
if guild.id not in self.games or self.games[guild.id].game_over:
|
if guild.id not in self.games or self.games[guild.id].game_over:
|
||||||
await ctx.send("Starting a new game...")
|
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")
|
await ctx.send("Cannot start a new game")
|
||||||
return None
|
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]
|
return self.games[guild.id]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user