diff --git a/metadata/genshin.py b/metadata/genshin.py index ef1cac81..f741588b 100644 --- a/metadata/genshin.py +++ b/metadata/genshin.py @@ -3,7 +3,7 @@ from __future__ import annotations import functools -from typing import Any, Generic, ItemsView, Iterator, KeysView, TypeVar +from typing import Any, Generic, ItemsView, Iterator, KeysView, TypeVar, Optional import ujson as json @@ -21,6 +21,8 @@ __all__ = [ "honey_id_to_game_id", "game_id_to_role_id", "Data", + "weapon_to_game_id", + "avatar_to_game_id" ] K = TypeVar("K") @@ -99,3 +101,15 @@ def game_id_to_role_id(gid: str) -> int | None: return next( (int(key.split("-")[0]) for key, value in AVATAR_DATA.items() if value["icon"].split("_")[-1] == gid), None ) + + +def weapon_to_game_id(name: str) -> Optional[int]: + return next( + (int(key) for key, value in WEAPON_DATA.items() if value['name'] == name), None + ) + + +def avatar_to_game_id(name: str) -> Optional[int]: + return next( + (int(key) for key, value in AVATAR_DATA.items() if value['name'] == name), None + ) diff --git a/modules/apihelper/hyperion.py b/modules/apihelper/hyperion.py index 3cc047dc..5dd4b03a 100644 --- a/modules/apihelper/hyperion.py +++ b/modules/apihelper/hyperion.py @@ -1,6 +1,7 @@ import asyncio import re import time +from datetime import datetime from json import JSONDecodeError from typing import List, Optional, Dict @@ -9,7 +10,6 @@ from genshin.utility.ds import generate_dynamic_secret from genshin.utility.uid import recognize_genshin_server from httpx import AsyncClient from pydantic import BaseModel, validator -from datetime import datetime from modules.apihelper.base import ArtworkImage, PostInfo from modules.apihelper.helpers import get_device_id @@ -190,6 +190,9 @@ class GachaInfo: self.cache[gacha_id] = req return req + async def close(self): + await self.client.shutdown() + class SignIn: LOGIN_URL = "https://webapi.account.mihoyo.com/Api/login_by_mobilecaptcha" diff --git a/modules/gacha/banner.py b/modules/gacha/banner.py index d7319c7a..ba153d16 100644 --- a/modules/gacha/banner.py +++ b/modules/gacha/banner.py @@ -30,6 +30,9 @@ class GachaBanner: 15304, ] # 硬编码三星武器 + title: str = "" + html_title: str = "" + banner_id: str = "" banner_type: BannerType = BannerType.STANDARD wish_max_progress: int = 0 pool_balance_weights4: Tuple[int] = ((1, 255), (17, 255), (21, 10455)) diff --git a/plugins/genshin/gacha/gacha.py b/plugins/genshin/gacha/gacha.py index 2ef54cf2..ed9d8d8e 100644 --- a/plugins/genshin/gacha/gacha.py +++ b/plugins/genshin/gacha/gacha.py @@ -1,19 +1,25 @@ +import asyncio import os import re from datetime import datetime -from typing import Dict +from typing import Optional, Union, Any, List +import ujson as json from bs4 import BeautifulSoup -from pyppeteer import launch from telegram import Update from telegram.constants import ChatAction from telegram.ext import CallbackContext, CommandHandler, MessageHandler, filters +from core.base.redisdb import RedisDB from core.baseplugin import BasePlugin from core.plugin import Plugin, handler from core.template import TemplateService -from modules.apihelper.hyperion import GachaInfo -from plugins.genshin.gacha.wish import WishCountInfo, get_one +from metadata.genshin import weapon_to_game_id, avatar_to_game_id, WEAPON_DATA, AVATAR_DATA +from metadata.shortname import weaponToName +from modules.apihelper.hyperion import GachaInfo, GachaInfoObject +from modules.gacha.banner import BannerType, GachaBanner +from modules.gacha.player.info import PlayerGachaInfo +from modules.gacha.system import BannerSystem from utils.bot import get_all_args from utils.decorators.error import error_callable from utils.decorators.restricts import restricts @@ -23,37 +29,126 @@ from utils.log import logger class GachaNotFound(Exception): """卡池未找到""" - def __init__(self, gacha_name): + def __init__(self, gacha_name: str): + self.gacha_name = gacha_name super().__init__(f"{gacha_name} gacha not found") +class GachaRedis: + def __init__(self, redis: RedisDB): + self.client = redis.client + self.qname = "plugin:gacha:" + + async def get(self, user_id: int) -> PlayerGachaInfo: + data = await self.client.get(f"{self.qname}{user_id}") + if data is None: + return PlayerGachaInfo() + return PlayerGachaInfo(**json.loads(data)) + + async def set(self, user_id: int, player_gacha_info: PlayerGachaInfo): + value = player_gacha_info.json() + await self.client.set(f"{self.qname}{user_id}", value) + + +class GachaHandle: + def __init__(self, hyperion: Optional[GachaInfo] = None): + if hyperion is None: + self.hyperion = GachaInfo() + else: + self.hyperion = hyperion + + async def de_banner(self, gacha_id: str, gacha_type: int) -> Optional[GachaBanner]: + gacha_info = await self.hyperion.get_gacha_info(gacha_id) + banner = GachaBanner() + banner.title, banner.html_title = self.de_title(gacha_info["title"]) + for r5_up_items in gacha_info["r5_up_items"]: + if r5_up_items["item_type"] == "角色": + banner.rate_up_items5.append(avatar_to_game_id(r5_up_items["item_name"])) + elif r5_up_items["item_type"] == "武器": + banner.rate_up_items5.append(weapon_to_game_id(r5_up_items["item_name"])) + for r5_prob_list in gacha_info["r5_prob_list"]: + if r5_prob_list["item_type"] == "角色": + banner.fallback_items5_pool1.append(avatar_to_game_id(r5_prob_list["item_name"])) + elif r5_prob_list["item_type"] == "武器": + banner.fallback_items5_pool1.append(weapon_to_game_id(r5_prob_list["item_name"])) + for r4_up_items in gacha_info["r4_up_items"]: + if r4_up_items["item_type"] == "角色": + banner.rate_up_items4.append(avatar_to_game_id(r4_up_items["item_name"])) + elif r4_up_items["item_type"] == "武器": + banner.rate_up_items4.append(weapon_to_game_id(r4_up_items["item_name"])) + for r4_prob_list in gacha_info["r4_prob_list"]: + if r4_prob_list["item_type"] == "角色": + banner.fallback_items4_pool1.append(avatar_to_game_id(r4_prob_list["item_name"])) + elif r4_prob_list["item_type"] == "武器": + banner.fallback_items4_pool1.append(weapon_to_game_id(r4_prob_list["item_name"])) + if gacha_type in (310, 400): + banner.wish_max_progress = 1 + banner.banner_type = BannerType.EVENT + banner.weight4 = ((1, 510), (8, 510), (10, 10000)) + banner.weight5 = ((1, 60), (73, 60), (90, 10000)) + elif gacha_type == 302: + banner.wish_max_progress = 3 + banner.banner_type = BannerType.WEAPON + banner.weight4 = ((1, 600), (7, 600), (10, 10000)) + banner.weight5 = ((1, 70), (62, 70), (90, 10000)) + else: + banner.banner_type = BannerType.STANDARD + return banner + + async def gacha_base_info(self, gacha_name: str = "角色活动", default: bool = False) -> GachaInfoObject: + gacha_list_info = await self.hyperion.get_gacha_list_info() + now = datetime.now() + for gacha in gacha_list_info: + if gacha.gacha_name == gacha_name and gacha.begin_time <= now <= gacha.end_time: + return gacha + else: # pylint: disable=W0120 + if default and len(gacha_list_info) > 0: + return gacha_list_info[0] + else: + raise GachaNotFound(gacha_name) + + @staticmethod + async def de_item_list(item_list: List[int]) -> List[dict]: + gacha_item: List[dict] = [] + for item_id in item_list: + if 10000 <= item_id <= 100000: + gacha_item.append(WEAPON_DATA.get(str(item_id))) + if 10000000 <= item_id <= 19999999: + gacha_item.append(AVATAR_DATA.get(str(item_id))) + return gacha_item + + @staticmethod + def de_title(title: str) -> Union[tuple[str, None], tuple[str, Any]]: + title_html = BeautifulSoup(title, "lxml") + re_color = re.search(r"", title, flags=0) + if re_color is None: + return title_html.text, None + color = re_color.group(1) + title_html.color.name = "span" + title_html.span["style"] = f"color:#{color};" + return title_html.text, title_html.p + + class Gacha(Plugin, BasePlugin): """抽卡模拟器(非首模拟器/减寿模拟器)""" - def __init__(self, template_service: TemplateService = None): - self.gacha = GachaInfo() + def __init__(self, template_service: TemplateService = None, redis: RedisDB = None): + self.gacha_db = GachaRedis(redis) + self.handle = GachaHandle() + self.banner_system = BannerSystem() self.template_service = template_service - self.browser: launch = None self.current_dir = os.getcwd() self.resources_dir = os.path.join(self.current_dir, "resources") - self.character_gacha_card = {} - self.user_time = {} + self.banner_cache = {} + self._look = asyncio.Lock() - async def gacha_info(self, gacha_name: str = "角色活动", default: bool = False): - gacha_list_info = await self.gacha.get_gacha_list_info() - gacha_id = "" - now = datetime.now() - for gacha in gacha_list_info: - if gacha.gacha_name == gacha_name and gacha.begin_time <= now <= gacha.end_time: - gacha_id = gacha.gacha_id - if gacha_id == "": - if default and len(gacha_list_info) > 0: - gacha_id = gacha_list_info[0].gacha_id - else: - raise GachaNotFound(gacha_name) - gacha_info = await self.gacha.get_gacha_info(gacha_id) - gacha_info["gacha_id"] = gacha_id - return gacha_info + async def get_banner(self, gacha_base_info: GachaInfoObject): + async with self._look: + banner = self.banner_cache.get(gacha_base_info.gacha_id) + if banner is None: + banner = await self.handle.de_banner(gacha_base_info.gacha_id, gacha_base_info.gacha_type) + self.banner_cache.setdefault(gacha_base_info.gacha_id, banner) + return banner @handler(CommandHandler, command="gacha", block=False) @handler(MessageHandler, filters=filters.Regex("^非首模拟器(.*)"), block=False) @@ -72,66 +167,92 @@ class Gacha(Plugin, BasePlugin): gacha_name = value break try: - gacha_info = await self.gacha_info(gacha_name) - except GachaNotFound: - await message.reply_text(f"没有找到名为 {gacha_name} 的卡池") + gacha_base_info = await self.handle.gacha_base_info(gacha_name) + except GachaNotFound as exc: + await message.reply_text(f"没有找到名为 {exc.gacha_name} 的卡池") return else: - gacha_info = await self.gacha_info(default=True) + gacha_base_info = await self.handle.gacha_base_info(default=True) logger.info(f"用户 {user.full_name}[{user.id}] 抽卡模拟器命令请求 || 参数 {gacha_name}") # 用户数据储存和处理 - gacha_id: str = gacha_info["gacha_id"] - user_gacha: Dict[str, WishCountInfo] = context.user_data.get("gacha") - if user_gacha is None: - user_gacha = context.user_data["gacha"] = {} - user_gacha_count: WishCountInfo = user_gacha.get(gacha_id) - if user_gacha_count is None: - user_gacha_count = user_gacha[gacha_id] = WishCountInfo(user_id=user.id) - # 用户数据储存和处理 - title = gacha_info["title"] - re_color = re.search(r"", title, flags=0) - if re_color is None: - title_html = BeautifulSoup(title, "lxml") - pool_name = title_html.text - logger.warning(f"卡池信息 title 提取 color 失败 title[{title}]") - else: - color = re_color.group(1) - title_html = BeautifulSoup(title, "lxml") - title_html.color.name = "span" - title_html.span["style"] = f"color:#{color};" - pool_name = title_html.p await message.reply_chat_action(ChatAction.TYPING) - data = { + banner = await self.get_banner(gacha_base_info) + player_gacha_info = await self.gacha_db.get(user.id) + # 检查 wish_item_id + if banner.banner_type == BannerType.WEAPON: + if player_gacha_info.event_weapon_banner.wish_item_id not in banner.rate_up_items5: + player_gacha_info.event_weapon_banner.wish_item_id = 0 + # 执行抽卡 + item_list = self.banner_system.do_pulls(player_gacha_info, banner, 10) + data = await self.handle.de_item_list(item_list) + player_gacha_banner_info = player_gacha_info.get_banner_info(banner) + template_data = { "_res_path": f"file://{self.resources_dir}", "name": f"{user.full_name}", "info": gacha_name, - "poolName": pool_name, + "banner_name": banner.html_title, + "banner_type": banner.banner_type.name, + "player_gacha_banner_info": player_gacha_banner_info, "items": [], + "wish_name": "", } - for _ in range(10): - item = get_one(user_gacha_count, gacha_info) - # 下面为忽略的代码,因为metadata未完善,具体武器和角色类型无法显示 - # item_name = item["item_name"] - # item_type = item["item_type"] - # if item_type == "角色": - # gacha_card = self.character_gacha_card.get(item_name) - # if gacha_card is None: - # await message.reply_text(f"获取角色 {item_name} GachaCard信息失败") - # return - # item["item_character_img"] = await url_to_file(gacha_card) - data["items"].append(item) + if player_gacha_banner_info.wish_item_id != 0: + weapon = WEAPON_DATA.get(str(player_gacha_banner_info.wish_item_id)) + if weapon is not None: + template_data["wish_name"] = weapon["name"] + await self.gacha_db.set(user.id, player_gacha_info) def take_rang(elem: dict): return elem["rank"] - data["items"].sort(key=take_rang, reverse=True) + data.sort(key=take_rang, reverse=True) + template_data["items"] = data await message.reply_chat_action(ChatAction.UPLOAD_PHOTO) - # 因为 gacha_info["title"] 返回的是 HTML 标签 尝试关闭自动转义 png_data = await self.template_service.render( - "genshin/gacha/gacha.html", data, {"width": 1157, "height": 603}, False + "genshin/gacha/gacha.html", template_data, {"width": 1157, "height": 603}, False ) reply_message = await message.reply_photo(png_data) if filters.ChatType.GROUPS.filter(message): self._add_delete_message_job(context, reply_message.chat_id, reply_message.message_id, 300) self._add_delete_message_job(context, message.chat_id, message.message_id, 300) + + @handler(CommandHandler, command="set_wish", block=False) + @handler(MessageHandler, filters=filters.Regex("^非首模拟器定轨(.*)"), block=False) + @restricts(restricts_time=3, restricts_time_of_groups=20) + @error_callable + async def set_wish(self, update: Update, context: CallbackContext) -> None: + message = update.effective_message + user = update.effective_user + args = get_all_args(context) + gacha_base_info = await self.handle.gacha_base_info("武器活动") + banner = await self.get_banner(gacha_base_info) + if len(args) >= 1: + weapon_name = args[0] + else: + reply_message = await message.reply_text("参数错误") + if filters.ChatType.GROUPS.filter(reply_message): + self._add_delete_message_job(context, message.chat_id, message.message_id, 10) + self._add_delete_message_job(context, reply_message.chat_id, reply_message.message_id, 10) + return + weapon_name = weaponToName(weapon_name) + player_gacha_info = await self.gacha_db.get(user.id) + for rate_up_items5 in banner.rate_up_items5: + weapon = WEAPON_DATA.get(str(rate_up_items5)) + if weapon is None: + continue + if weapon["name"] == weapon_name: + player_gacha_info.event_weapon_banner.wish_item_id = rate_up_items5 + break + else: + reply_message = await message.reply_text(f"没有找到 {weapon_name} 武器或该武器不存在UP卡池中") + if filters.ChatType.GROUPS.filter(reply_message): + self._add_delete_message_job(context, message.chat_id, message.message_id, 10) + self._add_delete_message_job(context, reply_message.chat_id, reply_message.message_id, 10) + return + await self.gacha_db.set(user.id, player_gacha_info) + reply_message = await message.reply_text(f"抽卡模拟器定轨 {weapon_name} 武器成功") + if filters.ChatType.GROUPS.filter(reply_message): + self._add_delete_message_job(context, message.chat_id, message.message_id, 10) + self._add_delete_message_job(context, reply_message.chat_id, reply_message.message_id, 10) + return diff --git a/plugins/genshin/gacha/wish.py b/plugins/genshin/gacha/wish.py deleted file mode 100644 index c719bcb7..00000000 --- a/plugins/genshin/gacha/wish.py +++ /dev/null @@ -1,131 +0,0 @@ -import random -from enum import Enum - - -class GachaType(Enum): - activity = 301 # 限定卡池 - activity2 = 400 # 限定卡池 - weapon = 302 # 武器卡池 - permanent = 200 # 常驻卡池 - - -class WishCountInfo: - def __init__(self, user_id: int): - self.user_id = user_id - self.five_stars_count: int = 1 - self.four_stars_count: int = 1 - self.is_up: bool = False - self.maximum_fate_points: int = 0 - - -def character_probability(rank, count): - ret = 0 - if rank == 5 and count <= 73: - ret = 60 - elif rank == 5 and count >= 74: - ret = 60 + 600 * (count - 73) - elif rank == 4 and count <= 8: - ret = 510 - elif rank == 4 and count >= 9: - ret = 510 + 5100 * (count - 8) - return ret - - -def weapon_probability(rank, count): - ret = 0 - if rank == 5 and count <= 62: - ret = 70 - elif rank == 5 and count <= 73: - ret = 70 + 700 * (count - 62) - elif rank == 5 and count >= 74: - ret = 7770 + 350 * (count - 73) - elif rank == 4 and count <= 7: - ret = 600 - elif rank == 4 and count == 8: - ret = 6600 - elif rank == 4 and count >= 9: - ret = 6600 + 3000 * (count - 8) - return ret - - -def is_character_gacha(gacha_type: GachaType) -> bool: - return gacha_type in (GachaType.activity, GachaType.activity2, GachaType.permanent) - - -def random_int(): - return random.randint(0, 10000) - - -def get_is_up(rank: int, count: WishCountInfo, gacha_type: GachaType): - if gacha_type == GachaType.permanent: - return False - elif gacha_type == GachaType.weapon: - return random_int() <= 7500 - else: - return random_int() <= 5000 or (rank == 5 and count.is_up) - - -def get_rank(count: WishCountInfo, gacha_type: GachaType): - value = random_int() - probability_fn = character_probability if is_character_gacha(gacha_type) else weapon_probability - index_5 = probability_fn(5, count.five_stars_count) - index_4 = probability_fn(4, count.four_stars_count) + index_5 - if value <= index_5: - return 5 - elif value <= index_4: - return 4 - else: - return 3 - - -def get_one(count: WishCountInfo, gacha_info: dict, weapon_name: str = "") -> dict: - gacha_type = GachaType(gacha_info["gacha_type"]) - rank = get_rank(count, gacha_type) - is_up = get_is_up(rank, count, gacha_type) - if rank == 5: - count.five_stars_count = 1 - if is_up: - data = random.choice(gacha_info["r5_up_items"]) - else: - data = random.choice(gacha_info["r5_prob_list"]) - if gacha_type == GachaType.weapon: - if data["item_name"] == weapon_name: - count.maximum_fate_points = 0 - elif count.maximum_fate_points == 2: - count.maximum_fate_points = 0 - for temp_item in gacha_info["r5_up_items"]: - if temp_item["item_name"] == weapon_name: - data = temp_item - break - else: - count.maximum_fate_points += 1 - if gacha_type in (GachaType.activity, GachaType.activity2, GachaType.weapon): - count.is_up = not is_up - return { - "item_type": data["item_type"], - "item_name": data["item_name"], - "rank": 5, - } - elif rank == 4: - count.five_stars_count += 1 - count.four_stars_count = 1 - if is_up: - data = random.choice(gacha_info["r4_up_items"]) - else: - data = random.choice(gacha_info["r4_prob_list"]) - return { - "item_type": data["item_type"], - "item_name": data["item_name"], - "rank": 4, - } - elif rank == 3: - count.five_stars_count += 1 - count.four_stars_count += 1 - data = random.choice(gacha_info["r3_prob_list"]) - return { - "item_type": data["item_type"], - "item_name": data["item_name"], - "rank": 3, - } - else: - raise ValueError("rank value error") diff --git a/resources/bot/help/help.html b/resources/bot/help/help.html index f49d4a91..09aeef52 100644 --- a/resources/bot/help/help.html +++ b/resources/bot/help/help.html @@ -137,6 +137,10 @@
/gacha
抽卡模拟器(非洲人模拟器)
+
+
/set_wish
+
抽卡模拟器定轨
+
/quiz
diff --git a/resources/genshin/gacha/gacha.css b/resources/genshin/gacha/gacha.css index cc396390..50672497 100644 --- a/resources/genshin/gacha/gacha.css +++ b/resources/genshin/gacha/gacha.css @@ -54,14 +54,14 @@ body { z-index: 9999; } - -.poor-bing { +.pity5 { position: fixed; top: 85px; right: 55px; z-index: 9999; } + .list-box { display: flex; padding-top: 130px; @@ -162,6 +162,20 @@ body { z-index: 120; } +.poor-wish { + position: fixed; + top: 500px; + right: 55px; + z-index: 9999; +} + +.poor-bing { + position: fixed; + top: 580px; + right: 55px; + z-index: 9999; +} + .logo { position: absolute; right: 55px; diff --git a/resources/genshin/gacha/gacha.html b/resources/genshin/gacha/gacha.html index 1b8fdd94..5b37420e 100644 --- a/resources/genshin/gacha/gacha.html +++ b/resources/genshin/gacha/gacha.html @@ -10,29 +10,43 @@
{{name}}
{{info}}
+ {% if banner_type == "WEAPON" %} + {% if wish_name %} +
定轨:{{wish_name}}
+
命定值:{{player_gacha_banner_info.failed_chosen_item_pulls}}
+ {% else %} +
当前卡池未定轨
+ {% endif %} + {% endif %}
{% autoescape off %} - {{poolName}} + {{banner_name}} {% endautoescape %}
+
距离上一个五星{{player_gacha_banner_info.pity5}}抽
{% for item in items %}
- +
- - - {% if item.item_type=='武器' %} + + + {% if item.id <= 100000 %}
- +
{% else %}
- +
{% endif %} - + {% if item.id <= 100000 %} + + {% else %} + + {% endif %} +
{% endfor %}
diff --git a/resources/genshin/gacha/items/雷.png b/resources/genshin/gacha/items/Electric.png similarity index 100% rename from resources/genshin/gacha/items/雷.png rename to resources/genshin/gacha/items/Electric.png diff --git a/resources/genshin/gacha/items/火.png b/resources/genshin/gacha/items/Fire.png similarity index 100% rename from resources/genshin/gacha/items/火.png rename to resources/genshin/gacha/items/Fire.png diff --git a/resources/genshin/gacha/items/草.png b/resources/genshin/gacha/items/Grass.png similarity index 100% rename from resources/genshin/gacha/items/草.png rename to resources/genshin/gacha/items/Grass.png diff --git a/resources/genshin/gacha/items/冰.png b/resources/genshin/gacha/items/Ice.png similarity index 100% rename from resources/genshin/gacha/items/冰.png rename to resources/genshin/gacha/items/Ice.png diff --git a/resources/genshin/gacha/items/岩.png b/resources/genshin/gacha/items/Rock.png similarity index 100% rename from resources/genshin/gacha/items/岩.png rename to resources/genshin/gacha/items/Rock.png diff --git a/resources/genshin/gacha/items/弓.png b/resources/genshin/gacha/items/WEAPON_BOW.png similarity index 100% rename from resources/genshin/gacha/items/弓.png rename to resources/genshin/gacha/items/WEAPON_BOW.png diff --git a/resources/genshin/gacha/items/法器.png b/resources/genshin/gacha/items/WEAPON_CATALYST.png similarity index 100% rename from resources/genshin/gacha/items/法器.png rename to resources/genshin/gacha/items/WEAPON_CATALYST.png diff --git a/resources/genshin/gacha/items/大剑.png b/resources/genshin/gacha/items/WEAPON_CLAYMORE.png similarity index 100% rename from resources/genshin/gacha/items/大剑.png rename to resources/genshin/gacha/items/WEAPON_CLAYMORE.png diff --git a/resources/genshin/gacha/items/枪.png b/resources/genshin/gacha/items/WEAPON_POLE.png similarity index 100% rename from resources/genshin/gacha/items/枪.png rename to resources/genshin/gacha/items/WEAPON_POLE.png diff --git a/resources/genshin/gacha/items/单手剑.png b/resources/genshin/gacha/items/WEAPON_SWORD_ONE_HAND.png similarity index 100% rename from resources/genshin/gacha/items/单手剑.png rename to resources/genshin/gacha/items/WEAPON_SWORD_ONE_HAND.png diff --git a/resources/genshin/gacha/items/水.png b/resources/genshin/gacha/items/Water.png similarity index 100% rename from resources/genshin/gacha/items/水.png rename to resources/genshin/gacha/items/Water.png diff --git a/resources/genshin/gacha/items/风.png b/resources/genshin/gacha/items/Wind.png similarity index 100% rename from resources/genshin/gacha/items/风.png rename to resources/genshin/gacha/items/Wind.png