Files
HeXi/hexi/plugins/nonebot_plugin_helldivers_tools/__init__.py
T

204 lines
6.8 KiB
Python
Raw Normal View History

import httpx
from nonebot import logger
from nonebot.internal.params import ArgPlainText
from nonebot.typing import T_State
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent, Bot, MessageSegment
from nonebot.plugin import PluginMetadata
from typing import Optional, Union
from .equipment import get_random_equipment, get_equipment_by_combination
from .hd2_api import get_briefing_data
from .war_renderer import render_war_briefing
from .utils import *
from .equipment_store import init_db as _init_equipment_db
from . import stratagem_admin as _stratagem_admin
from hexi.web_plugin_registry import register_web_plugin
from nonebot.matcher import Matcher
__plugin_meta__ = PluginMetadata(
name="绝地潜兵小助手",
description="绝地潜兵小助手,提供一些小功能,让超级地球更加美好!",
usage="简报:获取星系战争简要概况(每个阵营取人数前 4 张卡片)\n"
"详报:全量绘制当前进行的战役\n"
"随机战备:让机器人帮你随机一套战备\n"
"战备管理后台:/hub/ 统一管理台内可视化编辑",
type="application",
homepage="https://github.com/sansenhoshi/nonebot_plugin_helldivers_tools"
)
basic_path = os.path.dirname(__file__)
save_path = os.path.join(basic_path, "temp")
img_path = os.path.join(basic_path, "img")
data_path = os.path.join(basic_path, "data")
# 注册到统一 Web:hub 启动时会自动挂载 /api/helldivers,无需手动配置
_init_equipment_db()
register_web_plugin(
"helldivers",
"战备管理",
"rocket",
lambda: _stratagem_admin.build_admin_app(),
module_name=__name__,
)
logger.info("战备管理 Web 插件已注册(/api/helldivers)")
# 统一配置标准:把 API 相关配置暴露给 Web 管理台(/hub 插件配置)
from hexi.config_standard import register_model_config # noqa: E402
from .config import config as _hd2_config # noqa: E402
register_model_config(
__name__,
_hd2_config,
fields=[
"hd2_api_base_url",
"hd2_api_language",
"hd2_cache_ttl",
"hd2_super_client",
"hd2_super_contact",
],
labels={
"hd2_api_base_url": "API 根地址",
"hd2_api_language": "本地化语言",
"hd2_cache_ttl": "数据缓存秒数",
"hd2_super_client": "请求头 Client",
"hd2_super_contact": "请求头 Contact",
},
descriptions={
"hd2_api_base_url": "自托管 helldivers-2/api 根地址;不填则用公共社区 API",
"hd2_api_language": "请求本地化语言,自托管实例支持 zh-Hans/zh-Hant",
"hd2_cache_ttl": "战况快照约几分钟更新一次,靠这个避免频繁打接口触发限流",
"hd2_super_client": "公共/自托管都要求 X-Super-Client 头",
"hd2_super_contact": "公共/自托管都要求 X-Super-Contact 头",
},
)
async def _send_war_card(matcher: Matcher, ev: MessageEvent, top_per_race: Optional[int]) -> None:
await matcher.send("正在获取前线战况,请民主的等待!")
try:
data = await get_briefing_data()
png = await render_war_briefing(data, top_per_race)
except Exception as e:
logger.exception("获取战况失败")
await matcher.finish(
MessageSegment.reply(ev.message_id)
+ f"战况获取失败:{type(e).__name__}:{e}"
)
return
mes = (MessageSegment.reply(ev.message_id), gen_ms_img(png))
await matcher.send(mes)
war_situation = on_command("简报", aliases={"简报"})
war_detail = on_command("详报", aliases={"详报"})
@war_situation.handle()
async def get_war_info(ev: MessageEvent):
await _send_war_card(war_situation, ev, top_per_race=4)
@war_detail.handle()
async def get_war_detail(ev: MessageEvent):
await _send_war_card(war_detail, ev, top_per_race=None)
async def download_url(url: str) -> bytes | None:
async with httpx.AsyncClient() as client:
for i in range(3):
try:
resp = await client.get(url)
if resp.status_code != 200:
continue
return resp.content
except Exception as e:
print(f"Error downloading {url}, retry {i}/3: {str(e)}")
return None
random_helldivers = on_command("随机战备", aliases={"随机战备"}, block=True)
# PROMPT = """ ***超级地球武装部***
# 请发送你需要的随机规则
#
# 1:纯随机(不推荐)
#
# 套路随机(按一定规则随机)
#
# 2:2红/1蓝/1绿
# 3:2绿/1红/1蓝
# 4:2蓝/1绿/1红
#
# 5:3红/1蓝
# 6:3绿/1蓝
#
# 7:2红/2蓝
# 8:2蓝/2绿
# 9:2绿/2红
#
# 10:4红
# 11:4绿"""
board_path = f"{img_path}/board2.png"
PROMPT = MessageSegment.image(pic2b64(Image.open(board_path)))
error_count = 0
# 用户选择
@random_helldivers.got("pick_type", prompt=PROMPT)
async def got_random_helldivers(event: MessageEvent, pick_type: str = ArgPlainText()):
global error_count
if error_count >= 2:
await random_helldivers.finish("已回归平民生活——")
logger.info("持续输错退出随机战备")
error_count = 0
return
logger.info(f"用户选择的战备类型: {pick_type}")
if not is_number(pick_type):
error_count += 1
await random_helldivers.reject(f"您输入的 {pick_type} 非数字,请重新输入1到11,或者输入0退出")
elif int(pick_type) not in range(12):
error_count += 1
await random_helldivers.reject(f"您输入的 {pick_type} 不在范围内,请重新输入1到11,或者输入0退出")
elif int(pick_type) == 0:
await random_helldivers.finish("已回归平民生活——")
logger.info("用户选择退出随机战备")
error_count = 0
return
mix_msg = (MessageSegment.reply(event.message_id),)
type_combinations = {
2: {'red': 2, 'blue': 1, 'green': 1},
3: {'green': 2, 'red': 1, 'blue': 1},
4: {'blue': 2, 'green': 1, 'red': 1},
5: {'red': 3, 'blue': 1},
6: {'green': 3, 'blue': 1},
7: {'red': 2, 'blue': 2},
8: {'blue': 2, 'green': 2},
9: {'green': 2, 'red': 2},
10: {'red': 4},
11: {'green': 4}
}
if int(pick_type) == 1:
logger.info("用户选择纯随机战备")
result = await get_random_equipment(4) # 4 random equipments
else:
combination = type_combinations.get(int(pick_type))
logger.info(f"用户选择的战备组合: {combination}")
result = await get_equipment_by_combination(combination)
final_msg = MessageSegment.text("您的随机结果是:\n")
image_tuple = gen_ms_img(result)
mix_msg += (final_msg, image_tuple)
await random_helldivers.finish(mix_msg)
def is_number(s):
return bool(re.match(r'^[0-9]+$', s))