From 3dbc17b2a2939b6362aabbe05bed87ccb809709d Mon Sep 17 00:00:00 2001 From: xtaodada Date: Fri, 12 Jul 2024 21:54:54 +0800 Subject: [PATCH] :bug: Fix player info system --- gram_core | 2 +- plugins/tools/player_info.py | 139 +++++++++++++++++++--------- plugins/zzz/action_log.py | 10 +- plugins/zzz/avatar_list.py | 14 ++- plugins/zzz/signal_log.py | 10 +- plugins/zzz/stats.py | 21 +++-- resources/zzz/avatar_list/main.html | 7 ++ resources/zzz/stats/stats.html | 7 +- 8 files changed, 144 insertions(+), 66 deletions(-) diff --git a/gram_core b/gram_core index 549a40e..0ae6a40 160000 --- a/gram_core +++ b/gram_core @@ -1 +1 @@ -Subproject commit 549a40e8afe579d2448809ef566e91f84e1440f9 +Subproject commit 0ae6a4043375a50a011efd212d54bb6c9feb7b23 diff --git a/plugins/tools/player_info.py b/plugins/tools/player_info.py index 4090568..fa70da6 100644 --- a/plugins/tools/player_info.py +++ b/plugins/tools/player_info.py @@ -1,62 +1,113 @@ +from datetime import datetime, timedelta from typing import Optional -from enkanetwork import Assets +from pydantic import BaseModel +from simnet import ZZZClient from core.plugin import Plugin +from core.services.players.models import PlayersDataBase as Player from core.services.players.services import PlayerInfoService, PlayersService -from metadata.genshin import AVATAR_DATA +from gram_core.dependence.redisdb import RedisDB +from gram_core.services.players.models import ExtraPlayerInfo +from plugins.tools.genshin import GenshinHelper +from utils.const import RESOURCE_DIR from utils.log import logger +class PlayerAvatarInfo(BaseModel, frozen=False): + player_id: int + name_card: str + avatar: str + nickname: str + level: int + + class PlayerInfoSystem(Plugin): def __init__( self, player_service: PlayersService = None, player_info_service: PlayerInfoService = None, + helper: GenshinHelper = None, + redis: RedisDB = None, ) -> None: - self.player_info_service = player_info_service self.player_service = player_service + self.player_info_service = player_info_service + self.helper = helper + self.cache = redis.client + self.qname = "players_info_avatar" + self.ttl = 1 * 60 * 60 # 1小时 - async def get_player_info(self, player_id: int, user_id: int, user_name: str): - player = await self.player_service.get(user_id, player_id) - player_info = await self.player_info_service.get(player) - nickname = user_name - name_card: Optional[str] = None - avatar: Optional[str] = None - rarity: int = 5 - try: - if player_info is not None: - if player_info.nickname is not None: - nickname = player_info.nickname - if player_info.name_card is not None: - name_card = (await self.assets_service.namecard(int(player_info.name_card)).navbar()).as_uri() - if player_info.hand_image is not None: - if player_info.hand_image > 10000000: - avatar = (await self.assets_service.avatar(player_info.hand_image).icon()).as_uri() - try: - rarity = {k: v["rank"] for k, v in AVATAR_DATA.items()}[str(player_info.hand_image)] - except KeyError: - logger.warning("未找到角色 %s 的星级", player_info.hand_image) - else: - avatar = Assets.profile_picture(player_info.hand_image).url - rarity = 5 - except Exception as exc: # pylint: disable=W0703 - logger.error("卡片信息请求失败 %s", str(exc)) - if name_card is None: # 默认 - name_card = (await self.assets_service.namecard(0).navbar()).as_uri() - if avatar is None: # 默认 - avatar = (await self.assets_service.avatar(0).icon()).as_uri() - return name_card, avatar, nickname, rarity + async def get_form_cache(self, player_id: int) -> Optional[PlayerAvatarInfo]: + qname = f"{self.qname}:{player_id}" + data = await self.cache.get(qname) + if data is None: + return None + json_data = str(data, encoding="utf-8") + return PlayerAvatarInfo.parse_raw(json_data) - async def get_name_card(self, player_id: int, user_id: int): - player = await self.player_service.get(user_id, player_id) - player_info = await self.player_info_service.get(player) - name_card: Optional[str] = None + async def set_form_cache(self, player: PlayerAvatarInfo): + qname = f"{self.qname}:{player.player_id}" + await self.cache.set(qname, player.json(), ex=self.ttl) + + @staticmethod + def get_base_avatar_info(player_id: int, user_name: str) -> PlayerAvatarInfo: + res = RESOURCE_DIR / "img" + return PlayerAvatarInfo( + player_id=player_id, + name_card=(res / "home.png").as_uri(), + avatar=(res / "avatar.png").as_uri(), + nickname=user_name, + level=0, + ) + + async def update_player_info(self, player: "Player", nickname: str, level: int): + player_info = await self.player_info_service.get_form_sql(player) + if player_info is not None and player_info.create_time is not None: + player_info.nickname = nickname + if player_info.extra_data is None: + player_info.extra_data = ExtraPlayerInfo() + player_info.extra_data.level = level + await self.player_info_service.update(player_info) + + async def get_player_info_by_cookie(self, player: "Player", user_name: str) -> PlayerAvatarInfo: + base_info = self.get_base_avatar_info(player.player_id, user_name) try: - if player_info is not None and player_info.name_card is not None: - name_card = (await self.assets_service.namecard(int(player_info.name_card)).navbar()).as_uri() - except Exception as exc: # pylint: disable=W0703 - logger.error("卡片信息请求失败 %s", str(exc)) - if name_card is None: # 默认 - name_card = (await self.assets_service.namecard(0).navbar()).as_uri() - return name_card + async with self.helper.genshin(player.user_id, player_id=player.player_id) as client: + client: "ZZZClient" + record_card = await client.get_record_card() + if record_card is not None: + base_info.nickname = record_card.nickname + base_info.level = record_card.level + await self.update_player_info(player, base_info.nickname, base_info.level) + except Exception as e: + logger.warning("卡片信息通过 cookie 请求失败 %s", str(e)) + return base_info + + async def get_player_info(self, player_id: int, user_name: str) -> PlayerAvatarInfo: + cache = await self.get_form_cache(player_id) + if cache is not None: + return cache + + player = await self.player_service.get(None, player_id) + base_info = self.get_base_avatar_info(player_id, user_name) + if not player: + return base_info + player_info = await self.player_info_service.get(player) + if player_info is None or player_info.create_time is None: + return base_info + expiration_time = datetime.now() - timedelta(hours=2) + if ( + player_info.last_save_time is None + or player_info.extra_data is None + or player_info.last_save_time <= expiration_time + ): + base_info = await self.get_player_info_by_cookie(player, player_info.nickname) + else: + base_info.nickname = player_info.nickname + base_info.level = player_info.extra_data.level + + await self.set_form_cache(base_info) + return base_info + + async def get_theme_info(self, player_id: int) -> PlayerAvatarInfo: + return await self.get_player_info(player_id, "") diff --git a/plugins/zzz/action_log.py b/plugins/zzz/action_log.py index 4a1e68e..c32bbe7 100644 --- a/plugins/zzz/action_log.py +++ b/plugins/zzz/action_log.py @@ -13,7 +13,7 @@ from gram_core.services.template.services import TemplateService from modules.action_log.client import ActionLogAnalyse from plugins.tools.action_log_system import ActionLogSystem from plugins.tools.genshin import GenshinHelper -from utils.const import RESOURCE_DIR +from plugins.tools.player_info import PlayerInfoSystem from utils.log import logger from utils.uid import mask_number @@ -42,11 +42,13 @@ class ActionLogPlugins(Plugin): action_log_service: ActionLogService, action_log_system: ActionLogSystem, template_service: TemplateService, + player_info: PlayerInfoSystem, ): self.helper = helper self.action_log_service = action_log_service self.action_log_system = action_log_system self.template_service = template_service + self.player_info = player_info @handler.command(command="action_log_import", filters=filters.ChatType.PRIVATE, cookie=True, block=False) async def action_log_import(self, update: "Update", _: "ContextTypes.DEFAULT_TYPE") -> None: @@ -95,9 +97,9 @@ class ActionLogPlugins(Plugin): } async def add_theme_data(self, data: Dict, player_id: int): - res = RESOURCE_DIR / "img" - data["avatar"] = (res / "avatar.png").as_uri() - data["background"] = (res / "home.png").as_uri() + theme_info = await self.player_info.get_theme_info(player_id) + data["avatar"] = theme_info.avatar + data["background"] = theme_info.name_card return data async def render(self, client: "ZZZClient") -> "RenderResult": diff --git a/plugins/zzz/avatar_list.py b/plugins/zzz/avatar_list.py index 1c50abe..c00f034 100644 --- a/plugins/zzz/avatar_list.py +++ b/plugins/zzz/avatar_list.py @@ -19,7 +19,7 @@ from gram_core.config import config from gram_core.plugin.methods.inline_use_data import IInlineUseData from gram_core.services.template.models import RenderGroupResult from plugins.tools.genshin import GenshinHelper, CharacterDetails -from utils.const import RESOURCE_DIR +from plugins.tools.player_info import PlayerInfoSystem from utils.log import logger from utils.uid import mask_number @@ -69,6 +69,7 @@ class AvatarListPlugin(Plugin): wiki_service: WikiService = None, helper: GenshinHelper = None, character_details: CharacterDetails = None, + player_info: PlayerInfoSystem = None, ) -> None: self.cookies_service = cookies_service self.assets_service = assets_service @@ -76,6 +77,7 @@ class AvatarListPlugin(Plugin): self.wiki_service = wiki_service self.helper = helper self.character_details = character_details + self.player_info = player_info async def get_avatar_data(self, character_id: int, client: "ZZZClient") -> Optional["ZZZCalculatorCharacter"]: return await self.character_details.get_character_details(client, character_id) @@ -179,14 +181,14 @@ class AvatarListPlugin(Plugin): return await asyncio.gather(*tasks) async def add_theme_data(self, data: Dict, player_id: int): - res = RESOURCE_DIR / "img" - data["avatar"] = (res / "avatar.png").as_uri() - data["background"] = (res / "home.png").as_uri() + theme_info = await self.player_info.get_theme_info(player_id) + data["avatar"] = theme_info.avatar + data["background"] = theme_info.name_card return data async def render(self, client: "ZZZClient", all_avatars: bool = False) -> List["RenderResult"]: characters: List["ZZZPartialCharacter"] = await self.get_avatars_data(client) - + player_info = await self.player_info.get_player_info(client.player_id, "") has_more = (not all_avatars) and len(characters) > MAX_AVATAR_COUNT if has_more: characters = characters[:MAX_AVATAR_COUNT] @@ -194,6 +196,8 @@ class AvatarListPlugin(Plugin): base_render_data = { "uid": mask_number(client.player_id), # 玩家uid + "nickname": player_info.nickname, # 玩家昵称 + "level": player_info.level, "has_more": has_more, # 是否显示了全部角色 } await self.add_theme_data(base_render_data, client.player_id) diff --git a/plugins/zzz/signal_log.py b/plugins/zzz/signal_log.py index 3548b65..de1c51a 100644 --- a/plugins/zzz/signal_log.py +++ b/plugins/zzz/signal_log.py @@ -32,7 +32,7 @@ from modules.gacha_log.log import GachaLog from modules.gacha_log.migrate import GachaLogMigrate from modules.gacha_log.models import GachaLogInfo from plugins.tools.genshin import PlayerNotFoundError -from utils.const import RESOURCE_DIR +from plugins.tools.player_info import PlayerInfoSystem from utils.log import logger try: @@ -70,6 +70,7 @@ class WishLogPlugin(Plugin.Conversation): players_service: PlayersService, assets: AssetsService, cookie_service: CookiesService, + player_info: PlayerInfoSystem, ): self.template_service = template_service self.players_service = players_service @@ -77,6 +78,7 @@ class WishLogPlugin(Plugin.Conversation): self.cookie_service = cookie_service self.gacha_log = GachaLog() self.wish_photo = None + self.player_info = player_info async def get_player_id(self, user_id: int, player_id: int, offset: int) -> int: """获取绑定的游戏ID""" @@ -543,9 +545,9 @@ class WishLogPlugin(Plugin.Conversation): await png.edit_media(message) async def add_theme_data(self, data: Dict, player_id: int): - res = RESOURCE_DIR / "img" - data["avatar"] = (res / "avatar.png").as_uri() - data["background"] = (res / "home.png").as_uri() + theme_info = await self.player_info.get_theme_info(player_id) + data["avatar"] = theme_info.avatar + data["background"] = theme_info.name_card return data @staticmethod diff --git a/plugins/zzz/stats.py b/plugins/zzz/stats.py index c9e1fe7..e0a64b7 100644 --- a/plugins/zzz/stats.py +++ b/plugins/zzz/stats.py @@ -1,4 +1,3 @@ -import random from typing import Optional, TYPE_CHECKING, List from telegram.constants import ChatAction from telegram.ext import filters @@ -10,7 +9,7 @@ from core.services.template.models import RenderResult from core.services.template.services import TemplateService from gram_core.plugin.methods.inline_use_data import IInlineUseData from plugins.tools.genshin import GenshinHelper -from utils.const import RESOURCE_DIR +from plugins.tools.player_info import PlayerInfoSystem from utils.log import logger from utils.uid import mask_number @@ -25,9 +24,15 @@ __all__ = ("PlayerStatsPlugins",) class PlayerStatsPlugins(Plugin): """玩家统计查询""" - def __init__(self, template: TemplateService, helper: GenshinHelper): + def __init__( + self, + template: TemplateService, + helper: GenshinHelper, + player_info: PlayerInfoSystem, + ): self.template_service = template self.helper = helper + self.player_info = player_info @handler.command("stats", player=True, block=False) @handler.message(filters.Regex("^玩家统计查询(.*)"), player=True, block=False) @@ -60,11 +65,13 @@ class PlayerStatsPlugins(Plugin): async def render(self, client: "ZZZClient", nickname: str) -> RenderResult: uid = client.player_id user_info = await client.get_zzz_user(uid) + player_info = await self.player_info.get_player_info(uid, nickname) data = { "uid": mask_number(uid), "stats": user_info.stats, - "nickname": nickname, + "nickname": player_info.nickname, + "level": player_info.level, "stats_labels": [ ("活跃天数", "active_days"), ("获取角色数", "avatar_num"), @@ -112,9 +119,9 @@ class PlayerStatsPlugins(Plugin): await render_result.edit_inline_media(callback_query) async def add_theme_data(self, data, player_id: int): - res = RESOURCE_DIR / "img" - data["avatar"] = (res / "avatar.png").as_uri() - data["background"] = (res / "home.png").as_uri() + theme_info = await self.player_info.get_theme_info(player_id) + data["avatar"] = theme_info.avatar + data["background"] = theme_info.name_card return data async def get_inline_use_data(self) -> List[Optional[IInlineUseData]]: diff --git a/resources/zzz/avatar_list/main.html b/resources/zzz/avatar_list/main.html index 0bc331d..f63ff21 100644 --- a/resources/zzz/avatar_list/main.html +++ b/resources/zzz/avatar_list/main.html @@ -33,6 +33,13 @@ alt="Avatar" />
+ +
+ {{ nickname }} + {% if level > 0 %} + lv.{{ level }} + {% endif %} +
UID: {{ uid }}
diff --git a/resources/zzz/stats/stats.html b/resources/zzz/stats/stats.html index c7a87b8..8c8c5c4 100644 --- a/resources/zzz/stats/stats.html +++ b/resources/zzz/stats/stats.html @@ -46,7 +46,12 @@
-

{{ nickname }}

+

+ {{ nickname }} + {% if level > 0 %} + lv.{{ level }} + {% endif %} +

UID: {{ uid }}