nonebot-plugin-werewolf 1.1.1__py3-none-any.whl → 1.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@ require("nonebot_plugin_waiter")
8
8
  from . import matchers as matchers
9
9
  from .config import Config
10
10
 
11
- __version__ = "1.1.1"
11
+ __version__ = "1.1.2"
12
12
  __plugin_meta__ = PluginMetadata(
13
13
  name="狼人杀",
14
14
  description="适用于 Nonebot2 的狼人杀插件",
@@ -0,0 +1,110 @@
1
+ import asyncio
2
+ import enum
3
+ import sys
4
+ from types import TracebackType
5
+ from typing import final
6
+
7
+ if sys.version_info >= (3, 11):
8
+ from asyncio.timeouts import timeout as timeout
9
+
10
+ else:
11
+ # ruff: noqa: S101
12
+
13
+ class _State(enum.Enum):
14
+ CREATED = "created"
15
+ ENTERED = "active"
16
+ EXPIRING = "expiring"
17
+ EXPIRED = "expired"
18
+ EXITED = "finished"
19
+
20
+ @final
21
+ class Timeout:
22
+ def __init__(self, when: float | None) -> None:
23
+ self._state = _State.CREATED
24
+ self._timeout_handler: asyncio.Handle | None = None
25
+ self._task: asyncio.Task | None = None
26
+ if when is not None:
27
+ when = asyncio.get_running_loop().time() + when
28
+ self._when = when
29
+
30
+ def when(self) -> float | None:
31
+ return self._when
32
+
33
+ def reschedule(self, when: float | None) -> None:
34
+ if self._state is not _State.ENTERED:
35
+ if self._state is _State.CREATED:
36
+ raise RuntimeError("Timeout has not been entered")
37
+ raise RuntimeError(
38
+ f"Cannot change state of {self._state.value} Timeout",
39
+ )
40
+
41
+ self._when = when
42
+
43
+ if self._timeout_handler is not None:
44
+ self._timeout_handler.cancel()
45
+
46
+ if when is None:
47
+ self._timeout_handler = None
48
+ else:
49
+ loop = asyncio.get_running_loop()
50
+ if when <= loop.time():
51
+ self._timeout_handler = loop.call_soon(self._on_timeout)
52
+ else:
53
+ self._timeout_handler = loop.call_at(when, self._on_timeout)
54
+
55
+ def expired(self) -> bool:
56
+ return self._state in (_State.EXPIRING, _State.EXPIRED)
57
+
58
+ def __repr__(self) -> str:
59
+ info = [""]
60
+ if self._state is _State.ENTERED:
61
+ when = round(self._when, 3) if self._when is not None else None
62
+ info.append(f"when={when}")
63
+ info_str = " ".join(info)
64
+ return f"<Timeout [{self._state.value}]{info_str}>"
65
+
66
+ async def __aenter__(self) -> "Timeout":
67
+ if self._state is not _State.CREATED:
68
+ raise RuntimeError("Timeout has already been entered")
69
+ task = asyncio.current_task()
70
+ if task is None:
71
+ raise RuntimeError("Timeout should be used inside a task")
72
+ self._state = _State.ENTERED
73
+ self._task = task
74
+ self.reschedule(self._when)
75
+ return self
76
+
77
+ async def __aexit__(
78
+ self,
79
+ exc_type: type[BaseException] | None,
80
+ exc_val: BaseException | None,
81
+ exc_tb: TracebackType | None,
82
+ ) -> bool | None:
83
+ assert self._state in (_State.ENTERED, _State.EXPIRING)
84
+
85
+ if self._timeout_handler is not None:
86
+ self._timeout_handler.cancel()
87
+ self._timeout_handler = None
88
+
89
+ if self._state is _State.EXPIRING:
90
+ self._state = _State.EXPIRED
91
+
92
+ if exc_type is asyncio.CancelledError:
93
+ raise TimeoutError from exc_val
94
+ elif self._state is _State.ENTERED:
95
+ self._state = _State.EXITED
96
+
97
+ return None
98
+
99
+ def _on_timeout(self) -> None:
100
+ assert self._state is _State.ENTERED
101
+ assert self._task is not None
102
+ self._task.cancel()
103
+ self._state = _State.EXPIRING
104
+ self._timeout_handler = None
105
+
106
+ def timeout(delay: float | None) -> Timeout:
107
+ return Timeout(delay)
108
+
109
+
110
+ __all__ = ["timeout"]
@@ -1,8 +1,9 @@
1
- from typing import Literal, Self, overload
1
+ from typing import Literal, overload
2
2
 
3
3
  from nonebot import get_plugin_config, logger
4
4
  from nonebot.compat import PYDANTIC_V2
5
5
  from pydantic import BaseModel, Field
6
+ from typing_extensions import Self
6
7
 
7
8
  from .constant import (
8
9
  Role,
@@ -47,7 +48,7 @@ class PluginConfig(BaseModel):
47
48
  if isinstance(self.role_preset, list):
48
49
  for preset in self.role_preset:
49
50
  if preset[0] != sum(preset[1:]):
50
- raise RuntimeError(
51
+ raise ValueError(
51
52
  "配置项 `role_preset` 错误: "
52
53
  f"预设总人数为 {preset[0]}, 实际总人数为 {sum(preset[1:])} "
53
54
  f"({', '.join(map(str, preset[1:]))})"
@@ -59,13 +60,13 @@ class PluginConfig(BaseModel):
59
60
 
60
61
  min_length = max(i[0] for i in self.role_preset.values())
61
62
  if len(self.werewolf_priority) < min_length:
62
- raise RuntimeError(
63
+ raise ValueError(
63
64
  f"配置项 `werewolf_priority` 错误: 应至少为 {min_length} 项"
64
65
  )
65
66
 
66
67
  min_length = max(i[1] for i in self.role_preset.values())
67
68
  if len(self.priesthood_proirity) < min_length:
68
- raise RuntimeError(
69
+ raise ValueError(
69
70
  f"配置项 `priesthood_proirity` 错误: 应至少为 {min_length} 项"
70
71
  )
71
72
 
@@ -52,7 +52,7 @@ class GameState:
52
52
  killed: Player | None = None
53
53
  shoot: tuple[Player, Player] | tuple[None, None] = (None, None)
54
54
  antidote: set[Player] = dataclasses.field(default_factory=set)
55
- poison: set[tuple[Player, Player]] = dataclasses.field(default_factory=set)
55
+ poison: set[Player] = dataclasses.field(default_factory=set)
56
56
  protected: set[Player] = dataclasses.field(default_factory=set)
57
57
 
58
58
 
@@ -10,7 +10,7 @@ class Error(Exception):
10
10
  """插件错误类型基类"""
11
11
 
12
12
 
13
- class GameFinishedError(Error):
13
+ class GameFinished(Error): # noqa: N818
14
14
  """游戏结束时抛出,无视游戏进程进入结算"""
15
15
 
16
16
  status: GameStatus
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- import asyncio.timeouts
5
4
  import contextlib
6
5
  import secrets
7
6
  from typing import TYPE_CHECKING, NoReturn
@@ -9,9 +8,10 @@ from typing import TYPE_CHECKING, NoReturn
9
8
  from nonebot.log import logger
10
9
  from nonebot_plugin_alconna import At, Target, UniMessage
11
10
 
11
+ from ._timeout import timeout
12
12
  from .config import config
13
13
  from .constant import GameState, GameStatus, KillReason, Role, RoleGroup, role_name_conv
14
- from .exception import GameFinishedError
14
+ from .exception import GameFinished
15
15
  from .player import Player
16
16
  from .player_set import PlayerSet
17
17
  from .utils import InputStore
@@ -112,16 +112,16 @@ class Game:
112
112
 
113
113
  # 狼人数量大于其他职业数量
114
114
  if w.size >= p.size:
115
- raise GameFinishedError(GameStatus.Werewolf)
115
+ raise GameFinished(GameStatus.Werewolf)
116
116
  # 屠边-村民/中立全灭
117
117
  if not p.select(Role.Civilian, RoleGroup.Others).size:
118
- raise GameFinishedError(GameStatus.Werewolf)
118
+ raise GameFinished(GameStatus.Werewolf)
119
119
  # 屠边-神职全灭
120
120
  if not p.exclude(Role.Civilian).size:
121
- raise GameFinishedError(GameStatus.Werewolf)
121
+ raise GameFinished(GameStatus.Werewolf)
122
122
  # 狼人全灭
123
123
  if not w.size:
124
- raise GameFinishedError(GameStatus.GoodGuy)
124
+ raise GameFinished(GameStatus.GoodGuy)
125
125
 
126
126
  def show_killed_players(self) -> str:
127
127
  msg = ""
@@ -173,7 +173,7 @@ class Game:
173
173
  break
174
174
 
175
175
  with contextlib.suppress(TimeoutError):
176
- async with asyncio.timeouts.timeout(timeout_secs):
176
+ async with timeout(timeout_secs):
177
177
  await asyncio.gather(*[wait(p) for p in players])
178
178
 
179
179
  async def interact(
@@ -372,7 +372,7 @@ class Game:
372
372
 
373
373
  # 狼人击杀目标
374
374
  if (
375
- (killed := self.state.killed) # 狼人未空刀
375
+ (killed := self.state.killed) is not None # 狼人未空刀
376
376
  and killed not in self.state.protected # 守卫保护
377
377
  and killed not in self.state.antidote # 女巫使用解药
378
378
  ):
@@ -383,10 +383,12 @@ class Game:
383
383
  )
384
384
 
385
385
  # 女巫操作目标
386
- for witch, potioned in self.state.poison:
387
- if potioned not in self.state.protected: # 守卫未保护
386
+ for witch in self.state.poison:
387
+ if witch.selected is None:
388
+ continue
389
+ if witch.selected not in self.state.protected: # 守卫未保护
388
390
  # 女巫毒杀玩家
389
- await potioned.kill(KillReason.Poison, witch)
391
+ await witch.selected.kill(KillReason.Poison, witch)
390
392
 
391
393
  day_count += 1
392
394
  msg = UniMessage.text(f"『第{day_count}天』天亮了...\n")
@@ -456,7 +458,7 @@ class Game:
456
458
  game_task.result()
457
459
  except asyncio.CancelledError:
458
460
  logger.warning(f"{self.group.id} 的狼人杀游戏进程被取消")
459
- except GameFinishedError as result:
461
+ except GameFinished as result:
460
462
  await self.handle_game_finish(result.status)
461
463
  logger.info(f"{self.group.id} 的狼人杀游戏进程正常退出")
462
464
  except Exception as err:
@@ -1,5 +1,3 @@
1
- import asyncio
2
- import asyncio.timeouts
3
1
  from typing import Annotated
4
2
 
5
3
  from nonebot import on_command, on_message
@@ -9,6 +7,7 @@ from nonebot.rule import to_me
9
7
  from nonebot_plugin_alconna import MsgTarget, UniMessage, UniMsg
10
8
  from nonebot_plugin_userinfo import EventUserInfo, UserInfo
11
9
 
10
+ from ._timeout import timeout
12
11
  from .game import Game
13
12
  from .ob11_ext import ob11_ext_enabled
14
13
  from .utils import InputStore, is_group, prepare_game, rule_in_game, rule_not_in_game
@@ -52,7 +51,7 @@ async def handle_start(
52
51
  players = {admin_id: admin_info.user_name}
53
52
 
54
53
  try:
55
- async with asyncio.timeouts.timeout(5 * 60):
54
+ async with timeout(5 * 60):
56
55
  await prepare_game(event, players)
57
56
  except FinishedException:
58
57
  raise
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- import asyncio.timeouts
4
+ import weakref
5
5
  from dataclasses import dataclass
6
6
  from typing import TYPE_CHECKING, ClassVar, TypeVar, final
7
7
 
@@ -10,7 +10,7 @@ from nonebot_plugin_alconna.uniseg import Receipt, Target, UniMessage
10
10
  from typing_extensions import override
11
11
 
12
12
  from .constant import GameStatus, KillReason, Role, RoleGroup, role_name_conv
13
- from .exception import GameFinishedError
13
+ from .exception import GameFinished
14
14
  from .utils import InputStore, check_index
15
15
 
16
16
  if TYPE_CHECKING:
@@ -47,7 +47,7 @@ class Player:
47
47
  role_group: ClassVar[RoleGroup]
48
48
 
49
49
  bot: Bot
50
- game: Game
50
+ _game_ref: weakref.ReferenceType[Game]
51
51
  user: Target
52
52
  name: str
53
53
  alive: bool = True
@@ -58,7 +58,7 @@ class Player:
58
58
  @final
59
59
  def __init__(self, bot: Bot, game: Game, user: Target, name: str) -> None:
60
60
  self.bot = bot
61
- self.game = game
61
+ self._game_ref = weakref.ref(game)
62
62
  self.user = user
63
63
  self.name = name
64
64
  self.killed = asyncio.Event()
@@ -81,6 +81,12 @@ class Player:
81
81
  def __repr__(self) -> str:
82
82
  return f"<{self.role_name}: user={self.name!r} alive={self.alive}>"
83
83
 
84
+ @property
85
+ def game(self) -> Game:
86
+ if game := self._game_ref():
87
+ return game
88
+ raise ValueError("Game not exist")
89
+
84
90
  @property
85
91
  def user_id(self) -> str:
86
92
  return self.user.id
@@ -95,7 +101,7 @@ class Player:
95
101
  logger.opt(colors=True).info(
96
102
  f"<b><e>{self.game.group.id}</e></b> | "
97
103
  f"[<b><m>{self.role_name}</m></b>] "
98
- f"<y>{self.name}</y>(<e>{self.user_id}</e>) | "
104
+ f"<y>{self.name}</y>(<b><e>{self.user_id}</e></b>) | "
99
105
  f"{text}",
100
106
  )
101
107
 
@@ -325,6 +331,7 @@ class Witch(Player):
325
331
  text = await self.receive_text()
326
332
  if text == "1":
327
333
  self.antidote = 0
334
+ self.selected = killed
328
335
  self.game.state.antidote.add(killed)
329
336
  await self.send(f"你对 {killed.name} 使用了解药,回合结束")
330
337
  return True
@@ -362,9 +369,9 @@ class Witch(Player):
362
369
  await self.send("输入错误: 请发送玩家编号或 “/stop”")
363
370
 
364
371
  self.poison = 0
365
- player = players[selected]
366
- self.game.state.poison.add((self, player))
367
- await self.send(f"当前回合选择对玩家 {player.name} 使用毒药\n回合结束")
372
+ self.selected = players[selected]
373
+ self.game.state.poison.add(self)
374
+ await self.send(f"当前回合选择对玩家 {self.selected.name} 使用毒药\n回合结束")
368
375
 
369
376
 
370
377
  @register_role(Role.Hunter, RoleGroup.GoodGuy)
@@ -446,7 +453,7 @@ class Joker(Player):
446
453
  await super().kill(reason, *killers)
447
454
  if reason == KillReason.Vote:
448
455
  self.game.killed_players.append(self)
449
- raise GameFinishedError(GameStatus.Joker)
456
+ raise GameFinished(GameStatus.Joker)
450
457
  return True
451
458
 
452
459
 
@@ -1,9 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- import asyncio.timeouts
5
4
  from typing import TYPE_CHECKING
6
5
 
6
+ from ._timeout import timeout
7
7
  from .player import Player
8
8
 
9
9
  if TYPE_CHECKING:
@@ -54,13 +54,13 @@ class PlayerSet(set[Player]):
54
54
  return sorted(self, key=lambda p: p.user_id)
55
55
 
56
56
  async def interact(self, timeout_secs: float = 60) -> None:
57
- async with asyncio.timeouts.timeout(timeout_secs):
57
+ async with timeout(timeout_secs):
58
58
  await asyncio.gather(*[p.interact() for p in self.alive()])
59
59
 
60
60
  async def vote(self, timeout_secs: float = 60) -> dict[Player, list[Player]]:
61
61
  async def vote(player: Player) -> tuple[Player, Player] | None:
62
62
  try:
63
- async with asyncio.timeouts.timeout(timeout_secs):
63
+ async with timeout(timeout_secs):
64
64
  return await player.vote(self)
65
65
  except TimeoutError:
66
66
  await player.send("投票超时,将视为弃票")
@@ -1,5 +1,4 @@
1
1
  import asyncio
2
- import asyncio.timeouts
3
2
  import re
4
3
  from collections import defaultdict
5
4
  from typing import Annotated, Any, ClassVar
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nonebot-plugin-werewolf
3
- Version: 1.1.1
3
+ Version: 1.1.2
4
4
  Summary: 适用于 Nonebot2 的狼人杀插件
5
5
  Author-email: wyf7685 <wyf7685@163.com>
6
6
  License: MIT
7
- Requires-Python: >=3.11
7
+ Requires-Python: >=3.10
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
10
  Requires-Dist: nonebot2 >=2.3.3
@@ -14,7 +14,7 @@ Requires-Dist: nonebot-plugin-waiter >=0.7.1
14
14
 
15
15
  <div align="center">
16
16
  <a href="https://v2.nonebot.dev/store">
17
- <img src="https://github.com/wyf7685/wyf7685/blob/main/assets/NoneBotPlugin.svg" width="300" alt="logo">
17
+ <img src="https://raw.githubusercontent.com/wyf7685/wyf7685/main/assets/NoneBotPlugin.svg" width="300" alt="logo">
18
18
  </a>
19
19
  </div>
20
20
 
@@ -26,14 +26,14 @@ _✨ 简单的狼人杀插件 ✨_
26
26
 
27
27
  [![license](https://img.shields.io/github/license/wyf7685/nonebot-plugin-werewolf.svg)](./LICENSE)
28
28
  [![pypi](https://img.shields.io/pypi/v/nonebot-plugin-werewolf?logo=python&logoColor=edb641)](https://pypi.python.org/pypi/nonebot-plugin-werewolf)
29
- [![python](https://img.shields.io/badge/python-3.11+-blue?logo=python&logoColor=edb641)](https://www.python.org/)
29
+ [![python](https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=edb641)](https://www.python.org/)
30
+
30
31
  [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
31
32
  [![ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
32
33
  [![isort](https://img.shields.io/badge/%20imports-isort-%231674b1)](https://pycqa.github.io/isort/)
33
34
  [![black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
34
35
  [![pyright](https://img.shields.io/badge/types-pyright-797952.svg?logo=python&logoColor=edb641)](https://github.com/Microsoft/pyright)
35
36
 
36
- [![commits](https://img.shields.io/github/commit-activity/w/wyf7685/nonebot-plugin-werewolf)](https://github.com/wyf7685/nonebot-plugin-werewolf/commits)
37
37
  [![wakatime](https://wakatime.com/badge/user/b097681b-c224-44ec-8e04-e1cf71744655/project/70a7f68d-5625-4989-9476-be6877408332.svg)](https://wakatime.com/badge/user/b097681b-c224-44ec-8e04-e1cf71744655/project/70a7f68d-5625-4989-9476-be6877408332)
38
38
  [![pre-commit](https://results.pre-commit.ci/badge/github/wyf7685/nonebot-plugin-werewolf/master.svg)](https://results.pre-commit.ci/latest/github/wyf7685/nonebot-plugin-werewolf/master)
39
39
  [![pyright](https://github.com/wyf7685/nonebot-plugin-werewolf/actions/workflows/pyright.yml/badge.svg?branch=master&event=push)](https://github.com/wyf7685/nonebot-plugin-werewolf/actions/workflows/pyright.yml)
@@ -52,7 +52,7 @@ _✨ 简单的狼人杀插件 ✨_
52
52
 
53
53
  > [!note]
54
54
  >
55
- > 请确保 NoneBot2 使用的 Python 解释器版本 >=3.11
55
+ > 请确保 NoneBot2 使用的 Python 解释器版本 >=3.10
56
56
 
57
57
  <details open>
58
58
  <summary>使用 nb-cli 安装</summary>
@@ -240,6 +240,10 @@ werewolf__priesthood_proirity=[11, 12, 13, 14, 15]
240
240
 
241
241
  <!-- CHANGELOG -->
242
242
 
243
+ - 2024.09.18 v1.1.2
244
+
245
+ - 修改 Python 需求为 `>=3.10`
246
+
243
247
  - 2024.09.11 v1.1.1
244
248
 
245
249
  - 修改 Python 需求为 `>=3.11`
@@ -0,0 +1,16 @@
1
+ nonebot_plugin_werewolf/__init__.py,sha256=qCS-gVMiMZcF9yT3SIMe8np-wmKX2vGT5DxYJ2jRxgY,734
2
+ nonebot_plugin_werewolf/_timeout.py,sha256=MVkA5oMoxOTV8Luc0BH2QPP8wwz4Tr9CJjeYgiPu_O4,3649
3
+ nonebot_plugin_werewolf/config.py,sha256=a5dyF21_3T1o6AFrK6onIiwXUNyEwj5Yg-c7V9qoueI,2923
4
+ nonebot_plugin_werewolf/constant.py,sha256=gUApZs-N3DRSwV2_B05mPi6fCmynSzVZb28fgqdLX6E,1894
5
+ nonebot_plugin_werewolf/exception.py,sha256=YSwxeogIB0YJqH9MP1bgxojiu-I_xQE44XnSk5bC1AQ,400
6
+ nonebot_plugin_werewolf/game.py,sha256=FqYAs8CalCRUKoyPTpqvKK5iAelV9ZQ5EmefNo5wE9E,17459
7
+ nonebot_plugin_werewolf/matchers.py,sha256=Xnq1n4xobdr1T_8ilsQfXns_iEsNx_h_-aQ5jZwpWx0,2080
8
+ nonebot_plugin_werewolf/ob11_ext.py,sha256=P8uc3AdN5K5MzJaK80WDK85VKFg_CK5avDHu7ueMkho,2418
9
+ nonebot_plugin_werewolf/player.py,sha256=2jWlJOIWNK3JVVKNaqROfvKPRQfopDXv7KAXGtXNmh4,14973
10
+ nonebot_plugin_werewolf/player_set.py,sha256=7f4GHklp-wBGROddVqGUQAMeMzKlN2iec_w5UJQXvz0,2726
11
+ nonebot_plugin_werewolf/utils.py,sha256=LiNitH3UYNqXnCOOAzjKifVpJNhurIt4wYgWVBUW1Zo,6811
12
+ nonebot_plugin_werewolf-1.1.2.dist-info/LICENSE,sha256=B_WbEqjGr6GYVNfEJPY31T1Opik7OtgOkhRs4Ig3e2M,1064
13
+ nonebot_plugin_werewolf-1.1.2.dist-info/METADATA,sha256=0W7Nb6qqwJvW7xVdLHxM4643DuJ3YN9683owdDoUOhs,10363
14
+ nonebot_plugin_werewolf-1.1.2.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
15
+ nonebot_plugin_werewolf-1.1.2.dist-info/top_level.txt,sha256=wLTfg8sTKbH9lLT9LtU118C9cTspEBJareLsrYM52YA,24
16
+ nonebot_plugin_werewolf-1.1.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.1.2)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,15 +0,0 @@
1
- nonebot_plugin_werewolf/__init__.py,sha256=I6lFyJgJ4Tz4t8gS2lrsx-7paN2h_PNoGjGR8ryvSeU,734
2
- nonebot_plugin_werewolf/config.py,sha256=gl_ujiY-8fxQ5hN9_gjL1WpJJR5UOBIRBGofbLcQzaE,2900
3
- nonebot_plugin_werewolf/constant.py,sha256=1XNTcTicil90WSviI2e33FX0LstWXl1aV2ugbhsDlIk,1909
4
- nonebot_plugin_werewolf/exception.py,sha256=Ui8rB1sBg6_p8JHSvrjCpUaXJlgrM_9XsLJ09k8F1bg,391
5
- nonebot_plugin_werewolf/game.py,sha256=Y9MQASaNdm2uuNw37IjdQEQzikWmbql_PWLHaL7lcB8,17414
6
- nonebot_plugin_werewolf/matchers.py,sha256=5FioDfARlxTEibGL1JMKUMzmTzOwljjWKAJxBnyzaYs,2106
7
- nonebot_plugin_werewolf/ob11_ext.py,sha256=P8uc3AdN5K5MzJaK80WDK85VKFg_CK5avDHu7ueMkho,2418
8
- nonebot_plugin_werewolf/player.py,sha256=ifqTBfNepQY5FCY7hZoUA6DcObkcFEiNmKEeRkitJqY,14749
9
- nonebot_plugin_werewolf/player_set.py,sha256=AI8v6KjH9ACtP4lvrd5IJfayan0qALmpTRLC3s_3DFw,2754
10
- nonebot_plugin_werewolf/utils.py,sha256=l7oNSK471SV5CaB1eEVyZm10XSBFf_TwNotvb30U6vE,6835
11
- nonebot_plugin_werewolf-1.1.1.dist-info/LICENSE,sha256=B_WbEqjGr6GYVNfEJPY31T1Opik7OtgOkhRs4Ig3e2M,1064
12
- nonebot_plugin_werewolf-1.1.1.dist-info/METADATA,sha256=5ikh-mdZTIObaFs9w7qgzrgsx31lCxB5Ag--C8stl0g,10447
13
- nonebot_plugin_werewolf-1.1.1.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
14
- nonebot_plugin_werewolf-1.1.1.dist-info/top_level.txt,sha256=wLTfg8sTKbH9lLT9LtU118C9cTspEBJareLsrYM52YA,24
15
- nonebot_plugin_werewolf-1.1.1.dist-info/RECORD,,