nonebot-plugin-werewolf 1.1.3__py3-none-any.whl → 1.1.5__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.
Files changed (29) hide show
  1. nonebot_plugin_werewolf/__init__.py +2 -1
  2. nonebot_plugin_werewolf/constant.py +23 -1
  3. nonebot_plugin_werewolf/game.py +172 -113
  4. nonebot_plugin_werewolf/matchers/depends.py +38 -0
  5. nonebot_plugin_werewolf/matchers/message_in_game.py +14 -4
  6. nonebot_plugin_werewolf/matchers/poke/__init__.py +8 -0
  7. nonebot_plugin_werewolf/matchers/poke/chronocat_poke.py +117 -0
  8. nonebot_plugin_werewolf/matchers/{ob11_ext.py → poke/ob11_poke.py} +21 -19
  9. nonebot_plugin_werewolf/matchers/start_game.py +161 -15
  10. nonebot_plugin_werewolf/player_set.py +33 -34
  11. nonebot_plugin_werewolf/players/can_shoot.py +12 -18
  12. nonebot_plugin_werewolf/players/civilian.py +2 -2
  13. nonebot_plugin_werewolf/players/guard.py +15 -22
  14. nonebot_plugin_werewolf/players/hunter.py +2 -2
  15. nonebot_plugin_werewolf/players/idiot.py +3 -3
  16. nonebot_plugin_werewolf/players/joker.py +2 -2
  17. nonebot_plugin_werewolf/players/player.py +137 -65
  18. nonebot_plugin_werewolf/players/prophet.py +7 -15
  19. nonebot_plugin_werewolf/players/werewolf.py +51 -29
  20. nonebot_plugin_werewolf/players/witch.py +32 -38
  21. nonebot_plugin_werewolf/players/wolfking.py +2 -2
  22. nonebot_plugin_werewolf/utils.py +56 -190
  23. {nonebot_plugin_werewolf-1.1.3.dist-info → nonebot_plugin_werewolf-1.1.5.dist-info}/METADATA +14 -2
  24. nonebot_plugin_werewolf-1.1.5.dist-info/RECORD +31 -0
  25. {nonebot_plugin_werewolf-1.1.3.dist-info → nonebot_plugin_werewolf-1.1.5.dist-info}/WHEEL +1 -1
  26. nonebot_plugin_werewolf/_timeout.py +0 -110
  27. nonebot_plugin_werewolf-1.1.3.dist-info/RECORD +0 -29
  28. {nonebot_plugin_werewolf-1.1.3.dist-info → nonebot_plugin_werewolf-1.1.5.dist-info}/LICENSE +0 -0
  29. {nonebot_plugin_werewolf-1.1.3.dist-info → nonebot_plugin_werewolf-1.1.5.dist-info}/top_level.txt +0 -0
@@ -1,18 +1,16 @@
1
- import asyncio
2
- import itertools
3
- import re
1
+ import functools
4
2
  from collections import defaultdict
5
- from typing import Any, ClassVar
3
+ from typing import TYPE_CHECKING, Any, ClassVar, TypeVar
6
4
 
7
- import nonebot
8
- import nonebot_plugin_waiter as waiter
9
- from nonebot.adapters import Bot, Event
10
- from nonebot.rule import to_me
11
- from nonebot.utils import escape_tag
12
- from nonebot_plugin_alconna import MsgTarget, Target, UniMessage, UniMsg
13
- from nonebot_plugin_uninfo import Uninfo
5
+ import anyio
6
+ from nonebot_plugin_alconna import UniMessage
7
+ from nonebot_plugin_uninfo import Session
14
8
 
15
- from .config import config
9
+ if TYPE_CHECKING:
10
+ from .player_set import PlayerSet
11
+ from .players import Player
12
+
13
+ T = TypeVar("T")
16
14
 
17
15
 
18
16
  def check_index(text: str, arrlen: int) -> int | None:
@@ -23,198 +21,66 @@ def check_index(text: str, arrlen: int) -> int | None:
23
21
  return None
24
22
 
25
23
 
