nonebot-plugin-l4d2-server 1.0.3__py3-none-any.whl → 1.0.4__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.
- nonebot_plugin_l4d2_server/__main__.py +77 -31
- nonebot_plugin_l4d2_server/config.py +52 -3
- nonebot_plugin_l4d2_server/l4_help/__init__.py +1 -1
- nonebot_plugin_l4d2_server/l4_request/__init__.py +109 -29
- nonebot_plugin_l4d2_server/l4_request/draw_msg.py +172 -35
- nonebot_plugin_l4d2_server/utils/api/models.py +1 -1
- nonebot_plugin_l4d2_server/utils/api/request.py +29 -10
- nonebot_plugin_l4d2_server/utils/utils.py +11 -2
- {nonebot_plugin_l4d2_server-1.0.3.dist-info → nonebot_plugin_l4d2_server-1.0.4.dist-info}/METADATA +17 -14
- {nonebot_plugin_l4d2_server-1.0.3.dist-info → nonebot_plugin_l4d2_server-1.0.4.dist-info}/RECORD +13 -15
- nonebot_plugin_l4d2_server/l4_anne/__init__.py +0 -125
- nonebot_plugin_l4d2_server/l4_anne/ranne.py +0 -18
- {nonebot_plugin_l4d2_server-1.0.3.dist-info → nonebot_plugin_l4d2_server-1.0.4.dist-info}/WHEEL +0 -0
- {nonebot_plugin_l4d2_server-1.0.3.dist-info → nonebot_plugin_l4d2_server-1.0.4.dist-info}/entry_points.txt +0 -0
- {nonebot_plugin_l4d2_server-1.0.3.dist-info → nonebot_plugin_l4d2_server-1.0.4.dist-info}/licenses/LICENSE +0 -0
@@ -16,7 +16,7 @@
|
|
16
16
|
"""
|
17
17
|
|
18
18
|
from pathlib import Path
|
19
|
-
from typing import TYPE_CHECKING, List, Optional
|
19
|
+
from typing import TYPE_CHECKING, List, Optional, Union
|
20
20
|
|
21
21
|
import aiofiles
|
22
22
|
import ujson as json
|
@@ -24,10 +24,11 @@ from nonebot.adapters import Message
|
|
24
24
|
from nonebot.log import logger
|
25
25
|
from nonebot.matcher import Matcher
|
26
26
|
from nonebot.params import CommandArg, CommandStart, RawCommand
|
27
|
+
from nonebot.permission import SUPERUSER
|
27
28
|
from nonebot.plugin import on_command
|
28
29
|
from nonebot_plugin_alconna import UniMessage
|
29
30
|
|
30
|
-
from .config import config
|
31
|
+
from .config import config, config_manager
|
31
32
|
from .l4_help import get_l4d2_core_help
|
32
33
|
from .l4_local import * # noqa: F403
|
33
34
|
from .l4_request import (
|
@@ -45,7 +46,7 @@ if TYPE_CHECKING:
|
|
45
46
|
|
46
47
|
reload_ip()
|
47
48
|
|
48
|
-
l4_help = on_command("l4help", aliases={"
|
49
|
+
l4_help = on_command("l4help", aliases={"l4d2帮助"})
|
49
50
|
l4_request = on_command("anne", aliases=COMMAND, priority=10)
|
50
51
|
l4_reload = on_command("l4reload", aliases={"l4刷新,l4重载"})
|
51
52
|
l4_all = on_command("l4all", aliases={"l4全服"})
|
@@ -59,13 +60,11 @@ config_path = Path(config.l4_path) / "config.json"
|
|
59
60
|
|
60
61
|
|
61
62
|
@l4_help.handle()
|
62
|
-
async def _(
|
63
|
+
async def _():
|
63
64
|
"""帮助"""
|
64
65
|
logger.info("开始执行[l4d2帮助]")
|
65
66
|
im = await get_l4d2_core_help()
|
66
|
-
|
67
|
-
await matcher.finish(im)
|
68
|
-
await UniMessage.image(raw=im).send()
|
67
|
+
await out_msg_out(im)
|
69
68
|
|
70
69
|
|
71
70
|
@l4_request.handle()
|
@@ -74,11 +73,31 @@ async def _(
|
|
74
73
|
command: str = RawCommand(),
|
75
74
|
args: Message = CommandArg(),
|
76
75
|
):
|
77
|
-
"""
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
76
|
+
"""
|
77
|
+
异步函数,用于处理特定的指令。
|
78
|
+
|
79
|
+
Args:
|
80
|
+
start (str, optional): 指令的开头部分,默认为 CommandStart() 返回的值。
|
81
|
+
command (str, optional): 完整的指令字符串,默认为 RawCommand() 返回的值。
|
82
|
+
args (Message, optional): 指令后的参数,默认为 CommandArg() 返回的值。
|
83
|
+
|
84
|
+
Returns:
|
85
|
+
None
|
86
|
+
|
87
|
+
Examples:
|
88
|
+
示例指令:"/橘5"
|
89
|
+
- start: "/" (指令的开头部分)
|
90
|
+
- command: "/橘" (完整的指令字符串)
|
91
|
+
- args: "5" (指令后的参数)
|
92
|
+
|
93
|
+
Notes:
|
94
|
+
1. 如果 start 存在,会将 command 中的 start 部分替换为空字符串。
|
95
|
+
2. 如果 command 等于 "anne",则将其替换为 "云"。
|
96
|
+
3. 提取 args 中的纯文本内容,如果内容非空且不是数字,则返回。
|
97
|
+
4. 如果 args 为空,则将其设置为 None。
|
98
|
+
5. 使用 logger 记录处理过程中的信息。
|
99
|
+
6. 调用 get_server_detail 函数获取服务器详情,并根据返回结果发送相应的消息。
|
100
|
+
7. 如果 get_server_detail 返回 None,则发送 "服务器无响应" 的文本消息。
|
82
101
|
"""
|
83
102
|
|
84
103
|
if start:
|
@@ -93,12 +112,9 @@ async def _(
|
|
93
112
|
logger.info(f"组:{command} ;数字:{_id}")
|
94
113
|
msg = await get_server_detail(command, _id)
|
95
114
|
if msg is not None:
|
96
|
-
|
97
|
-
await UniMessage.text(msg).finish()
|
98
|
-
if isinstance(msg, bytes):
|
99
|
-
await UniMessage.image(raw=msg).finish()
|
115
|
+
await out_msg_out(msg, is_connect=config.l4_image)
|
100
116
|
else:
|
101
|
-
await
|
117
|
+
await out_msg_out("服务器无响应")
|
102
118
|
|
103
119
|
|
104
120
|
@l4_find_player.handle()
|
@@ -120,32 +136,26 @@ async def _(
|
|
120
136
|
if len(tag_list) == 2:
|
121
137
|
group, name = tag_list
|
122
138
|
await UniMessage.text(f"正在查询{group}组").send()
|
123
|
-
out: List[OutServer] = await get_server_detail(group, is_img=False) # type: ignore
|
139
|
+
out: List[OutServer] = await get_server_detail(group=group, is_img=False) # type: ignore
|
124
140
|
out_msg = "未找到玩家"
|
125
141
|
for one in out:
|
126
142
|
for player in one["player"]:
|
127
143
|
if name in player.name:
|
128
144
|
out_msg = await get_ip_server(f"{one['host']}:{one['port']}")
|
129
145
|
|
130
|
-
return await
|
146
|
+
return await out_msg_out(out_msg)
|
131
147
|
|
132
148
|
|
133
149
|
@l4_all.handle()
|
134
150
|
async def _():
|
135
|
-
await
|
151
|
+
await out_msg_out(await get_all_server_detail())
|
136
152
|
|
137
153
|
|
138
154
|
@l4_connect.handle()
|
139
155
|
async def _(args: Message = CommandArg()):
|
140
156
|
ip: Optional[str] = args.extract_plain_text()
|
141
157
|
if ip is not None:
|
142
|
-
await
|
143
|
-
|
144
|
-
|
145
|
-
# anne部分
|
146
|
-
if config.l4_anne:
|
147
|
-
logger.info("加载anne功能")
|
148
|
-
from .l4_anne import * # noqa: F403
|
158
|
+
await out_msg_out(await get_ip_server(ip), is_connect=config.l4_image)
|
149
159
|
|
150
160
|
|
151
161
|
@l4_reload.handle()
|
@@ -161,7 +171,7 @@ async def _(args: Message = CommandArg()):
|
|
161
171
|
for tag, url in ip_json.items():
|
162
172
|
logger.info(f"重载{tag}的ip")
|
163
173
|
await L4API.get_sourceban(tag, url)
|
164
|
-
await
|
174
|
+
await out_msg_out("重载ip完成")
|
165
175
|
|
166
176
|
|
167
177
|
l4_add_ban = on_command("l4addban", aliases={"l4添加ban"})
|
@@ -192,7 +202,7 @@ async def _(args: Message = CommandArg()):
|
|
192
202
|
await UniMessage.text(f"文件写入失败: {e}").finish()
|
193
203
|
|
194
204
|
await L4API.get_sourceban(arg[0], arg[1])
|
195
|
-
await
|
205
|
+
await out_msg_out(f"添加成功\n组名: {arg[0]}\n网址: {arg[1]}")
|
196
206
|
|
197
207
|
|
198
208
|
l4_del_ban = on_command("l4delban", aliases={"l4删除ban", "l4移除ban"})
|
@@ -219,7 +229,7 @@ async def _(args: Message = CommandArg()):
|
|
219
229
|
del config_data[arg[0]]
|
220
230
|
async with aiofiles.open(config_path, "w", encoding="utf-8") as f:
|
221
231
|
json.dump(config_data, f, ensure_ascii=False, indent=4)
|
222
|
-
await
|
232
|
+
await out_msg_out(f"删除成功,组名:{arg[0]}")
|
223
233
|
elif len(arg) == 2:
|
224
234
|
if not Path(Path(config.l4_path) / "config.json").is_file():
|
225
235
|
await UniMessage.text("没有添加过组名").finish()
|
@@ -236,7 +246,7 @@ async def _(args: Message = CommandArg()):
|
|
236
246
|
config_datas[arg[0]] = arg[1]
|
237
247
|
async with aiofiles.open(config_path, "w", encoding="utf-8") as f:
|
238
248
|
json.dump(config_datas, f, ensure_ascii=False, indent=4)
|
239
|
-
await
|
249
|
+
await out_msg_out(f"修改成功,组名:{arg[0]},网址:{arg[1]}")
|
240
250
|
|
241
251
|
|
242
252
|
@ld_tj.handle()
|
@@ -249,3 +259,39 @@ async def _(matcher: Matcher):
|
|
249
259
|
async def _(matcher: Matcher):
|
250
260
|
await matcher.send("正在寻找牢房信息")
|
251
261
|
await matcher.finish(await tj_request("云", "zl"))
|
262
|
+
|
263
|
+
|
264
|
+
async def out_msg_out(
|
265
|
+
msg: Union[str, bytes, UniMessage],
|
266
|
+
is_connect: bool = False,
|
267
|
+
host: str = "",
|
268
|
+
port: str = "",
|
269
|
+
):
|
270
|
+
if isinstance(msg, UniMessage):
|
271
|
+
return await msg.finish()
|
272
|
+
if isinstance(msg, str):
|
273
|
+
await UniMessage.text(msg).finish()
|
274
|
+
if is_connect:
|
275
|
+
out = UniMessage.image(raw=msg) + UniMessage.text(
|
276
|
+
f"连接到服务器: {host}:{port}",
|
277
|
+
)
|
278
|
+
return await out.finish()
|
279
|
+
return await UniMessage.image(raw=msg).finish()
|
280
|
+
|
281
|
+
|
282
|
+
## 以下为配置修改
|
283
|
+
|
284
|
+
img_trung = on_command("l4img", aliases={"l4图片"}, permission=SUPERUSER)
|
285
|
+
|
286
|
+
|
287
|
+
@img_trung.handle()
|
288
|
+
async def _(args: Message = CommandArg()):
|
289
|
+
arg = args.extract_plain_text().strip().lower()
|
290
|
+
if arg == "开启":
|
291
|
+
config_manager.update_image_config(enabled=True)
|
292
|
+
await out_msg_out("[l4]已开启图片模式")
|
293
|
+
elif arg == "关闭":
|
294
|
+
config_manager.update_image_config(enabled=False)
|
295
|
+
await out_msg_out("[l4]已关闭图片模式")
|
296
|
+
else:
|
297
|
+
await UniMessage.text("请在参数后加上开启或关闭").finish()
|
@@ -20,11 +20,9 @@ map_index = 0
|
|
20
20
|
|
21
21
|
|
22
22
|
class ConfigModel(BaseModel):
|
23
|
-
l4_anne: bool = False
|
24
|
-
"""是否启用anne电信服相关功能"""
|
25
23
|
l4_enable: bool = True
|
26
24
|
"""是否全局启用求生功能"""
|
27
|
-
l4_image: bool =
|
25
|
+
l4_image: bool = True
|
28
26
|
"""是否启用图片"""
|
29
27
|
l4_connect: bool = True
|
30
28
|
"""是否在查服命令后加入connect ip"""
|
@@ -43,3 +41,54 @@ class ConfigModel(BaseModel):
|
|
43
41
|
|
44
42
|
|
45
43
|
config = get_plugin_config(ConfigModel)
|
44
|
+
|
45
|
+
|
46
|
+
class ConfigManager:
|
47
|
+
"""配置项管理类,提供类型安全的配置更新方法"""
|
48
|
+
|
49
|
+
def __init__(self):
|
50
|
+
self._config = config
|
51
|
+
|
52
|
+
def update_image_config(self, enabled: bool) -> None:
|
53
|
+
"""更新图片配置
|
54
|
+
|
55
|
+
Args:
|
56
|
+
enabled: 是否启用图片功能
|
57
|
+
"""
|
58
|
+
self._config.l4_image = enabled
|
59
|
+
|
60
|
+
def update_style_config(self, style: str) -> None:
|
61
|
+
"""更新图片风格配置
|
62
|
+
|
63
|
+
Args:
|
64
|
+
style: 图片风格名称
|
65
|
+
"""
|
66
|
+
if not isinstance(style, str):
|
67
|
+
raise TypeError("style必须是字符串")
|
68
|
+
self._config.l4_style = style
|
69
|
+
|
70
|
+
def update_connect_config(self, enabled: bool) -> None:
|
71
|
+
"""更新connect ip配置
|
72
|
+
|
73
|
+
Args:
|
74
|
+
enabled: 是否在查服命令后加入connect ip
|
75
|
+
"""
|
76
|
+
self._config.l4_connect = enabled
|
77
|
+
|
78
|
+
def update(self, **kwargs) -> None:
|
79
|
+
"""通用配置更新方法
|
80
|
+
|
81
|
+
Args:
|
82
|
+
**kwargs: 要更新的配置项键值对
|
83
|
+
|
84
|
+
Raises:
|
85
|
+
ValueError: 当传入无效的配置项时
|
86
|
+
"""
|
87
|
+
for key, value in kwargs.items():
|
88
|
+
if hasattr(self._config, key):
|
89
|
+
setattr(self._config, key, value)
|
90
|
+
else:
|
91
|
+
raise ValueError(f"无效的配置项: {key}")
|
92
|
+
|
93
|
+
|
94
|
+
config_manager = ConfigManager()
|
@@ -10,7 +10,7 @@ from ..l4_image.convert import core_font
|
|
10
10
|
from ..l4_image.model import PluginHelp
|
11
11
|
from .draw import get_help
|
12
12
|
|
13
|
-
__version__ = "1.0.
|
13
|
+
__version__ = "1.0.4"
|
14
14
|
TEXT_PATH = Path(__file__).parent / "texture2d"
|
15
15
|
HELP_DATA = Path(__file__).parent / "Help.json"
|
16
16
|
|
@@ -1,11 +1,12 @@
|
|
1
1
|
import random
|
2
|
-
from typing import Dict, List, Optional, cast
|
2
|
+
from typing import Dict, List, Optional, Tuple, Union, cast
|
3
3
|
|
4
4
|
from nonebot.log import logger
|
5
|
+
from nonebot_plugin_alconna import UniMessage
|
5
6
|
|
6
7
|
from ..config import server_all_path
|
7
8
|
from ..l4_image import msg_to_image
|
8
|
-
from ..utils.api.models import AllServer, NserverOut
|
9
|
+
from ..utils.api.models import AllServer, NserverOut
|
9
10
|
from ..utils.api.request import L4API
|
10
11
|
from ..utils.utils import split_maohao
|
11
12
|
from .draw_msg import convert_duration, draw_one_ip, get_much_server
|
@@ -79,48 +80,127 @@ async def get_server_detail(
|
|
79
80
|
command (str): 服务器组名。
|
80
81
|
_id (Optional[str], optional): 服务器ID。默认为None。
|
81
82
|
is_img (bool, optional): 是否返回图片格式的信息。默认为True。
|
83
|
+
return_host_port (bool, optional): 是否返回host和port值。默认为False。
|
82
84
|
|
83
85
|
Returns:
|
84
|
-
Union[bytes,
|
85
|
-
|
86
|
-
|
86
|
+
Union[bytes, str, None, Tuple[str, int]]:
|
87
|
+
如果return_host_port为True且_id不为None,返回(host, port)元组;
|
88
|
+
否则返回服务器详细信息(图片格式返回bytes,文本格式返回str);
|
89
|
+
未找到服务器组返回None。
|
87
90
|
"""
|
88
|
-
|
89
|
-
server_json = ALLHOST.get(command)
|
90
|
-
else:
|
91
|
-
server_json = []
|
92
|
-
for servers in ALLHOST.values():
|
93
|
-
server_json.extend(servers)
|
94
|
-
|
91
|
+
server_json = _get_server_json(command)
|
95
92
|
logger.info(server_json)
|
96
93
|
if server_json is None:
|
97
94
|
logger.warning("未找到这个组")
|
98
95
|
return None
|
99
96
|
|
100
97
|
if _id is None:
|
101
|
-
|
102
|
-
logger.info(f"正在请求组服务器信息 {command}")
|
103
|
-
server_dict = await get_much_server(server_json, command)
|
104
|
-
if is_img:
|
105
|
-
out_msg = await msg_to_image(server_dict)
|
106
|
-
else:
|
107
|
-
out_msg = server_dict
|
108
|
-
return out_msg
|
98
|
+
return await _handle_group_info(server_json, command, is_img)
|
109
99
|
|
110
|
-
|
111
|
-
|
112
|
-
|
100
|
+
_ip = await get_single_server_info(server_json, _id)
|
101
|
+
if _ip is None:
|
102
|
+
logger.warning("未找到这个服务器")
|
103
|
+
return None
|
104
|
+
|
105
|
+
out_msg = await _handle_single_server(server_json, _id, is_img)
|
106
|
+
if isinstance(out_msg, bytes):
|
107
|
+
return UniMessage.image(raw=out_msg) + UniMessage.text(
|
108
|
+
f"connect {_ip[0]}:{_ip[1]}",
|
109
|
+
)
|
110
|
+
if isinstance(out_msg, str):
|
111
|
+
return UniMessage.text(out_msg)
|
112
|
+
return None
|
113
|
+
|
114
|
+
|
115
|
+
def _get_server_json(command: str) -> Optional[list]:
|
116
|
+
"""
|
117
|
+
根据命令获取服务器JSON列表
|
118
|
+
|
119
|
+
Args:
|
120
|
+
command (str): 服务器组名
|
121
|
+
|
122
|
+
Returns:
|
123
|
+
Optional[list]: 服务器JSON列表,未找到组时返回None
|
124
|
+
"""
|
125
|
+
if command:
|
126
|
+
return ALLHOST.get(command)
|
127
|
+
server_json = []
|
128
|
+
for servers in ALLHOST.values():
|
129
|
+
server_json.extend(servers)
|
130
|
+
return server_json
|
131
|
+
|
132
|
+
|
133
|
+
async def _handle_group_info(
|
134
|
+
server_json: list,
|
135
|
+
command: str,
|
136
|
+
is_img: bool,
|
137
|
+
) -> Union[bytes, str, None]:
|
138
|
+
"""
|
139
|
+
处理服务器组信息请求
|
140
|
+
|
141
|
+
Args:
|
142
|
+
server_json (list): 服务器JSON列表
|
143
|
+
command (str): 服务器组名
|
144
|
+
is_img (bool): 是否返回图片格式
|
145
|
+
|
146
|
+
Returns:
|
147
|
+
Union[bytes, list, None]: 图片格式返回bytes,否则返回服务器列表
|
148
|
+
"""
|
149
|
+
logger.info(f"正在请求组服务器信息 {command}")
|
150
|
+
server_dict = await get_much_server(server_json, command)
|
151
|
+
if is_img:
|
152
|
+
return await msg_to_image(server_dict)
|
153
|
+
return str(server_dict)
|
154
|
+
|
155
|
+
|
156
|
+
async def get_single_server_info(
|
157
|
+
server_json: list,
|
158
|
+
_id: str,
|
159
|
+
) -> Optional[Tuple[str, int]]:
|
160
|
+
"""
|
161
|
+
获取单个服务器的host和port信息
|
162
|
+
|
163
|
+
Args:
|
164
|
+
server_json (list): 服务器JSON列表
|
165
|
+
_id (str): 服务器ID
|
166
|
+
|
167
|
+
Returns:
|
168
|
+
Optional[Tuple[str, int]]: 返回(host, port)元组,未找到返回None
|
169
|
+
"""
|
170
|
+
logger.info("正在获取单服务器信息")
|
113
171
|
for i in server_json:
|
114
172
|
if str(_id) == str(i["id"]):
|
115
|
-
|
116
|
-
if is_img:
|
117
|
-
return cast(bytes, out_msg)
|
118
|
-
if not is_img:
|
119
|
-
return cast(List[OutServer], out_msg)
|
120
|
-
# print(out_msg)
|
173
|
+
return i["host"], i["port"]
|
121
174
|
return None
|
122
175
|
|
123
176
|
|
177
|
+
async def _handle_single_server(
|
178
|
+
server_json: list,
|
179
|
+
_id: str,
|
180
|
+
is_img: bool,
|
181
|
+
) -> Union[bytes, str, None]:
|
182
|
+
"""
|
183
|
+
处理单个服务器信息请求
|
184
|
+
|
185
|
+
Args:
|
186
|
+
server_json (list): 服务器JSON列表
|
187
|
+
_id (str): 服务器ID
|
188
|
+
is_img (bool): 是否返回图片格式
|
189
|
+
|
190
|
+
Returns:
|
191
|
+
Union[bytes, str, None]: 找到服务器时返回信息,否则返回None
|
192
|
+
"""
|
193
|
+
server_info = await get_single_server_info(server_json, _id)
|
194
|
+
if server_info is None:
|
195
|
+
return None
|
196
|
+
|
197
|
+
host, port = server_info
|
198
|
+
out_msg = await draw_one_ip(host, port)
|
199
|
+
if is_img:
|
200
|
+
return cast(bytes, out_msg)
|
201
|
+
return out_msg
|
202
|
+
|
203
|
+
|
124
204
|
async def get_group_detail(
|
125
205
|
command: str,
|
126
206
|
):
|
@@ -1,56 +1,193 @@
|
|
1
1
|
import asyncio
|
2
2
|
|
3
3
|
# from logging import log
|
4
|
+
import io
|
5
|
+
from pathlib import Path
|
4
6
|
from typing import List, Tuple
|
5
7
|
|
8
|
+
from nonebot.log import logger
|
9
|
+
from PIL import Image, ImageDraw, ImageFont
|
10
|
+
|
6
11
|
from ..config import config
|
7
12
|
from ..utils.api.models import NserverOut, OutServer
|
8
13
|
from ..utils.api.request import L4API
|
9
14
|
|
10
15
|
|
11
|
-
async def draw_one_ip(host: str, port: int):
|
16
|
+
async def draw_one_ip(host: str, port: int, is_img: bool = config.l4_image):
|
12
17
|
"""输出单个ip"""
|
13
|
-
# 先用文字凑合
|
14
18
|
try:
|
15
19
|
ser_list = await L4API.a2s_info([(host, port)], is_player=True)
|
16
20
|
except asyncio.exceptions.TimeoutError:
|
17
21
|
return "服务器无响应"
|
18
|
-
player_msg = ""
|
19
22
|
one_server = ser_list[0][0]
|
20
23
|
one_player = ser_list[0][1]
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
25
|
+
async def format_player_info(players: list) -> str:
|
26
|
+
"""格式化玩家信息
|
27
|
+
Args:
|
28
|
+
players: 玩家对象列表
|
29
|
+
Returns:
|
30
|
+
格式化后的玩家信息字符串
|
31
|
+
"""
|
32
|
+
player_msg = ""
|
33
|
+
if len(players):
|
34
|
+
max_duration_len = max(
|
35
|
+
[len(str(await convert_duration(i.duration))) for i in players],
|
36
|
+
)
|
37
|
+
max_score_len = max(len(str(i.score)) for i in players)
|
38
|
+
|
39
|
+
for player in players:
|
40
|
+
soc = "[{:>{}}]".format(player.score, max_score_len)
|
41
|
+
chines_dur = await convert_duration(player.duration)
|
42
|
+
dur = "{:^{}}".format(chines_dur, max_duration_len)
|
43
|
+
name_leg = len(player.name)
|
44
|
+
if name_leg > 2:
|
45
|
+
xing = ":)" * (name_leg - 2)
|
46
|
+
name = f"{player.name[0]}{xing}{player.name[-1]}"
|
47
|
+
else:
|
48
|
+
name = player.name
|
49
|
+
player_msg += f"{soc} | {dur} | {name} \n"
|
50
|
+
else:
|
51
|
+
player_msg = "服务器感觉很安静啊"
|
52
|
+
return player_msg
|
53
|
+
|
54
|
+
def build_server_message(server, player_info: str) -> str:
|
55
|
+
"""构建服务器信息消息
|
56
|
+
Args:
|
57
|
+
server: 服务器对象
|
58
|
+
player_info: 格式化后的玩家信息字符串
|
59
|
+
Returns:
|
60
|
+
完整的服务器信息字符串
|
61
|
+
"""
|
62
|
+
msg = f"""-{server.server_name}-
|
63
|
+
游戏: {server.folder}
|
64
|
+
地图: {server.map_name}
|
65
|
+
人数: {server.player_count}/{server.max_players}"""
|
66
|
+
if server.ping is not None:
|
67
|
+
msg += f"""
|
68
|
+
ping: {server.ping * 1000:.0f}ms
|
69
|
+
{player_info}"""
|
70
|
+
if config.l4_show_ip:
|
71
|
+
msg += f"""
|
52
72
|
connect {host}:{port}"""
|
53
|
-
|
73
|
+
return msg
|
74
|
+
|
75
|
+
def draw_text_on_image(
|
76
|
+
text: str,
|
77
|
+
font: ImageFont.FreeTypeFont,
|
78
|
+
draw: ImageDraw.ImageDraw,
|
79
|
+
) -> Image.Image:
|
80
|
+
"""在图片上绘制文本
|
81
|
+
Args:
|
82
|
+
text: 要绘制的文本
|
83
|
+
font: PIL字体对象
|
84
|
+
draw: PIL绘图对象
|
85
|
+
Returns:
|
86
|
+
包含绘制文本的PIL图片对象
|
87
|
+
"""
|
88
|
+
try:
|
89
|
+
# 分割文本为标题行和内容行
|
90
|
+
lines = text.split("\n")
|
91
|
+
if not lines:
|
92
|
+
return Image.new("RGB", (600, 400), color=(73, 109, 137))
|
93
|
+
|
94
|
+
title = lines[0]
|
95
|
+
content = "\n".join(lines[1:]) if len(lines) > 1 else ""
|
96
|
+
|
97
|
+
# 计算各部分文字尺寸
|
98
|
+
title_bbox = font.getbbox(title)
|
99
|
+
title_width = title_bbox[2] - title_bbox[0]
|
100
|
+
title_height = title_bbox[3] - title_bbox[1]
|
101
|
+
|
102
|
+
content_width = 0
|
103
|
+
content_height = 0
|
104
|
+
if content:
|
105
|
+
content_lines = content.split("\n")
|
106
|
+
line_height = font.getbbox("A")[3] - font.getbbox("A")[1]
|
107
|
+
content_height = len(content_lines) * line_height
|
108
|
+
content_width = max(
|
109
|
+
font.getbbox(line)[2] - font.getbbox(line)[0]
|
110
|
+
for line in content_lines
|
111
|
+
)
|
112
|
+
|
113
|
+
# 计算图片尺寸
|
114
|
+
margin = 20
|
115
|
+
line_spacing = 5
|
116
|
+
img_width = max(title_width, content_width) + 2 * margin
|
117
|
+
content_lines_count = len(content.split("\n")) if content else 0
|
118
|
+
img_height = max(
|
119
|
+
title_height
|
120
|
+
+ content_height
|
121
|
+
+ (line_spacing + 1) * max(0, content_lines_count - 1)
|
122
|
+
+ 2 * margin,
|
123
|
+
300,
|
124
|
+
)
|
125
|
+
|
126
|
+
# 加载背景图片
|
127
|
+
bg_path = (
|
128
|
+
Path(__file__).parent.parent / "l4_image" / "img" / "anne" / "back.png"
|
129
|
+
)
|
130
|
+
try:
|
131
|
+
img = Image.open(bg_path)
|
132
|
+
# 调整背景图尺寸
|
133
|
+
img = img.resize((int(img_width), int(img_height)))
|
134
|
+
logger.info(f"图片像素大小: {img.width}x{img.height}")
|
135
|
+
draw = ImageDraw.Draw(img)
|
136
|
+
|
137
|
+
title_x = (img_width - title_width) // 2
|
138
|
+
title_y = margin
|
139
|
+
draw.text((title_x, title_y), title, font=font, fill=(255, 255, 255))
|
140
|
+
|
141
|
+
if content:
|
142
|
+
content_x = margin
|
143
|
+
content_y = title_y + title_height + margin
|
144
|
+
draw.text(
|
145
|
+
(content_x, content_y),
|
146
|
+
content,
|
147
|
+
font=font,
|
148
|
+
fill=(255, 255, 255),
|
149
|
+
spacing=line_spacing,
|
150
|
+
)
|
151
|
+
|
152
|
+
return img
|
153
|
+
except Exception as e:
|
154
|
+
logger.error(f"加载背景图片失败: {e}")
|
155
|
+
img = Image.new(
|
156
|
+
"RGB",
|
157
|
+
(int(img_width), int(img_height)),
|
158
|
+
color=(73, 109, 137),
|
159
|
+
)
|
160
|
+
draw = ImageDraw.Draw(img)
|
161
|
+
draw.text((title_x, title_y), title, font=font, fill=(255, 255, 255))
|
162
|
+
if content:
|
163
|
+
draw.text(
|
164
|
+
(content_x, content_y),
|
165
|
+
content,
|
166
|
+
font=font,
|
167
|
+
fill=(255, 255, 255),
|
168
|
+
spacing=line_spacing,
|
169
|
+
)
|
170
|
+
return img
|
171
|
+
except Exception as e:
|
172
|
+
logger.error(f"绘制图片时出错: {e}")
|
173
|
+
error_img = Image.new("RGB", (600, 400), color=(255, 0, 0))
|
174
|
+
error_draw = ImageDraw.Draw(error_img)
|
175
|
+
error_draw.text((10, 10), "图片生成失败", fill=(255, 255, 255))
|
176
|
+
return error_img
|
177
|
+
|
178
|
+
player_info = await format_player_info(one_player)
|
179
|
+
server_message = build_server_message(one_server, player_info)
|
180
|
+
|
181
|
+
if is_img:
|
182
|
+
# 加载字体
|
183
|
+
font_path = Path(__file__).parent.parent / "data" / "font" / "loli.ttf"
|
184
|
+
font = ImageFont.truetype(str(font_path), 18)
|
185
|
+
draw = ImageDraw.Draw(Image.new("RGB", (600, 400), color=(73, 109, 137)))
|
186
|
+
img = draw_text_on_image(server_message, font, draw)
|
187
|
+
img_byte_arr = io.BytesIO()
|
188
|
+
img.save(img_byte_arr, format="PNG")
|
189
|
+
return img_byte_arr.getvalue()
|
190
|
+
return server_message
|
54
191
|
|
55
192
|
|
56
193
|
async def get_much_server(server_json: List[NserverOut], command: str):
|
@@ -64,7 +201,7 @@ async def get_much_server(server_json: List[NserverOut], command: str):
|
|
64
201
|
for index, i in enumerate(all_server):
|
65
202
|
out_server.append(
|
66
203
|
{
|
67
|
-
"server": i[0],
|
204
|
+
"server": i[0], # type: ignore
|
68
205
|
"player": i[1],
|
69
206
|
"host": server_json[index]["host"],
|
70
207
|
"port": server_json[index]["port"],
|
@@ -3,7 +3,7 @@ import contextlib
|
|
3
3
|
import socket
|
4
4
|
from copy import deepcopy
|
5
5
|
from pathlib import Path
|
6
|
-
from typing import Any, Dict, List, Literal, Optional, Tuple, cast
|
6
|
+
from typing import Any, Dict, List, Literal, Optional, Tuple, Union, cast
|
7
7
|
|
8
8
|
import a2s
|
9
9
|
import aiofiles
|
@@ -47,8 +47,12 @@ class L4D2Api:
|
|
47
47
|
ip_list: List[Tuple[str, int]],
|
48
48
|
is_server: bool = True,
|
49
49
|
is_player: bool = False,
|
50
|
-
) -> List[
|
51
|
-
|
50
|
+
) -> List[
|
51
|
+
Tuple[Union[a2s.SourceInfo[str], a2s.GoldSrcInfo[str]], List[a2s.Player]]
|
52
|
+
]:
|
53
|
+
msg_list: List[
|
54
|
+
Tuple[Union[a2s.SourceInfo[str], a2s.GoldSrcInfo[str]], List[a2s.Player]]
|
55
|
+
] = []
|
52
56
|
sorted_msg_list = []
|
53
57
|
tasks = [] # 用来保存异步任务
|
54
58
|
if ip_list != []:
|
@@ -80,19 +84,24 @@ class L4D2Api:
|
|
80
84
|
is_player: bool,
|
81
85
|
):
|
82
86
|
play: List[a2s.Player] = []
|
87
|
+
server: Union[a2s.SourceInfo, a2s.GoldSrcInfo]
|
83
88
|
if is_server:
|
84
89
|
try:
|
85
|
-
server
|
90
|
+
server = await a2s.ainfo(
|
91
|
+
ip,
|
92
|
+
timeout=3,
|
93
|
+
encoding="utf8",
|
94
|
+
)
|
86
95
|
|
87
96
|
if server is not None:
|
88
|
-
server.steam_id = index
|
97
|
+
server.steam_id = index # type: ignore
|
89
98
|
|
90
99
|
except (
|
91
100
|
asyncio.exceptions.TimeoutError,
|
92
101
|
ConnectionRefusedError,
|
93
102
|
socket.gaierror,
|
94
103
|
):
|
95
|
-
server
|
104
|
+
server = a2s.SourceInfo(
|
96
105
|
protocol=0,
|
97
106
|
server_name="服务器无响应",
|
98
107
|
map_name="无",
|
@@ -137,7 +146,7 @@ class L4D2Api:
|
|
137
146
|
json: Optional[Dict[str, Any]] = None,
|
138
147
|
data: Optional[Dict[str, Any]] = None,
|
139
148
|
is_json: bool = True,
|
140
|
-
):
|
149
|
+
) -> Union[Dict[str, Any], BeautifulSoup]: # type: ignore
|
141
150
|
header = deepcopy(self._HEADER)
|
142
151
|
|
143
152
|
if json is not None:
|
@@ -181,7 +190,17 @@ class L4D2Api:
|
|
181
190
|
return BeautifulSoup(html_content, "lxml")
|
182
191
|
|
183
192
|
async def get_sourceban(self, tag: str = "云", url: str = anne_ban):
|
184
|
-
"""
|
193
|
+
"""
|
194
|
+
异步函数,从sourceban++获取服务器列表,目前未做名称处理。
|
195
|
+
|
196
|
+
Args:
|
197
|
+
tag (str): 用于标识不同来源的标签,默认为"云"。
|
198
|
+
url (str): SourceBan的URL,默认为anne_ban。
|
199
|
+
|
200
|
+
Returns:
|
201
|
+
list: 包含服务器信息的列表。
|
202
|
+
|
203
|
+
"""
|
185
204
|
if not (url.startswith(("http://", "https://"))):
|
186
205
|
url = "http://" + url # 默认添加 http://
|
187
206
|
soup = await self._server_request(
|
@@ -272,14 +291,14 @@ class L4D2Api:
|
|
272
291
|
if not isinstance(soup, BeautifulSoup):
|
273
292
|
return None
|
274
293
|
|
275
|
-
tbody = soup.find(
|
294
|
+
tbody = cast(BeautifulSoup, soup).find(
|
276
295
|
"div",
|
277
296
|
class_="content text-center text-md-left",
|
278
297
|
style="background-color: #f2f2f2;",
|
279
298
|
)
|
280
299
|
if tbody is None:
|
281
300
|
return None
|
282
|
-
kill_tag = tbody.find(
|
301
|
+
kill_tag = cast(BeautifulSoup, tbody).find(
|
283
302
|
"div",
|
284
303
|
class_="card-body worldmap d-flex flex-column justify-content-center text-center",
|
285
304
|
)
|
@@ -7,6 +7,7 @@ from typing import Any, Dict, List, Optional, Tuple
|
|
7
7
|
import aiofiles
|
8
8
|
import aiohttp
|
9
9
|
import nonebot
|
10
|
+
from aiohttp import ClientTimeout
|
10
11
|
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent
|
11
12
|
from nonebot.log import logger
|
12
13
|
from nonebot_plugin_alconna import UniMessage
|
@@ -184,7 +185,11 @@ async def url_to_byte(url: str):
|
|
184
185
|
"""获取URL数据的字节流"""
|
185
186
|
|
186
187
|
async with aiohttp.ClientSession() as session:
|
187
|
-
async with session.get(
|
188
|
+
async with session.get(
|
189
|
+
url,
|
190
|
+
headers=headers,
|
191
|
+
timeout=ClientTimeout(total=600),
|
192
|
+
) as response:
|
188
193
|
if response.status == 200:
|
189
194
|
return await response.read()
|
190
195
|
return None
|
@@ -194,7 +199,11 @@ async def url_to_msg(url: str):
|
|
194
199
|
"""获取URL数据的字节流"""
|
195
200
|
|
196
201
|
async with aiohttp.ClientSession() as session:
|
197
|
-
async with session.get(
|
202
|
+
async with session.get(
|
203
|
+
url,
|
204
|
+
headers=headers,
|
205
|
+
timeout=ClientTimeout(total=600),
|
206
|
+
) as response:
|
198
207
|
if response.status == 200:
|
199
208
|
return await response.text()
|
200
209
|
return None
|
{nonebot_plugin_l4d2_server-1.0.3.dist-info → nonebot_plugin_l4d2_server-1.0.4.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: nonebot-plugin-l4d2-server
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.4
|
4
4
|
Summary: L4D2 server related operations plugin for NoneBot2
|
5
5
|
Keywords: steam,game,l4d2,nonebot2,plugin
|
6
6
|
Author-Email: Agnes_Digital <Z735803792@163.com>
|
@@ -32,7 +32,7 @@ Requires-Dist: ujson>=5.10.0
|
|
32
32
|
Requires-Dist: lxml>=5.2.2
|
33
33
|
Requires-Dist: rcon>=2.1.0
|
34
34
|
Requires-Dist: pillow>10
|
35
|
-
Requires-Dist:
|
35
|
+
Requires-Dist: bs4>=0.0.2
|
36
36
|
Requires-Dist: rarfile>=4.2
|
37
37
|
Requires-Dist: pyunpack>=0.3
|
38
38
|
Requires-Dist: aiofiles>=24.1.0
|
@@ -47,7 +47,7 @@ Description-Content-Type: text/markdown
|
|
47
47
|
|
48
48
|
<div align="center">
|
49
49
|
|
50
|
-
# nonebot_plugin_l4d2_server 1.0.
|
50
|
+
# nonebot_plugin_l4d2_server 1.0.4
|
51
51
|
|
52
52
|
_✨Nonebot & Left 4 Dead 2 server操作✨_
|
53
53
|
<div align = "center">
|
@@ -77,15 +77,12 @@ _✨Nonebot & Left 4 Dead 2 server操作✨_
|
|
77
77
|
|
78
78
|
## 顶置公告(如果以前用0.x.x版本暂时别更新)
|
79
79
|
|
80
|
-
- **版本** 1.x.x
|
80
|
+
- **版本** 1.x.x进行了破坏式更新,使用旧插件的不要更新
|
81
81
|
|
82
|
-
##
|
82
|
+
## 指令
|
83
83
|
|
84
|
-
-
|
85
|
-
-
|
86
|
-
- 取消了git拉取更新(nb规范用pypi)
|
87
|
-
- 增加pil和浏览器渲染做选择(可以选择pil以节省性能性能)
|
88
|
-
- 删除无用部分(依赖太多难以维护)
|
84
|
+
- 在json文件设置的前缀指令,例如设置"云",则指令 云 输出组服务器,云1 输出1号服务器
|
85
|
+
- l4图片开启/关闭 超管指令 可以修改输出单图是否为图片输出
|
89
86
|
|
90
87
|
## 安装
|
91
88
|
|
@@ -142,8 +139,7 @@ conda install nonebot-plugin-l4d2-server
|
|
142
139
|
## 主要功能
|
143
140
|
|
144
141
|
- [ ] 求生服务器-本地多路径操作(传地图等)
|
145
|
-
- [
|
146
|
-
- [ ] [求生电信服anne](https://github.com/fantasylidong/CompetitiveWithAnne)[查询~](https://sb.trygek.com/l4d_stats/ranking/index.php)
|
142
|
+
- [x] 批量查询指定ip服务器状态和玩家
|
147
143
|
|
148
144
|
## [数据结构](./docs/standand.md)
|
149
145
|
|
@@ -152,8 +148,6 @@ conda install nonebot-plugin-l4d2-server
|
|
152
148
|
## env设置
|
153
149
|
|
154
150
|
"""bash
|
155
|
-
l4_anne = False
|
156
|
-
"""是否启用anne电信服相关功能"""
|
157
151
|
l4_enable = True
|
158
152
|
"""是否全局启用求生功能"""
|
159
153
|
l4_image = False
|
@@ -172,6 +166,15 @@ conda install nonebot-plugin-l4d2-server
|
|
172
166
|
- 缤纷彩虹
|
173
167
|
"""
|
174
168
|
|
169
|
+
## 和0.x.x更改部分
|
170
|
+
|
171
|
+
- 取消了网页控制台(没有卵用)
|
172
|
+
- 取消了自动重启(与其他插件功能重复)
|
173
|
+
- 取消了git拉取更新(nb规范用pypi)
|
174
|
+
- 增加pil和浏览器渲染做选择(可以选择pil以节省性能性能)
|
175
|
+
- 删除无用部分(依赖太多难以维护)
|
176
|
+
- 删除了anne部分,已移植到[这里](https://github.com/Agnes4m/L4D2UID),通过core插件调用
|
177
|
+
|
175
178
|
## 其他
|
176
179
|
|
177
180
|
- 本人技术很差,如果您有发现BUG或者更好的建议,欢迎提Issue & Pr
|
{nonebot_plugin_l4d2_server-1.0.3.dist-info → nonebot_plugin_l4d2_server-1.0.4.dist-info}/RECORD
RENAMED
@@ -1,15 +1,13 @@
|
|
1
|
-
nonebot_plugin_l4d2_server-1.0.
|
2
|
-
nonebot_plugin_l4d2_server-1.0.
|
3
|
-
nonebot_plugin_l4d2_server-1.0.
|
4
|
-
nonebot_plugin_l4d2_server-1.0.
|
1
|
+
nonebot_plugin_l4d2_server-1.0.4.dist-info/METADATA,sha256=kZdrFtRaRtfYjXvIapyyUJnulUxQPjtbzRAOHAVyBkA,6763
|
2
|
+
nonebot_plugin_l4d2_server-1.0.4.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
|
3
|
+
nonebot_plugin_l4d2_server-1.0.4.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
|
4
|
+
nonebot_plugin_l4d2_server-1.0.4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
5
5
|
nonebot_plugin_l4d2_server/__init__.py,sha256=PIufOk1bxOx-nYqdoinoB7BcntIETNFwfzqKnmu-teE,1624
|
6
|
-
nonebot_plugin_l4d2_server/__main__.py,sha256=
|
7
|
-
nonebot_plugin_l4d2_server/config.py,sha256=
|
6
|
+
nonebot_plugin_l4d2_server/__main__.py,sha256=Z8laU36rLdNq-Qfroj-1t6dbt4rfKLetvJ1cY937oGo,10232
|
7
|
+
nonebot_plugin_l4d2_server/config.py,sha256=_UKAn1g5BbykMNc6LXRujKoGhpxIM5JAdh3z301BLHk,2665
|
8
8
|
nonebot_plugin_l4d2_server/data/font/loli.ttf,sha256=Yrh-RPoCrn1-NG94DR0x20ASXYUt8g3Ep6BCt3CdOFk,11125812
|
9
|
-
nonebot_plugin_l4d2_server/l4_anne/__init__.py,sha256=zX4kTu4LAsqm7_li0-GcihnbYI65SBPkfUCPTs79U8k,4124
|
10
|
-
nonebot_plugin_l4d2_server/l4_anne/ranne.py,sha256=vtNQJ-74rJiwVI3IYS3ZgFk_LaCviKU1yxrGk3DFvQs,532
|
11
9
|
nonebot_plugin_l4d2_server/l4_help/Help.json,sha256=hz_k-qmGmGJKwCa8wmkHTLzXu6C-G-E_g7xdK-t6fNk,2673
|
12
|
-
nonebot_plugin_l4d2_server/l4_help/__init__.py,sha256=
|
10
|
+
nonebot_plugin_l4d2_server/l4_help/__init__.py,sha256=sZRp6HJE2hvEcSST7CXJk8eAyv6rj4kLIcOK_7xUTI0,1535
|
13
11
|
nonebot_plugin_l4d2_server/l4_help/draw.py,sha256=y6yDPUnoZFvwly8cf7g9HRpT1JXTxyA9DC1TuvUinTM,6448
|
14
12
|
nonebot_plugin_l4d2_server/l4_help/icon/介绍.png,sha256=3QC6A38QC-7gDBxmtQSQdbsz7hsefU5LL-oZmJ41zTk,3806
|
15
13
|
nonebot_plugin_l4d2_server/l4_help/icon/任务.png,sha256=nyZ4_kM21ZO95nwanCFnUfCGX-PkmJXYQf9OrJVKomY,3782
|
@@ -88,12 +86,12 @@ nonebot_plugin_l4d2_server/l4_image/model.py,sha256=FGsCvf_BKbRNJUVy6I5BKnArMY-3
|
|
88
86
|
nonebot_plugin_l4d2_server/l4_image/vtfs.py,sha256=He_7zzEIOip8MXP55TS7aWPbzo6ac0wPf602nN3GWZM,1461
|
89
87
|
nonebot_plugin_l4d2_server/l4_local/__init__.py,sha256=nz9KUxmuvRrryHakQQ4B30oC9jeGWZ3sON1tCKb-lS0,3603
|
90
88
|
nonebot_plugin_l4d2_server/l4_local/file.py,sha256=hew1Y8kV3uSZvUGplmi09EGKC89-sUJWsWV7SCEstI8,3067
|
91
|
-
nonebot_plugin_l4d2_server/l4_request/__init__.py,sha256=
|
92
|
-
nonebot_plugin_l4d2_server/l4_request/draw_msg.py,sha256=
|
89
|
+
nonebot_plugin_l4d2_server/l4_request/__init__.py,sha256=9Yo6mQ_bIBvMwQubC3Ctie6H2Qzx7ScwCQyVS9y25TE,11682
|
90
|
+
nonebot_plugin_l4d2_server/l4_request/draw_msg.py,sha256=koAVWrsDoLCTmwXY-NJTi5yjL1y1ND3daFkDWccQjcU,8071
|
93
91
|
nonebot_plugin_l4d2_server/l4_request/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
94
92
|
nonebot_plugin_l4d2_server/utils/api/api.py,sha256=auvDicCEKwvnm6EJYeCxCtugFby61K-zAmmaRWWEwtM,296
|
95
|
-
nonebot_plugin_l4d2_server/utils/api/models.py,sha256=
|
96
|
-
nonebot_plugin_l4d2_server/utils/api/request.py,sha256=
|
93
|
+
nonebot_plugin_l4d2_server/utils/api/models.py,sha256=p-hoxPHwadTaMRb2hqwfbaQ3pvJySrV8VbBmhA0Oi-M,2391
|
94
|
+
nonebot_plugin_l4d2_server/utils/api/request.py,sha256=aAsXtxvm7erXLfFCbs6NmsZCRGpsg3tsMdWvSn8SkNU,15575
|
97
95
|
nonebot_plugin_l4d2_server/utils/database/models.py,sha256=SLdcgwsn39r_ZkcBoqf4MLX1EfpCOjGBwWcR16u9Bqo,454
|
98
|
-
nonebot_plugin_l4d2_server/utils/utils.py,sha256=
|
99
|
-
nonebot_plugin_l4d2_server-1.0.
|
96
|
+
nonebot_plugin_l4d2_server/utils/utils.py,sha256=TD3cUCxmmj2GPmK1sQwP7NtkIXNO2FpuXjymaUqBDYo,6141
|
97
|
+
nonebot_plugin_l4d2_server-1.0.4.dist-info/RECORD,,
|
@@ -1,125 +0,0 @@
|
|
1
|
-
from nonebot import log as log
|
2
|
-
from nonebot import on_command
|
3
|
-
from nonebot.adapters import Event, Message
|
4
|
-
from nonebot.log import logger
|
5
|
-
from nonebot.params import CommandArg
|
6
|
-
from nonebot_plugin_alconna import UniMessage
|
7
|
-
|
8
|
-
from ..utils.api.request import L4API
|
9
|
-
from ..utils.database.models import SteamUser
|
10
|
-
from ..utils.utils import get_message_at
|
11
|
-
from .ranne import get_anne_rank_out
|
12
|
-
|
13
|
-
anne_bind = on_command("Banne", aliases={"l4绑定", "anne绑定"}, priority=5, block=True)
|
14
|
-
anne_search = on_command("Sanne", aliases={"anne搜索"})
|
15
|
-
anne_rank = on_command("Ranne", aliases={"anne成绩"}, block=True, priority=1)
|
16
|
-
|
17
|
-
anne_del = on_command(
|
18
|
-
"Danne",
|
19
|
-
aliases={"l4删除", "anne删除", "l4解绑", "anne解绑"},
|
20
|
-
priority=5,
|
21
|
-
block=True,
|
22
|
-
)
|
23
|
-
|
24
|
-
|
25
|
-
@anne_search.handle()
|
26
|
-
async def _(args: Message = CommandArg()):
|
27
|
-
name: str = args.extract_plain_text().strip()
|
28
|
-
print(name)
|
29
|
-
user_list = await L4API.get_anne_steamid(name)
|
30
|
-
if user_list is None:
|
31
|
-
await UniMessage.text("未找到玩家").finish()
|
32
|
-
msg = f"---有{len(user_list)}个玩家---"
|
33
|
-
for index, user in enumerate(user_list, start=1):
|
34
|
-
if index >= 10:
|
35
|
-
break
|
36
|
-
msg += f"""
|
37
|
-
{index}. {user["name"]} | [{user["score"]}] | {user["play_time"]}
|
38
|
-
{user["steamid"]}
|
39
|
-
"""
|
40
|
-
if msg:
|
41
|
-
await UniMessage.text("\n".join(msg.splitlines())).finish()
|
42
|
-
else:
|
43
|
-
await UniMessage.text("没有找到玩家").finish()
|
44
|
-
|
45
|
-
|
46
|
-
@anne_bind.handle()
|
47
|
-
async def _(ev: Event, args: Message = CommandArg()):
|
48
|
-
arg: str = args.extract_plain_text()
|
49
|
-
if not arg:
|
50
|
-
await UniMessage.text("虚空绑定?").finish()
|
51
|
-
|
52
|
-
user = await SteamUser.get_or_none(userid=int(ev.get_user_id()))
|
53
|
-
if user is None:
|
54
|
-
user = await SteamUser.create(userid=int(ev.get_user_id()))
|
55
|
-
|
56
|
-
if len(arg) == 17:
|
57
|
-
# steamid64
|
58
|
-
logger.info(f"SteamID64:{arg}")
|
59
|
-
user.SteamID64 = arg
|
60
|
-
msg = "绑定steamid64"
|
61
|
-
|
62
|
-
elif arg.startswith("STEAM_"):
|
63
|
-
# steamid
|
64
|
-
logger.info(f"SteamID:{arg}")
|
65
|
-
user.SteamID = arg
|
66
|
-
msg = "绑定steamid"
|
67
|
-
|
68
|
-
else:
|
69
|
-
# name
|
70
|
-
logger.info(f"Name:{arg}")
|
71
|
-
user.Name = arg
|
72
|
-
msg = "绑定名字"
|
73
|
-
await user.save()
|
74
|
-
|
75
|
-
return await UniMessage.text(f"{msg}成功").finish()
|
76
|
-
|
77
|
-
|
78
|
-
@anne_del.handle()
|
79
|
-
async def _(ev: Event):
|
80
|
-
if record := await SteamUser.get_or_none(userid=int(ev.get_user_id())):
|
81
|
-
logger.info(f"删除用户:{record}")
|
82
|
-
await record.delete()
|
83
|
-
await record.save()
|
84
|
-
return await UniMessage.text("删除成功").finish()
|
85
|
-
return await UniMessage.text("没有绑定信息呢").finish()
|
86
|
-
|
87
|
-
|
88
|
-
@anne_rank.handle()
|
89
|
-
async def _(ev: Event, args: Message = CommandArg()):
|
90
|
-
uid = await get_message_at(str(ev.json()))
|
91
|
-
if uid is None:
|
92
|
-
uid = int(int(ev.get_user_id()))
|
93
|
-
steamid = ""
|
94
|
-
arg: str = args.extract_plain_text().strip()
|
95
|
-
logger.info(f"arg:{arg}")
|
96
|
-
# 优先从数据库查询
|
97
|
-
if not arg:
|
98
|
-
msg = await SteamUser.get_or_none(userid=uid)
|
99
|
-
if msg is not None:
|
100
|
-
steamid = msg.SteamID
|
101
|
-
if not steamid:
|
102
|
-
name = msg.Name
|
103
|
-
if not name:
|
104
|
-
await UniMessage.text("未绑定名字/steamid").finish()
|
105
|
-
msg_dict = await L4API.get_anne_steamid(name)
|
106
|
-
if not msg_dict:
|
107
|
-
await UniMessage.text("绑定的昵称找不到呢").finish()
|
108
|
-
steamid = msg_dict[0]["steamid"]
|
109
|
-
logger.info(f"steamid:{steamid}")
|
110
|
-
|
111
|
-
# 再从arg中查找
|
112
|
-
else:
|
113
|
-
if arg.startswith("STEAM_"):
|
114
|
-
steamid = arg
|
115
|
-
else:
|
116
|
-
arg_dict = await L4API.get_anne_steamid(arg)
|
117
|
-
if not arg_dict:
|
118
|
-
await UniMessage.text("未找到该昵称玩家").finish()
|
119
|
-
steamid = arg_dict[0]["steamid"]
|
120
|
-
if not steamid:
|
121
|
-
await UniMessage.text("未找到玩家,请使用指令`l4搜索`查找").finish()
|
122
|
-
out_msg = await get_anne_rank_out(steamid)
|
123
|
-
if out_msg is None:
|
124
|
-
await UniMessage.text("未找到玩家").finish()
|
125
|
-
await UniMessage.text(out_msg).finish()
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# coding=utf-8
|
2
|
-
# anne战绩查询
|
3
|
-
from ..utils.api.request import L4API
|
4
|
-
|
5
|
-
|
6
|
-
async def get_anne_rank_out(steamid: str):
|
7
|
-
msg = await L4API.get_anne_playerdetail(steamid)
|
8
|
-
if msg is None:
|
9
|
-
return None
|
10
|
-
return f"""电信anne查询结果:
|
11
|
-
昵称:{msg['info']['name']}
|
12
|
-
排名:{msg['detail']['rank']}
|
13
|
-
分数:{msg['detail']["source"]}
|
14
|
-
击杀:{msg['detail']["kills"]}
|
15
|
-
爆头率:{msg['detail']["avg_source"]}
|
16
|
-
时间:{msg['info']['playtime']}
|
17
|
-
上次:{msg['info']['lasttime']}
|
18
|
-
"""
|
{nonebot_plugin_l4d2_server-1.0.3.dist-info → nonebot_plugin_l4d2_server-1.0.4.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
File without changes
|