mirror of
https://github.com/PaiGramTeam/MibooGram.git
synced 2024-11-27 18:31:25 +00:00
313 lines
12 KiB
Python
313 lines
12 KiB
Python
import math
|
|
from typing import TYPE_CHECKING, List, Tuple, Optional, Union
|
|
|
|
from simnet.models.zzz.calculator import ZZZCalculatorCharacterDetails, ZZZCalculatorAvatarProperty
|
|
from telegram import (
|
|
InlineKeyboardButton,
|
|
InlineKeyboardMarkup,
|
|
)
|
|
from telegram.constants import ChatAction
|
|
from telegram.ext import filters
|
|
|
|
from core.config import config
|
|
from core.dependence.redisdb import RedisDB
|
|
from core.plugin import Plugin, handler
|
|
from core.services.template.services import TemplateService
|
|
from metadata.shortname import roleToName, idToRole
|
|
from plugins.tools.genshin import GenshinHelper
|
|
from plugins.tools.player_detail import PlayerDetailHelper, NeedClient
|
|
from utils.log import logger
|
|
from utils.uid import mask_number
|
|
|
|
if TYPE_CHECKING:
|
|
from simnet import ZZZClient
|
|
from telegram import Update
|
|
from telegram.ext import ContextTypes
|
|
from core.services.template.models import RenderResult
|
|
|
|
__all__ = ("AgentDetailPlugin",)
|
|
|
|
|
|
class ZZZCalculatorAvatarPropertyModify(ZZZCalculatorAvatarProperty):
|
|
|
|
@property
|
|
def icon(self) -> str:
|
|
return {
|
|
"生命值": "hp",
|
|
"攻击力": "atk",
|
|
"防御力": "def",
|
|
"冲击力": "impact",
|
|
"暴击率": "crit-rate",
|
|
"暴击伤害": "crit-dmg",
|
|
"异常掌控": "anomaly-proficiency",
|
|
"异常精通": "anomaly-mastery",
|
|
"穿透率": "pen-ratio",
|
|
"能量自动回复": "energy-regen",
|
|
}.get(self.property_name, "")
|
|
|
|
|
|
color_map = {
|
|
"1011": "#c8e16c",
|
|
"1021": "#a0351c",
|
|
"1031": "#e6adaa",
|
|
"1041": "#febb2e",
|
|
"1061": "#c8d7bd",
|
|
"1081": "#af3e3a",
|
|
"1101": "#de643d",
|
|
"1111": "#ddc374",
|
|
"1121": "#a68d73",
|
|
"1131": "#28bdcc",
|
|
"1141": "#d0d3e0",
|
|
"1151": "#e8cda2",
|
|
"1181": "#b75339",
|
|
"1191": "#c9becc",
|
|
"1211": "#c4c1b1",
|
|
"1241": "#4e7ebd",
|
|
"1281": "#e9d892",
|
|
}
|
|
|
|
|
|
class AgentDetailPlugin(Plugin):
|
|
"""角色详细信息查询"""
|
|
|
|
def __init__(
|
|
self,
|
|
helper: GenshinHelper,
|
|
template_service: TemplateService,
|
|
redis: RedisDB,
|
|
):
|
|
self.template_service = template_service
|
|
self.helper = helper
|
|
self.qname = "plugins:agent_detail"
|
|
self.redis = redis.client
|
|
self.expire = 15 * 60 # 15分钟
|
|
self.kitsune: Optional[str] = None
|
|
self.player_detail_helper = PlayerDetailHelper(helper, redis)
|
|
|
|
async def get_characters(
|
|
self, uid: int, client: "ZZZClient" = None
|
|
) -> Tuple[Optional[str], Optional["ZZZCalculatorCharacterDetails"]]:
|
|
return await self.player_detail_helper.get_characters(uid, client)
|
|
|
|
def parse_render_data(self, data: "ZZZCalculatorCharacterDetails", nickname: str, ch_id: int, uid: int):
|
|
char = None
|
|
for i in data.characters:
|
|
if i.id == ch_id:
|
|
char = i
|
|
break
|
|
props = [ZZZCalculatorAvatarPropertyModify(**i.dict()) for i in char.properties]
|
|
return {
|
|
"uid": mask_number(uid),
|
|
"char": char,
|
|
"props": props,
|
|
"color": color_map.get(str(char.id), "#010101"),
|
|
}
|
|
|
|
@staticmethod
|
|
def gen_button(
|
|
data: "ZZZCalculatorCharacterDetails",
|
|
user_id: Union[str, int],
|
|
uid: int,
|
|
page: int = 1,
|
|
) -> List[List[InlineKeyboardButton]]:
|
|
"""生成按钮"""
|
|
buttons = []
|
|
|
|
if data.characters:
|
|
buttons = [
|
|
InlineKeyboardButton(
|
|
idToRole(value.id),
|
|
callback_data=f"get_role_detail|{user_id}|{uid}|{idToRole(value.id)}",
|
|
)
|
|
for value in data.characters
|
|
if value.id
|
|
]
|
|
all_buttons = [buttons[i : i + 4] for i in range(0, len(buttons), 4)]
|
|
send_buttons = all_buttons[(page - 1) * 3 : page * 3]
|
|
last_page = page - 1 if page > 1 else 0
|
|
all_page = math.ceil(len(all_buttons) / 3)
|
|
next_page = page + 1 if page < all_page and all_page > 1 else 0
|
|
last_button = []
|
|
if last_page:
|
|
last_button.append(
|
|
InlineKeyboardButton(
|
|
"<< 上一页",
|
|
callback_data=f"get_role_detail|{user_id}|{uid}|{last_page}",
|
|
)
|
|
)
|
|
if last_page or next_page:
|
|
last_button.append(
|
|
InlineKeyboardButton(
|
|
f"{page}/{all_page}",
|
|
callback_data=f"get_role_detail|{user_id}|{uid}|empty_data",
|
|
)
|
|
)
|
|
if next_page:
|
|
last_button.append(
|
|
InlineKeyboardButton(
|
|
"下一页 >>",
|
|
callback_data=f"get_role_detail|{user_id}|{uid}|{next_page}",
|
|
)
|
|
)
|
|
if last_button:
|
|
send_buttons.append(last_button)
|
|
return send_buttons
|
|
|
|
async def get_render_result(
|
|
self, data: "ZZZCalculatorCharacterDetails", nickname: str, ch_id: int, uid: int
|
|
) -> "RenderResult":
|
|
final = self.parse_render_data(data, nickname, ch_id, uid)
|
|
return await self.template_service.render(
|
|
"zzz/agent_detail/agent_detail.html",
|
|
final,
|
|
{"width": 1024, "height": 1200},
|
|
query_selector=".shareContainer_2ZR-xeyd",
|
|
full_page=True,
|
|
)
|
|
|
|
@staticmethod
|
|
def get_caption(data: "ZZZCalculatorCharacterDetails", character_id: int) -> str:
|
|
tags = []
|
|
for character in data.characters:
|
|
if character.id == character_id:
|
|
tags.append(character.name)
|
|
tags.append(f"等级{character.level}")
|
|
tags.append(f"命座{character.rank}")
|
|
if weapon := character.weapon:
|
|
tags.append(weapon.name)
|
|
tags.append(f"武器等级{weapon.level}")
|
|
tags.append(f"精{weapon.star}")
|
|
break
|
|
return "#" + " #".join(tags)
|
|
|
|
@handler.command(command="agent_detail", block=False)
|
|
@handler.message(filters=filters.Regex("^角色详细信息查询(.*)"), block=False)
|
|
async def command_start(self, update: "Update", context: "ContextTypes.DEFAULT_TYPE") -> None:
|
|
user_id = await self.get_real_user_id(update)
|
|
message = update.effective_message
|
|
uid, offset = self.get_real_uid_or_offset(update)
|
|
args = self.get_args(context)
|
|
ch_name = None
|
|
for i in args:
|
|
if i.startswith("@"):
|
|
continue
|
|
ch_name = roleToName(i)
|
|
if ch_name:
|
|
break
|
|
self.log_user(
|
|
update,
|
|
logger.info,
|
|
"角色详细信息查询命令请求 || character_name[%s]",
|
|
ch_name,
|
|
)
|
|
await message.reply_chat_action(ChatAction.TYPING)
|
|
async with self.helper.genshin(user_id, player_id=uid, offset=offset) as client:
|
|
nickname, data = await self.get_characters(client.player_id, client)
|
|
uid = client.player_id
|
|
if ch_name is None:
|
|
buttons = self.gen_button(data, user_id, uid)
|
|
if isinstance(self.kitsune, str):
|
|
photo = self.kitsune
|
|
else:
|
|
photo = open("resources/img/aaa.jpg", "rb")
|
|
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
|
reply_message = await message.reply_photo(
|
|
photo=photo,
|
|
caption=f"请选择你要查询的角色 - UID {uid}",
|
|
reply_markup=InlineKeyboardMarkup(buttons),
|
|
)
|
|
if reply_message.photo:
|
|
self.kitsune = reply_message.photo[-1].file_id
|
|
return
|
|
for characters in data.characters:
|
|
if idToRole(characters.id) == ch_name:
|
|
break
|
|
else:
|
|
await message.reply_text(f"未在游戏中找到 {ch_name} ,请检查角色是否存在,或者等待角色数据更新后重试")
|
|
return
|
|
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
|
render_result = await self.get_render_result(data, nickname, characters.id, client.player_id)
|
|
await render_result.reply_photo(
|
|
message,
|
|
filename=f"{client.player_id}.png",
|
|
reply_markup=self.get_custom_button(user_id, uid, characters.id),
|
|
caption=self.get_caption(data, characters.id),
|
|
)
|
|
|
|
@handler.callback_query(pattern=r"^get_role_detail\|", block=False)
|
|
async def get_role_detail(self, update: "Update", _: "ContextTypes.DEFAULT_TYPE") -> None:
|
|
callback_query = update.callback_query
|
|
user = callback_query.from_user
|
|
message = callback_query.message
|
|
|
|
async def get_role_detail_callback(
|
|
callback_query_data: str,
|
|
) -> Tuple[str, int, int]:
|
|
_data = callback_query_data.split("|")
|
|
_user_id = int(_data[1])
|
|
_uid = int(_data[2])
|
|
_result = _data[3]
|
|
logger.debug(
|
|
"callback_query_data函数返回 result[%s] user_id[%s] uid[%s]",
|
|
_result,
|
|
_user_id,
|
|
_uid,
|
|
)
|
|
return _result, _user_id, _uid
|
|
|
|
result, user_id, uid = await get_role_detail_callback(callback_query.data)
|
|
if user.id != user_id:
|
|
await callback_query.answer(text="这不是你的按钮!\n" + config.notice.user_mismatch, show_alert=True)
|
|
return
|
|
if result == "empty_data":
|
|
await callback_query.answer(text="此按钮不可用", show_alert=True)
|
|
return
|
|
page = 0
|
|
if result.isdigit():
|
|
page = int(result)
|
|
logger.info(
|
|
"用户 %s[%s] 角色详细信息查询命令请求 || page[%s] uid[%s]",
|
|
user.full_name,
|
|
user.id,
|
|
page,
|
|
uid,
|
|
)
|
|
else:
|
|
logger.info(
|
|
"用户 %s[%s] 角色详细信息查询命令请求 || character_name[%s] uid[%s]",
|
|
user.full_name,
|
|
user.id,
|
|
result,
|
|
uid,
|
|
)
|
|
try:
|
|
nickname, data = await self.get_characters(uid)
|
|
except NeedClient:
|
|
async with self.helper.genshin(user.id, player_id=uid) as client:
|
|
nickname, data = await self.get_characters(client.player_id, client)
|
|
if page:
|
|
buttons = self.gen_button(data, user.id, uid, page)
|
|
await message.edit_reply_markup(reply_markup=InlineKeyboardMarkup(buttons))
|
|
await callback_query.answer(f"已切换到第 {page} 页", show_alert=False)
|
|
return
|
|
for characters in data.characters:
|
|
if idToRole(characters.id) == result:
|
|
break
|
|
else:
|
|
await message.delete()
|
|
await callback_query.answer(
|
|
f"未在游戏中找到 {result} ,请检查角色是否存在,或者等待角色数据更新后重试",
|
|
show_alert=True,
|
|
)
|
|
return
|
|
await callback_query.answer(text="正在渲染图片中 请稍等 请不要重复点击按钮", show_alert=False)
|
|
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
|
render_result = await self.get_render_result(data, nickname, characters.id, uid)
|
|
render_result.filename = f"role_detail_{uid}_{result}.png"
|
|
render_result.caption = self.get_caption(data, characters.id)
|
|
await render_result.edit_media(message, reply_markup=self.get_custom_button(user.id, uid, characters.id))
|
|
|
|
@staticmethod
|
|
def get_custom_button(user_id: int, uid: int, char_id: int) -> Optional[InlineKeyboardMarkup]:
|
|
return None
|