26
- class InputStore:
27
- locks: ClassVar[dict[str, asyncio.Lock]] = defaultdict(asyncio.Lock)
28
- futures: ClassVar[dict[str, asyncio.Future[UniMessage]]] = {}
29
- clear_handle: ClassVar[dict[str, asyncio.Handle]] = {}
30
-
31
- @classmethod
32
- def clear_lock(cls, key: str) -> None:
33
- if key in cls.locks and not cls.locks[key].locked():
34
- del cls.locks[key]
35
- if key in cls.clear_handle:
36
- del cls.clear_handle[key]
37
-
38
- @classmethod
39
- async def fetch(cls, user_id: str, group_id: str | None = None) -> UniMessage[Any]:
40
- key = f"{group_id}_{user_id}"
41
- async with cls.locks[key]:
42
- cls.futures[key] = fut = asyncio.get_event_loop().create_future()
43
- try:
44
- return await fut
45
- finally:
46
- del cls.futures[key]
47
- if key in cls.clear_handle:
48
- cls.clear_handle[key].cancel()
49
- loop = asyncio.get_event_loop()
50
- cls.clear_handle[key] = loop.call_later(120, cls.clear_lock, key)
24
+ def link(text: str, url: str | None) -> str:
25
+ return text if url is None else f"\u001b]8;;{url}\u0007{text}\u001b]8;;\u0007"
51
26
 
52
- @classmethod
53
- def put(cls, msg: UniMessage, user_id: str, group_id: str | None = None) -> None:
54
- key = f"{group_id}_{user_id}"
55
- if (future := cls.futures.get(key)) and not future.cancelled():
56
- future.set_result(msg)
57
27
 
28
+ def extract_session_member_nick(session: Session) -> str | None:
29
+ return (
30
+ (session.member and session.member.nick)
31
+ or session.user.nick
32
+ or session.user.name
33
+ )
58
34
 
59
- def user_in_game(self_id: str, user_id: str, group_id: str | None) -> bool:
60
- from .game import Game
61
35
 
62
- if group_id is None:
63
- return any(
64
- self_id == p.user.self_id and user_id == p.user_id
65
- for p in itertools.chain(*[g.players for g in Game.running_games])
66
- )
36
+ class _InputTask:
37
+ _event: anyio.Event
38
+ _msg: UniMessage
67
39
 
68
- def check(game: Game) -> bool:
69
- return self_id == game.group.self_id and group_id == game.group.id
40
+ def __init__(self) -> None:
41
+ self._event = anyio.Event()
70
42
 
71
- if game := next(filter(check, Game.running_games), None):
72
- return any(user_id == player.user_id for player in game.players)
43
+ def set(self, msg: UniMessage) -> None:
44
+ self._msg = msg
45
+ self._event.set()
73
46
 
74
- return False
47
+ async def wait(self) -> UniMessage:
48
+ await self._event.wait()
49
+ return self._msg
75
50
 
76
51
 
77
- async def rule_in_game(bot: Bot, event: Event, target: MsgTarget) -> bool:
78
- from .game import Game
52
+ class InputStore:
53
+ locks: ClassVar[dict[str, anyio.Lock]] = defaultdict(anyio.Lock)
54
+ tasks: ClassVar[dict[str, _InputTask]] = {}
79
55
 
80
- if not Game.running_games:
81
- return False
82
- if target.private:
83
- return user_in_game(bot.self_id, target.id, None)
84
- return user_in_game(bot.self_id, event.get_user_id(), target.id)
56
+ @classmethod
57
+ async def fetch(cls, user_id: str, group_id: str | None = None) -> UniMessage[Any]:
58
+ key = f"{group_id}_{user_id}"
59
+ async with cls.locks[key]:
60
+ cls.tasks[key] = task = _InputTask()
61
+ return await task.wait()
85
62
 
63
+ @classmethod
64
+ def put(cls, msg: UniMessage, user_id: str, group_id: str | None = None) -> None:
65
+ key = f"{group_id}_{user_id}"
66
+ if task := cls.tasks.pop(key, None):
67
+ task.set(msg)
86
68
 
