mirror of
https://github.com/PaiGramTeam/genshin-wiki.git
synced 2024-11-23 08:00:59 +00:00
🚧 building...
This commit is contained in:
parent
7e957ccea8
commit
fb77ca0569
@ -1,8 +1,78 @@
|
|||||||
from humps import camelize
|
from datetime import datetime
|
||||||
|
|
||||||
from utils.model import BaseConfig, BaseModel
|
# noinspection PyPep8Naming
|
||||||
|
from enum import Enum as E
|
||||||
|
from typing import Any, TYPE_CHECKING, Type
|
||||||
|
|
||||||
|
from databases import Database
|
||||||
|
|
||||||
|
# noinspection PyPep8Naming
|
||||||
|
from ormar import (
|
||||||
|
BaseField,
|
||||||
|
Enum as ENUM,
|
||||||
|
Model as _Model,
|
||||||
|
ModelMeta as _ModelMeta,
|
||||||
|
String as STRING,
|
||||||
|
)
|
||||||
|
from sqlalchemy import MetaData
|
||||||
|
|
||||||
|
from utils import json
|
||||||
|
|
||||||
|
try:
|
||||||
|
import regex as re
|
||||||
|
except ImportError:
|
||||||
|
import re
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
pass
|
||||||
|
|
||||||
|
__all__ = ("Model", "String", "Enum")
|
||||||
|
|
||||||
|
DATABASE_URL = "sqlite:///data/db.sqlite"
|
||||||
|
database = Database(DATABASE_URL)
|
||||||
|
metadata = MetaData()
|
||||||
|
|
||||||
|
|
||||||
class DataModel(BaseModel):
|
class ModelMeta(_ModelMeta):
|
||||||
class Config(BaseConfig):
|
database = database
|
||||||
alias_generator = lambda x: camelize(x.removesuffix("TextHashMap"))
|
metadata = metadata
|
||||||
|
|
||||||
|
|
||||||
|
class Model(_Model):
|
||||||
|
class Config(_Model.Config):
|
||||||
|
json_dumps = json.dumps
|
||||||
|
json_loads = json.loads
|
||||||
|
json_encoders = {datetime: lambda v: v.timestamp()}
|
||||||
|
|
||||||
|
|
||||||
|
class String(STRING):
|
||||||
|
def __new__(
|
||||||
|
cls,
|
||||||
|
*,
|
||||||
|
max_length: int = 255,
|
||||||
|
min_length: int = None,
|
||||||
|
regex: str = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
) -> BaseField:
|
||||||
|
return super().__new__(
|
||||||
|
cls=STRING,
|
||||||
|
max_length=max_length,
|
||||||
|
min_length=min_length,
|
||||||
|
regex=regex,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Enum(ENUM):
|
||||||
|
def __new__(cls, enum_class: Type[E], **kwargs: Any) -> BaseField:
|
||||||
|
return super().__new__(
|
||||||
|
cls,
|
||||||
|
**{
|
||||||
|
**kwargs,
|
||||||
|
**{
|
||||||
|
k: v
|
||||||
|
for k, v in locals().items()
|
||||||
|
if k not in ["cls", "__class__", "kwargs"]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
2
model/avatar/__init__.py
Normal file
2
model/avatar/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from model.avatar._avatar import *
|
||||||
|
from model.avatar._talente import *
|
@ -6,6 +6,16 @@ from utils.model import BaseModel
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from model.item import Item
|
from model.item import Item
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"Avatar",
|
||||||
|
"AvatarBirth",
|
||||||
|
"AvatarInfo",
|
||||||
|
"AvatarConstellation",
|
||||||
|
"AvatarPromote",
|
||||||
|
"Seuyu",
|
||||||
|
"ItemCount",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class AvatarBirth(BaseModel):
|
class AvatarBirth(BaseModel):
|
||||||
"""角色生日"""
|
"""角色生日"""
|
||||||
@ -46,7 +56,7 @@ class AvatarInfo(BaseModel):
|
|||||||
"""声优"""
|
"""声优"""
|
||||||
|
|
||||||
|
|
||||||
class AvatarItem(BaseModel):
|
class ItemCount(BaseModel):
|
||||||
item: "Item"
|
item: "Item"
|
||||||
"""物品"""
|
"""物品"""
|
||||||
count: int
|
count: int
|
||||||
@ -63,43 +73,10 @@ class AvatarPromote(BaseModel):
|
|||||||
|
|
||||||
coin: int = 0
|
coin: int = 0
|
||||||
"""摩拉"""
|
"""摩拉"""
|
||||||
items: list[AvatarItem]
|
items: list[ItemCount] = []
|
||||||
"""突破所需材料"""
|
"""突破所需材料"""
|
||||||
|
|
||||||
|
|
||||||
class AvatarSkill(BaseModel):
|
|
||||||
name: str
|
|
||||||
"""技能名称"""
|
|
||||||
description: str
|
|
||||||
"""技能描述"""
|
|
||||||
promote_level: int = 0
|
|
||||||
"""所需突破等级"""
|
|
||||||
icon: str
|
|
||||||
"""图标"""
|
|
||||||
|
|
||||||
|
|
||||||
class AvatarActiveSkill(AvatarSkill):
|
|
||||||
"""角色主动技能"""
|
|
||||||
|
|
||||||
CD: float
|
|
||||||
"""冷却时间"""
|
|
||||||
max_charge_num: int
|
|
||||||
"""技能最大储存次数"""
|
|
||||||
|
|
||||||
|
|
||||||
class AvatarPassiveSkill(AvatarSkill):
|
|
||||||
"""角色被动技能"""
|
|
||||||
|
|
||||||
|
|
||||||
class AvatarSkills(BaseModel):
|
|
||||||
attack_skill: AvatarActiveSkill
|
|
||||||
"""普通攻击"""
|
|
||||||
energy_skill: AvatarActiveSkill
|
|
||||||
"""元素爆发"""
|
|
||||||
proud_skills: list[AvatarSkill]
|
|
||||||
"""被动技能"""
|
|
||||||
|
|
||||||
|
|
||||||
class AvatarConstellation(BaseModel):
|
class AvatarConstellation(BaseModel):
|
||||||
"""角色命座"""
|
"""角色命座"""
|
||||||
|
|
103
model/avatar/_talente.py
Normal file
103
model/avatar/_talente.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
from utils.model import BaseModel
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"Talent",
|
||||||
|
"CombatTalent",
|
||||||
|
"NormalAttack",
|
||||||
|
"ElementalBurst",
|
||||||
|
"ElementalSkill",
|
||||||
|
"AlternateSprint",
|
||||||
|
"PassiveTalent",
|
||||||
|
"AscensionPassive",
|
||||||
|
"FirstAscensionPassive",
|
||||||
|
"FourthAscensionPassive",
|
||||||
|
"UtilityPassive",
|
||||||
|
"MiscellaneousPassive",
|
||||||
|
"AvatarTalents",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Talent(BaseModel):
|
||||||
|
name: str
|
||||||
|
"""天赋名称"""
|
||||||
|
description: str
|
||||||
|
"""天赋描述"""
|
||||||
|
icon: str
|
||||||
|
"""图标"""
|
||||||
|
level: int = 0
|
||||||
|
"""解锁等级"""
|
||||||
|
|
||||||
|
params: list[float] = []
|
||||||
|
"""数值参数列表"""
|
||||||
|
|
||||||
|
|
||||||
|
class CombatTalent(Talent):
|
||||||
|
"""战斗天赋"""
|
||||||
|
|
||||||
|
cooldown: float = 0
|
||||||
|
"""冷却时间"""
|
||||||
|
|
||||||
|
|
||||||
|
class NormalAttack(CombatTalent):
|
||||||
|
"""普通攻击"""
|
||||||
|
|
||||||
|
|
||||||
|
class ElementalSkill(CombatTalent):
|
||||||
|
"""元素战技"""
|
||||||
|
|
||||||
|
|
||||||
|
class ElementalBurst(CombatTalent):
|
||||||
|
"""元素爆发"""
|
||||||
|
|
||||||
|
|
||||||
|
class AlternateSprint(CombatTalent):
|
||||||
|
"""冲刺技能"""
|
||||||
|
|
||||||
|
|
||||||
|
class PassiveTalent(Talent):
|
||||||
|
"""被动天赋"""
|
||||||
|
|
||||||
|
|
||||||
|
class AscensionPassive(PassiveTalent):
|
||||||
|
"""突破被动天赋"""
|
||||||
|
|
||||||
|
ascension: ClassVar[int]
|
||||||
|
|
||||||
|
|
||||||
|
class FirstAscensionPassive(AscensionPassive):
|
||||||
|
"""第一次突破被动天赋"""
|
||||||
|
|
||||||
|
ascension = 1
|
||||||
|
|
||||||
|
|
||||||
|
class FourthAscensionPassive(AscensionPassive):
|
||||||
|
"""第四次突破被动天赋"""
|
||||||
|
|
||||||
|
ascension = 4
|
||||||
|
|
||||||
|
|
||||||
|
class UtilityPassive(PassiveTalent):
|
||||||
|
"""实用被动天赋"""
|
||||||
|
|
||||||
|
|
||||||
|
class MiscellaneousPassive(PassiveTalent):
|
||||||
|
"""杂项被动天赋"""
|
||||||
|
|
||||||
|
|
||||||
|
class AvatarTalents(BaseModel):
|
||||||
|
"""角色天赋"""
|
||||||
|
|
||||||
|
normal_attack: NormalAttack
|
||||||
|
"""普通攻击"""
|
||||||
|
elemental_skill: ElementalSkill
|
||||||
|
"""元素战技"""
|
||||||
|
elemental_burst: ElementalBurst
|
||||||
|
"""元素爆发"""
|
||||||
|
alternate_sprint: AlternateSprint | None = None
|
||||||
|
"""冲刺技能"""
|
||||||
|
|
||||||
|
first_ascension_passive: FirstAscensionPassive
|
||||||
|
fourth_ascension_passive: FourthAscensionPassive
|
||||||
|
utility_passive: UtilityPassive | None = None
|
||||||
|
miscellaneous_passive: MiscellaneousPassive | None = None
|
@ -1,7 +1,7 @@
|
|||||||
from model.enums import ItemType, MaterialType
|
from model.enums import ItemType, MaterialType
|
||||||
|
|
||||||
from model.enums import FoodQuality
|
from model.enums import FoodQuality
|
||||||
from utils.model import BaseModel
|
from model._base import Model as BaseModel
|
||||||
|
|
||||||
|
|
||||||
class Item(BaseModel):
|
class Item(BaseModel):
|
||||||
@ -9,8 +9,6 @@ class Item(BaseModel):
|
|||||||
"""ID"""
|
"""ID"""
|
||||||
name: str
|
name: str
|
||||||
"""名称"""
|
"""名称"""
|
||||||
family: str
|
|
||||||
"""种类"""
|
|
||||||
type: str | None
|
type: str | None
|
||||||
"""类型"""
|
"""类型"""
|
||||||
icon: str
|
icon: str
|
||||||
|
89
run.py
89
run.py
@ -1,98 +1,21 @@
|
|||||||
import asyncio
|
from scripts.avatar import parse_avatar_data
|
||||||
|
from scripts.item import parse_item_data
|
||||||
from model.enums import ItemType, MaterialType
|
|
||||||
from model.item import Material, Namecard
|
|
||||||
from utils.const import PROJECT_ROOT
|
|
||||||
from utils.context import ContextManager
|
|
||||||
from utils.manager import ResourceManager
|
|
||||||
from utils.text import Text
|
|
||||||
from utils.typedefs import Lang
|
from utils.typedefs import Lang
|
||||||
import ujson as json
|
|
||||||
|
|
||||||
OUTPUT_DIR = PROJECT_ROOT / "data"
|
|
||||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyShadowingBuiltins
|
async def parse(lang: Lang):
|
||||||
async def parse_item_data(resource: ResourceManager):
|
await parse_item_data(lang)
|
||||||
from model.item import Food, FoodQuality, Item
|
await parse_avatar_data(lang)
|
||||||
|
|
||||||
json_data = resource.fetch("MaterialExcelConfigData")
|
|
||||||
data_list = []
|
|
||||||
|
|
||||||
for item_data in json_data:
|
|
||||||
id = item_data["id"]
|
|
||||||
name = Text(item_data["nameTextMapHash"])
|
|
||||||
family = item_data.get("materialType", "")
|
|
||||||
rarity = item_data.get("rankLevel")
|
|
||||||
type = Text(item_data["typeDescTextMapHash"])
|
|
||||||
icon = item_data["icon"]
|
|
||||||
description = Text(item_data["descTextMapHash"])
|
|
||||||
special = Text(item_data["specialDescTextMapHash"]) or None
|
|
||||||
item_type = ItemType(item_data["itemType"].removeprefix("ITEM_"))
|
|
||||||
|
|
||||||
base_kwargs = {
|
|
||||||
"id": id,
|
|
||||||
"name": name,
|
|
||||||
"family": family,
|
|
||||||
"rarity": rarity,
|
|
||||||
"type": type,
|
|
||||||
"icon": icon,
|
|
||||||
"description": description,
|
|
||||||
"item_type": item_type,
|
|
||||||
}
|
|
||||||
if special is not None:
|
|
||||||
base_kwargs["special_description"] = special
|
|
||||||
|
|
||||||
if pics := list(filter(lambda x: x, item_data["picPath"])):
|
|
||||||
item = Namecard(pictures=pics, **base_kwargs)
|
|
||||||
elif "materialType" in item_data: # 材料
|
|
||||||
material_type = MaterialType(
|
|
||||||
item_data["materialType"].removeprefix("MATERIAL_")
|
|
||||||
)
|
|
||||||
item = Material(material_type=material_type, **base_kwargs)
|
|
||||||
elif "foodQuality" in item_data: # 食物
|
|
||||||
quality = FoodQuality(
|
|
||||||
item_data["foodQuality"].removeprefix("FOOD_QUALITY_").title()
|
|
||||||
)
|
|
||||||
effect = Text(item_data["effectDescTextMapHash"])
|
|
||||||
item = Food(quality=quality, effect=effect, **base_kwargs)
|
|
||||||
else:
|
|
||||||
item = Item(**base_kwargs)
|
|
||||||
data_list.append(item.dict(exclude_none=True))
|
|
||||||
|
|
||||||
item_data_file = OUTPUT_DIR / "item.json"
|
|
||||||
with open(item_data_file, "w", encoding="utf-8") as f:
|
|
||||||
f.write(json.dumps(data_list, ensure_ascii=False))
|
|
||||||
breakpoint()
|
|
||||||
|
|
||||||
|
|
||||||
async def fetch_parse_data(lang: Lang):
|
|
||||||
with ContextManager().with_context(
|
|
||||||
"resource_manager", ResourceManager(lang=lang)
|
|
||||||
) as resource_manager:
|
|
||||||
try:
|
|
||||||
await parse_item_data(resource_manager)
|
|
||||||
except Exception as e:
|
|
||||||
breakpoint()
|
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
task_list = []
|
|
||||||
for lang in Lang.__args__:
|
for lang in Lang.__args__:
|
||||||
task = asyncio.create_task(fetch_parse_data(lang=lang))
|
await parse(lang)
|
||||||
task_list.append(task)
|
|
||||||
await asyncio.gather(*task_list)
|
|
||||||
|
|
||||||
|
|
||||||
def __main__():
|
def __main__():
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if (3, 10) >= sys.version_info >= (3, 8) and sys.platform.startswith("win"):
|
|
||||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
|
||||||
|
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
loop.run_until_complete(main())
|
loop.run_until_complete(main())
|
||||||
|
|
||||||
|
0
scripts/__init__.py
Normal file
0
scripts/__init__.py
Normal file
44
scripts/_base.py
Normal file
44
scripts/_base.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import asyncio
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from asyncio import Task
|
||||||
|
|
||||||
|
targets: list["Target"] = []
|
||||||
|
|
||||||
|
|
||||||
|
class Target(ABC):
|
||||||
|
_task: Task | None = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def task(self) -> Task:
|
||||||
|
return self._task
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
targets.append(self)
|
||||||
|
|
||||||
|
async def __async_init__(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def __async_del__(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def run(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def _run(self) -> None:
|
||||||
|
await self.__async_init__()
|
||||||
|
await self.run()
|
||||||
|
await self.__async_del__()
|
||||||
|
|
||||||
|
async def run_in_background(self) -> Task:
|
||||||
|
self._task = asyncio.create_task(self._run())
|
||||||
|
return self._task
|
||||||
|
|
||||||
|
|
||||||
|
async def waiting_for_done():
|
||||||
|
task_list: list[Task] = []
|
||||||
|
for target in targets:
|
||||||
|
if target.task is not None and not target.task.done():
|
||||||
|
task_list.append(target.task)
|
||||||
|
|
||||||
|
await asyncio.gather(*task_list)
|
7
scripts/avatar.py
Normal file
7
scripts/avatar.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from utils.typedefs import Lang
|
||||||
|
|
||||||
|
from utils.manager import ResourceManager
|
||||||
|
|
||||||
|
|
||||||
|
async def parse_avatar_data(lang: Lang):
|
||||||
|
...
|
19
scripts/item.py
Normal file
19
scripts/item.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from model.enums import ItemType
|
||||||
|
from utils.manager import ResourceManager
|
||||||
|
from utils.typedefs import Lang
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyShadowingBuiltins
|
||||||
|
async def parse_item_data(lang: Lang):
|
||||||
|
manager = ResourceManager(lang=lang)
|
||||||
|
json_data = manager.fetch("MaterialExcelConfigData")
|
||||||
|
for data in json_data:
|
||||||
|
id = data["id"]
|
||||||
|
name = manager.get_text(data["nameTextMapHash"])
|
||||||
|
type = manager.get_text(data["typeDescTextMapHash"])
|
||||||
|
icon = data["icon"]
|
||||||
|
rarity = data["rankLevel"]
|
||||||
|
description = manager.get_text(data["descTextMapHash"])
|
||||||
|
special_description = manager.get_text(data["specialDescTextMapHash"])
|
||||||
|
item_type = ItemType(data["itemType"].removeprefix('ITEM_'))
|
||||||
|
breakpoint()
|
Loading…
Reference in New Issue
Block a user