87
- async def rule_not_in_game(bot: Bot, event: Event, target: MsgTarget) -> bool:
88
- return not await rule_in_game(bot, event, target)
69
+ @classmethod
70
+ def cleanup(cls, players: list[str], group_id: str) -> None:
71
+ for key in (f"{g}_{p}" for p in players for g in (group_id, None)):
72
+ if key in cls.locks:
73
+ del cls.locks[key]
74
+ if key in cls.tasks:
75
+ del cls.tasks[key]
89
76
 
90
77
 
91
- async def is_group(target: MsgTarget) -> bool:
92
- return not target.private
78
+ @functools.cache
79
+ def cached_player_set() -> type["PlayerSet"]:
80
+ from .player_set import PlayerSet
93
81
 
82
+ return PlayerSet
94
83
 
95
- async def _prepare_game_receive(
96
- queue: asyncio.Queue[tuple[str, str, str]],
97
- event: Event,
98
- group: Target,
99
- ) -> None:
100
- async def same_group(target: MsgTarget) -> bool:
101
- return group.verify(target)
102
84
 
103
- @waiter.waiter(
104
- waits=[event.get_type()],
105
- keep_session=False,
106
- rule=to_me() & same_group & rule_not_in_game,
107
- )
108
- def wait(
109
- event: Event,
110
- msg: UniMsg,
111
- session: Uninfo,
112
- ) -> tuple[str, str, str]:
113
- user_id = event.get_user_id()
114
- name = session.user.nick or session.user.name or user_id
115
- if session.member:
116
- name = session.member.nick or name
117
- return (
118
- user_id,
119
- msg.extract_plain_text().strip(),
120
- name,
121
- )
122
-
123
- async for user, text, name in wait(default=(None, "", "")):
124
- if user is None:
125
- continue
126
- await queue.put((user, text, re.sub(r"[\u2066-\u2069]", "", name)))
127
-
128
-
129
- async def _prepare_game_handle(
130
- queue: asyncio.Queue[tuple[str, str, str]],
131
- players: dict[str, str],
132
- admin_id: str,
133
- ) -> None:
134
- logger = nonebot.logger.opt(colors=True)
135
-
136
- while True:
137
- user, text, name = await queue.get()
138
- msg = UniMessage.at(user).text("\n")
139
- colored = f"<y>{escape_tag(name)}</y>(<c>{escape_tag(user)}</c>)"
140
-
141
- match (text, user == admin_id):
142
- case ("开始游戏", True):
143
- player_num = len(players)
144
- role_preset = config.get_role_preset()
145
- if player_num < min(role_preset):
146
- await (
147
- msg.text(f"⚠️游戏至少需要 {min(role_preset)} 人, ")
148
- .text(f"当前已有 {player_num} 人")
149
- .send()
150
- )
151
- elif player_num > max(role_preset):
152
- await (
153
- msg.text(f"⚠️游戏最多需要 {max(role_preset)} 人, ")
154
- .text(f"当前已有 {player_num} 人")
155
- .send()
156
- )
157
- elif player_num not in role_preset:
158
- await (
159
- msg.text(f"⚠️不存在总人数为 {player_num} 的预设, ")
160
- .text("无法开始游戏")
161
- .send()
162
- )
163
- else:
164
- await msg.text("✏️游戏即将开始...").send()
165
- logger.info(f"游戏发起者 {colored} 开始游戏")
166
- return
167
-
168
- case ("开始游戏", False):
169
- await msg.text("⚠️只有游戏发起者可以开始游戏").send()
170
-
171
- case ("结束游戏", True):
172
- logger.info(f"游戏发起者 {colored} 结束游戏")
173
- await msg.text("ℹ️已结束当前游戏").finish()
174
-
175
- case ("结束游戏", False):
176
- await msg.text("⚠️只有游戏发起者可以结束游戏").send()
177
-
178
- case ("加入游戏", True):
179
- await msg.text("ℹ️游戏发起者已经加入游戏了").send()
180
-
181
- case ("加入游戏", False):
182
- if user not in players:
183
- players[user] = name
184
- logger.info(f"玩家 {colored} 加入游戏")
185
- await msg.text("✅成功加入游戏").send()
186
- else:
187
- await msg.text("ℹ️你已经加入游戏了").send()
188
-
189
- case ("退出游戏", True):
190
- await msg.text("ℹ️游戏发起者无法退出游戏").send()
191
-
192
- case ("退出游戏", False):
193
- if user in players:
194
- del players[user]
195
- logger.info(f"玩家 {colored} 退出游戏")
196
- await msg.text("✅成功退出游戏").send()
197
- else:
198
- await msg.text("ℹ️你还没有加入游戏").send()
199
-
200
- case ("当前玩家", _):
201
- msg.text("✨当前玩家:\n")
202
- for idx, name in enumerate(players.values(), 1):
203
- msg.text(f"\n{idx}. {name}")
204
- await msg.send()
205
-
206
-
207
- async def prepare_game(event: Event, players: dict[str, str]) -> None:
208
- from .game import Game
209
-
210
- group = UniMessage.get_target(event)
211
- Game.starting_games[group] = players
212
-
213
- queue: asyncio.Queue[tuple[str, str, str]] = asyncio.Queue()
214
- task_receive = asyncio.create_task(_prepare_game_receive(queue, event, group))
215
-
216
- try:
217
- await _prepare_game_handle(queue, players, event.get_user_id())
218
- finally:
219
- task_receive.cancel()
220
- del Game.starting_games[group]
85
+ def as_player_set(*player: "Player") -> "PlayerSet":
86
+ return cached_player_set()(player)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nonebot-plugin-werewolf
3
- Version: 1.1.3
3
+ Version: 1.1.5
4
4
  Summary: 适用于 Nonebot2 的狼人杀插件
5
5
  Author-email: wyf7685 <wyf7685@163.com>
6
6
  License: MIT
@@ -14,6 +14,7 @@ Requires-Dist: nonebot2 >=2.3.3
14
14
  Requires-Dist: nonebot-plugin-alconna >=0.52.1
15
15
  Requires-Dist: nonebot-plugin-uninfo >=0.4.0
16
16
  Requires-Dist: nonebot-plugin-waiter >=0.7.1
17
+ Requires-Dist: anyio >=4.6.0
17
18
 
18
19
  <div align="center">
19
20
  <a href="https://v2.nonebot.dev/store">
@@ -42,6 +43,7 @@ _✨ 简单的狼人杀插件 ✨_
42
43
  [![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)
43
44
  [![publish](https://github.com/wyf7685/nonebot-plugin-werewolf/actions/workflows/pypi-publish.yml/badge.svg)](https://github.com/wyf7685/nonebot-plugin-werewolf/actions/workflows/pypi-publish.yml)
44
45
 
46
+ <!-- https://github.com/lgc2333/nonebot-registry-badge -->
45
47
  [![NoneBot Registry](https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin%2Fnonebot-plugin-werewolf)](https://registry.nonebot.dev/plugin/nonebot-plugin-werewolf:nonebot_plugin_werewolf)
46
48
  [![Supported Adapters](https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin-adapters%2Fnonebot-plugin-werewolf)](https://registry.nonebot.dev/plugin/nonebot-plugin-werewolf:nonebot_plugin_werewolf)
47
49
 
@@ -148,7 +150,7 @@ _✨ 简单的狼人杀插件 ✨_
148
150
 
149
151
  _其他交互参考游戏内提示_
150
152
 
151
- 对于 `OneBot V11` 适配器, 启用配置项 `werewolf__enable_poke` 后, 可以使用戳一戳代替 _准备阶段_ 的 `加入游戏` 操作 和 游戏内的 `/stop` 命令
153
+ 对于 `OneBot V11` 适配器和 `Satori` 适配器的 `chronocat`, 启用配置项 `werewolf__enable_poke` 后, 可以使用戳一戳代替 _准备阶段_ 的 `加入游戏` 操作 和 游戏内的 `stop` 命令
152
154
 
153
155
  ### 游戏内容
154
156
 
@@ -236,6 +238,10 @@ werewolf__priesthood_proirity=[11, 12, 13, 14, 15]
236
238
 
237
239
  </details>
238
240
 
241
+ ### 已知问题
242
+
243
+ - 截止 chronocat v0.2.19, 调用 [`guild.member.get`](https://github.com/chrononeko/chronocat/blob/8558ad9ff4319395d86abbfda22136939bf66780/packages/engine-chronocat-api/src/api/guild/member/get.ts) / [`user.get`](https://github.com/chrononeko/chronocat/blob/8558ad9ff4319395d86abbfda22136939bf66780/packages/engine-chronocat-api/src/api/user/get.ts) 均无法获取用户名,这将导致在交互过程中的玩家名显示为用户ID
244
+
239
245
  ## 📝 更新日志
240
246
 
241
247
  <details>
@@ -243,6 +249,12 @@ werewolf__priesthood_proirity=[11, 12, 13, 14, 15]
243
249
 
244
250
  <!-- CHANGELOG -->
245
251
 
252
+ - 2024.10.23 v1.1.5
253
+
254
+ - 添加对 chronocat:poke 的支持
255
+ - 游戏内 stop 命令使用 COMMAND_START
256
+ - 使用 `anyio` 重写并发逻辑
257
+
246
258
  - 2024.10.06 v1.1.3
247
259
 
248
260
  - 使用 `RF-Tar-Railt/nonebot-plugin-uninfo` 获取用户数据
@@ -0,0 +1,31 @@
1
+ nonebot_plugin_werewolf/__init__.py,sha256=v65nKZbsbmaJPR0o2ZrXuumUvCuEOvDVtVmw65CyVn8,894
2
+ nonebot_plugin_werewolf/config.py,sha256=FKQDkb57ujcBYJZX-sLgxWmTVqSeR7T1ywphp7GOCcE,2803
3
+ nonebot_plugin_werewolf/constant.py,sha256=d4Awy96YBe_AJoAZyd_6Wojo0qi2BTVM_LW-nDbsxQE,2902
4
+ nonebot_plugin_werewolf/exception.py,sha256=YSwxeogIB0YJqH9MP1bgxojiu-I_xQE44XnSk5bC1AQ,400
5
+ nonebot_plugin_werewolf/game.py,sha256=yUfJtLWH7--TRPnofAGfrUkUvd_3VW1J9j8zhTrN9hc,19106
6
+ nonebot_plugin_werewolf/player_set.py,sha256=J5KFWSugpu1Zd_gToqa-Gweoikj8kppLpckVjl-4XH0,2540
7
+ nonebot_plugin_werewolf/utils.py,sha256=6uFwgf4LAI1SZ_qH6I2ilHt2vbs6NfTj5YhMvC4GacE,2279
8
+ nonebot_plugin_werewolf/matchers/__init__.py,sha256=_MwAZsXlpBLXyzHWqNLTQdMWw9z_O01L5Yo02dzGC9I,88
9
+ nonebot_plugin_werewolf/matchers/depends.py,sha256=6JFLxQDgRjStbMkpoWe1tYZHs0wVfsyn4KikKNpgx0Q,1160
10
+ nonebot_plugin_werewolf/matchers/message_in_game.py,sha256=YkphERN2efaB0VdU3oTCvvYptrqDaKFKUb9moUyqIpY,780
11
+ nonebot_plugin_werewolf/matchers/start_game.py,sha256=ZNO2ypV8kMlImR0fZVhg0ZI8mrOsW3I-eioT6Lhf2Cw,7427
12
+ nonebot_plugin_werewolf/matchers/poke/__init__.py,sha256=gYysvGjztN3iDQpX6v5nkPT195FXnk7fqP9kzByTES0,220
13
+ nonebot_plugin_werewolf/matchers/poke/chronocat_poke.py,sha256=SrFN8dQELFVDR5US9sOcE2gaOnH7AFiRVVK2RNa-Y5o,4023
14
+ nonebot_plugin_werewolf/matchers/poke/ob11_poke.py,sha256=LROxtbauw4xbB8UKglsx6b6hkKWs_17HmgK4NTXW1HY,2640
15
+ nonebot_plugin_werewolf/players/__init__.py,sha256=djAI5XxR2I-XvnH-lVqX_YCHB_AiT-6jdmwFE1ffN_0,379
16
+ nonebot_plugin_werewolf/players/can_shoot.py,sha256=e9QtRUNxNZ9n3MxX7o0bUmQLLPDazTOZky3F_2m6UhM,1813
17
+ nonebot_plugin_werewolf/players/civilian.py,sha256=TbrIxjG4g74C9Cd_F3OskuM-ksKUkOLiE6OgPqmo0pA,157
18
+ nonebot_plugin_werewolf/players/guard.py,sha256=T2L7f0Dcx6jjlOrGcHUQxy9RawszvP6AKaI8Lz9nItI,1112
19
+ nonebot_plugin_werewolf/players/hunter.py,sha256=NaJNjngKCHC8RI1YsYI5XtVyFq9JP5U1ywOTbjjUHq4,195
20
+ nonebot_plugin_werewolf/players/idiot.py,sha256=Tpjf7RPW1dJ3J4ajr5HWcIustHO-h6PNicum4SiofDE,1433
21
+ nonebot_plugin_werewolf/players/joker.py,sha256=J_t-IPKjyHWq8azxFdN_cmJhbgoDcokiMLf-pMXQInE,691
22
+ nonebot_plugin_werewolf/players/player.py,sha256=JUCev-3jnAqApNR-cFaHRHkQVIgBfn5HhHhLq8OGWgw,6954
23
+ nonebot_plugin_werewolf/players/prophet.py,sha256=VQa4RJUbLpG9ntB055ORl09oEAmZ1uOUi4P4q_P_9TY,897
24
+ nonebot_plugin_werewolf/players/werewolf.py,sha256=MZOsHWNnKvh_fxKMEIWqa_yJIYHVjA1fM5W3jkg_CtU,3433
25
+ nonebot_plugin_werewolf/players/witch.py,sha256=XDCVSXhUA9afh0iCdxV8Shfc1YGDkXYhu1h0v1xpbmg,2340
26
+ nonebot_plugin_werewolf/players/wolfking.py,sha256=oBC5JW0UULDkthurDBvHRNo3rqArm-zQ_1jSuyeHpQU,440
27
+ nonebot_plugin_werewolf-1.1.5.dist-info/LICENSE,sha256=B_WbEqjGr6GYVNfEJPY31T1Opik7OtgOkhRs4Ig3e2M,1064
28
+ nonebot_plugin_werewolf-1.1.5.dist-info/METADATA,sha256=j-vwRZiK1lobgZ10-X30Upf6Vuo1ZYMraWgQvStKjvI,11435
29
+ nonebot_plugin_werewolf-1.1.5.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
30
+ nonebot_plugin_werewolf-1.1.5.dist-info/top_level.txt,sha256=wLTfg8sTKbH9lLT9LtU118C9cTspEBJareLsrYM52YA,24
31
+ nonebot_plugin_werewolf-1.1.5.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.1.0)
2
+ Generator: setuptools (75.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,110 +0,0 @@
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,29 +0,0 @@
1
- nonebot_plugin_werewolf/__init__.py,sha256=Im_u8hP6N6qA2SwnNSGu1MsewLoyHUa3v0Paj1yC3T0,862
2
- nonebot_plugin_werewolf/_timeout.py,sha256=MVkA5oMoxOTV8Luc0BH2QPP8wwz4Tr9CJjeYgiPu_O4,3649
3
- nonebot_plugin_werewolf/config.py,sha256=FKQDkb57ujcBYJZX-sLgxWmTVqSeR7T1ywphp7GOCcE,2803
4
- nonebot_plugin_werewolf/constant.py,sha256=-S-KjlrSc_wJwsXCkQOMFVqyu4RwR4GLXIRZEp_0mlI,2300
5
- nonebot_plugin_werewolf/exception.py,sha256=YSwxeogIB0YJqH9MP1bgxojiu-I_xQE44XnSk5bC1AQ,400
6
- nonebot_plugin_werewolf/game.py,sha256=LWxn2OCnkTAF8NdLt1BQzyAtyUfk477xisCf5mbfK_E,17376
7
- nonebot_plugin_werewolf/player_set.py,sha256=BlK7wHv_9YrCINMAPWL36TLkRjAiI_GXSHlZySVemoo,2777
8
- nonebot_plugin_werewolf/utils.py,sha256=50bJGhJU7b9kQEqmc2V8-5wYkukilDtchZBSBKcwwq4,7633
9
- nonebot_plugin_werewolf/matchers/__init__.py,sha256=_MwAZsXlpBLXyzHWqNLTQdMWw9z_O01L5Yo02dzGC9I,88
10
- nonebot_plugin_werewolf/matchers/message_in_game.py,sha256=hpQCaNaxCikma8DJTJLCttP5B1vBWlqMDEukSqfPlRk,452
11
- nonebot_plugin_werewolf/matchers/ob11_ext.py,sha256=TGhI4yWfb5N3K9hXkI8k8Rs6cMVXDwp05cXtu3a-_jU,2597
12
- nonebot_plugin_werewolf/matchers/start_game.py,sha256=DZPQ88hiobuJejIbKsIc8ZcoKDw7wcjawWfTC3wjIto,1884
13
- nonebot_plugin_werewolf/players/__init__.py,sha256=djAI5XxR2I-XvnH-lVqX_YCHB_AiT-6jdmwFE1ffN_0,379
14
- nonebot_plugin_werewolf/players/can_shoot.py,sha256=6u_luXfNOWO0svTpb78h74HcG65kh1GZyFPJFYNuOG0,2068
15
- nonebot_plugin_werewolf/players/civilian.py,sha256=6iKEWRRWDGq1qgVZZZ9pX7kBVpMN-yfxeLq9hIp17hU,165
16
- nonebot_plugin_werewolf/players/guard.py,sha256=pDH66q-KoU5oRD-tn542x3siXv9BM824-KRxsVb0Gvk,1408
17
- nonebot_plugin_werewolf/players/hunter.py,sha256=nqYGCVppd4mdCPhFHZbjbbNvZfyCNT0bZ3raQFXmELA,203
18
- nonebot_plugin_werewolf/players/idiot.py,sha256=7-BTsYUSOcs5rPOJx1hsHPOWcmGcv2rSO8IfUGPdqEE,1456
19
- nonebot_plugin_werewolf/players/joker.py,sha256=uUK6EuoOWd8_35yvBTkM14XCplOFwFCRsbhR7bjeiD8,699
20
- nonebot_plugin_werewolf/players/player.py,sha256=ejEjbsrIKpUJql3-qLMFsZY_jGFtQ3OTjcN1lFZ4yKo,4697
21
- nonebot_plugin_werewolf/players/prophet.py,sha256=nh8eB9T9LMBiqNgnqE-ygAFiYvTZS8bGUKYsNBPm8F0,1078
22
- nonebot_plugin_werewolf/players/werewolf.py,sha256=kyZjwijEGG0EkP80VOlu8HFzReg33v8a-o670fZN_xI,2560
23
- nonebot_plugin_werewolf/players/witch.py,sha256=P1odgjFc9kAIUxmlz9aV69aYzl76OVcsQQGhigmRTgc,2571
24
- nonebot_plugin_werewolf/players/wolfking.py,sha256=hgxOugrIOF6wC5wKcjflPuQ2K4d99eWpF9E69ishbsg,440
25
- nonebot_plugin_werewolf-1.1.3.dist-info/LICENSE,sha256=B_WbEqjGr6GYVNfEJPY31T1Opik7OtgOkhRs4Ig3e2M,1064
26
- nonebot_plugin_werewolf-1.1.3.dist-info/METADATA,sha256=uLZxheMxeLRL70cOrpZtr1Nqy2gP1sAIFNiiNtkEwi4,10707
27
- nonebot_plugin_werewolf-1.1.3.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
28
- nonebot_plugin_werewolf-1.1.3.dist-info/top_level.txt,sha256=wLTfg8sTKbH9lLT9LtU118C9cTspEBJareLsrYM52YA,24
29
- nonebot_plugin_werewolf-1.1.3.dist-info/RECORD,,