🐛 fix some bugs

This commit is contained in:
Karako 2023-05-02 22:21:08 +08:00
parent 7cb30c4b04
commit ea67d86f4b
No known key found for this signature in database
GPG Key ID: 5920831B0095D4A0
4 changed files with 323 additions and 192 deletions

View File

@ -1,12 +1,8 @@
from typing import TYPE_CHECKING
from model.avatar._talente import AvatarTalents
from model.enums import Association, AvatarQuality, Element, WeaponType
from model.other import ItemCount
from utils.model import BaseModel
if TYPE_CHECKING:
from model.avatar._talente import AvatarTalents
__all__ = (
"Avatar",
"AvatarBirth",
@ -74,17 +70,17 @@ class AvatarStories(BaseModel):
story_5: Story
"""角色故事5"""
miscellaneous: Story
miscellaneous: Story | None = None
"""角色杂谈"""
vision: Story
vision: Story | None = None
"""神之眼"""
class AvatarInfo(BaseModel):
title: str
title: str | None
"""称号"""
birth: AvatarBirth
birth: AvatarBirth | None
"""生日"""
occupation: str
"""所属"""
@ -123,6 +119,8 @@ class AvatarConstellation(BaseModel):
"""命座描述"""
icon: str
"""命座图标"""
param_list: list[float]
"""命座数据参数列表"""
class AvatarAttribute(BaseModel):
@ -177,7 +175,7 @@ class Avatar(BaseModel):
"""角色信息"""
attributes: AvatarAttribute
"""角色基础属性"""
talents: "AvatarTalents"
talents: AvatarTalents
"""角色天赋信息"""
promotes: list[AvatarPromote]
"""角色突破数据"""

View File

@ -112,16 +112,16 @@ class AvatarTalents(BaseModel):
normal_attack: NormalAttack
"""普通攻击"""
elemental_skill: ElementalSkill
elemental_skill: ElementalSkill | None
"""元素战技"""
elemental_burst: ElementalBurst
elemental_burst: ElementalBurst | None
"""元素爆发"""
alternate_sprint: AlternateSprint | None = None
"""冲刺技能"""
first_ascension_passive: FirstAscensionPassive
first_ascension_passive: FirstAscensionPassive | None
"""第一次突破固有天赋"""
fourth_ascension_passive: FourthAscensionPassive
fourth_ascension_passive: FourthAscensionPassive | None
"""第四次突破固有天赋"""
utility_passive: UtilityPassive | None = None
"""实用固有天赋"""

View File

@ -1,10 +1,15 @@
from itertools import chain
from typing import TypeVar
import ujson as json
from aiofiles import open as async_open
from model.avatar import (
AlternateSprint,
Avatar,
AvatarAttribute,
AvatarBirth,
AvatarConstellation,
AvatarInfo,
AvatarPromote,
AvatarStories,
@ -26,6 +31,7 @@ from model.avatar import (
from model.enums import Association, AvatarQuality, Element, WeaponType
from model.other import ItemCount
from utils.const import PROJECT_ROOT
from utils.funcs import remove_rich_tag
from utils.manager import ResourceManager
from utils.typedefs import Lang
@ -38,20 +44,184 @@ TalentType = TypeVar("TalentType", bound=Talent)
OUT_DIR = PROJECT_ROOT.joinpath("out")
elements = {
3057990932: Element.Cryo,
467004516: Element.Anemo,
821712868: Element.Null,
2480172868: Element.Electro,
4022324356: Element.Hydro,
627825788: Element.Pyro,
2596397668: Element.Dendro,
967031460: Element.Geo,
elements_map = {
(
230082676,
313529204,
627825788,
1247335084,
1646245548,
1740638908,
3105283268,
3112476852,
3177381772,
3847511308,
): Element.Pyro,
(
321258364,
483165900,
756679372,
1688473500,
2480954540,
3228108484,
3400532572,
3646588372,
4022324356,
): Element.Hydro,
(
126875444,
467004516,
550531300,
898621369,
1778251796,
2075460644,
2477900860,
2648184060,
): Element.Anemo,
(
122554396,
608089036,
689445588,
1072755468,
1821644548,
1843086100,
2085306033,
2143937940,
2480172868,
2689029804,
3352621156,
4219874220,
): Element.Electro,
(2161032364, 4017448612): Element.Dendro,
(
98482612,
766902996,
862088588,
1480674860,
1695600284,
2778487532,
2809830820,
3057990932,
4127670180,
4220569804,
): Element.Cryo,
(
825986772,
967031460,
1016213980,
1662907292,
2507042785,
3219124204,
3617274620,
3929787020,
): Element.Geo,
(471154292, 821712868, 1128382182, 3053155130, 4168416172): Element.Null,
}
# noinspection PyShadowingBuiltins,SpellCheckingInspection
def get_skill_attributes(proud_skill_group_id: int) -> list[TalentAttribute]:
proud_skill_datas = sorted(
filter(
lambda x: x["proudSkillGroupId"] == proud_skill_group_id,
proud_skill_json_data,
),
key=lambda x: x["level"],
)
result: list[TalentAttribute] = []
for proud_skill_data in proud_skill_datas:
param_descriptions = list(
filter(
lambda x: x is not None,
map(
lambda x: manager.get_text(x),
proud_skill_data["paramDescList"],
),
)
)
param_num = len(param_descriptions)
for param_description in param_descriptions:
param_num = max(
param_num,
*map(int, re.findall(r"param(\d*)\:", param_description)),
)
result.append(
TalentAttribute(
level=proud_skill_data["level"],
param_descriptions=param_descriptions,
param_list=proud_skill_data["paramList"][:param_num],
break_level=proud_skill_data.get("breakLevel", 0),
coin=proud_skill_data.get("coinCost", 0),
cost_items=list(
map(
lambda x: ItemCount(item_id=x["id"], count=x["count"]),
filter(lambda x: x, proud_skill_data["costItems"]),
)
),
)
)
return result
def parse_skill(skill_id: int, skill_cls: type[CombatTalent]) -> CombatTalent:
skill_data = next(filter(lambda x: x["id"] == skill_id, skill_json_data))
_name = manager.get_text(skill_data["nameTextMapHash"])
_description = manager.get_text(skill_data["descTextMapHash"])
icon = skill_data["skillIcon"]
cooldown = (
skill_data.get("cdTime", 0) if "cooldown" in skill_cls.__fields__ else None
)
attributes = get_skill_attributes(skill_data["proudSkillGroupId"])
return skill_cls(
**{
i[0]: i[1]
for i in zip(
["name", "description", "icon", "cooldown", "attributes"],
[_name, _description, icon, cooldown, attributes],
)
if i is not None
}
)
def parse_passive_talent(
talent_data: dict, talent_cls: type[PassiveTalent]
) -> PassiveTalent:
group_id = talent_data["proudSkillGroupId"]
_promote_level = talent_data.get("needAvatarPromoteLevel", 0)
skill_data = next(
filter(lambda x: x["proudSkillGroupId"] == group_id, proud_skill_json_data)
)
param_descriptions = list(
filter(
lambda x: x is not None,
map(
lambda x: manager.get_text(x),
skill_data["paramDescList"],
),
)
)
_description = manager.get_text(skill_data["descTextMapHash"])
_param_list = skill_data["paramList"][
: len(re.findall(r"(\d+(?:\.)?\d+)", remove_rich_tag(_description) or ""))
]
return talent_cls(
name=manager.get_text(skill_data["nameTextMapHash"]) or "",
description=_description or "",
icon=skill_data["icon"],
promote_level=_promote_level,
attribute=TalentAttribute(
param_descriptions=param_descriptions,
param_list=_param_list,
break_level=skill_data.get("breakLevel", 0),
),
)
# noinspection PyShadowingBuiltins,SpellCheckingInspection,PyGlobalUndefined
async def parse_avatar_data(lang: Lang):
global out_path, manager
global avatar_json_data, fetter_info_json_data, story_json_data, promote_json_data
global skill_depot_json_data, skill_json_data, proud_skill_json_data, talent_json_data
out_path = OUT_DIR.joinpath(f"{lang}")
out_path.mkdir(exist_ok=True, parents=True)
@ -64,6 +234,7 @@ async def parse_avatar_data(lang: Lang):
skill_depot_json_data = manager.fetch("AvatarSkillDepotExcelConfigData")
skill_json_data = manager.fetch("AvatarSkillExcelConfigData")
proud_skill_json_data = manager.fetch("ProudSkillExcelConfigData")
talent_json_data = manager.fetch("AvatarTalentExcelConfigData")
avatar_list = []
for data in avatar_json_data:
@ -71,25 +242,36 @@ async def parse_avatar_data(lang: Lang):
if (
info_data := next(
chain(
filter(lambda x: x["avatarId"] == id, fetter_info_json_data),
[
None,
],
filter(lambda x: x["avatarId"] == id, fetter_info_json_data), [None]
)
)
) is None:
continue
name = manager.get_text(data["nameTextMapHash"])
element = elements[info_data["avatarVisionBeforTextMapHash"]]
quality = AvatarQuality(data["qualityType"].removeprefix("QUALITY_"))
element = next(
filter(
lambda x: info_data["avatarVisionBeforTextMapHash"] in x[0],
elements_map.items(),
)
)[1]
quality = AvatarQuality(
data["qualityType"].removeprefix("QUALITY_").replace("ORANGE_SP", "SPECIAL")
)
weapon_type = next(
filter(lambda x: x in data["weaponType"], WeaponType.__members__.values())
filter(
lambda x: x in data["weaponType"].replace("POLE", "POLEARM"),
WeaponType.__members__.values(),
)
)
# 角色信息
title = manager.get_text(info_data["avatarTitleTextMapHash"])
birth = AvatarBirth(
month=info_data["infoBirthMonth"], day=info_data["infoBirthDay"]
birth = (
AvatarBirth(
month=info_data["infoBirthMonth"], day=info_data["infoBirthDay"]
)
if id not in [10000005, 10000007]
else None
)
occupation = manager.get_text(info_data["avatarNativeTextMapHash"])
vision = manager.get_text(info_data["avatarVisionBeforTextMapHash"])
@ -106,36 +288,30 @@ async def parse_avatar_data(lang: Lang):
en=manager.get_text(info_data["cvEnglishTextMapHash"]),
kr=manager.get_text(info_data["cvKoreanTextMapHash"]),
)
story_data = sorted(
story_datas = sorted(
filter(lambda x: x["avatarId"] == id, story_json_data),
key=lambda x: x["fetterId"],
)
stories = AvatarStories(
**{
i[0]: i[1]
for i in zip(
AvatarStories.__fields__.keys(),
map(
lambda x: Story(
title=manager.get_text(x["storyTitleTextMapHash"]),
content=manager.get_text(x["storyContextTextMapHash"]),
tips=list(
filter(
lambda y: y is not None,
map(
lambda z: manager.get_text(z),
x["tips"],
),
)
),
),
sorted(
filter(lambda x: x["avatarId"] == id, story_data),
key=lambda x: x["fetterId"],
),
),
stories = []
for story_data in sorted(
filter(lambda x: x["avatarId"] == id, story_datas),
key=lambda x: x["fetterId"],
):
tips = list(
filter(
lambda x: x is not None,
map(lambda x: manager.get_text(x), story_data["tips"]),
)
}
)
story = Story(
title=manager.get_text(story_data["storyTitleTextMapHash"]),
content=manager.get_text(story_data["storyContextTextMapHash"]),
tips=tips,
)
stories.append(story)
avatar_stories = AvatarStories(
**{i[0]: i[1] for i in zip(AvatarStories.__fields__, stories)}
)
information = AvatarInfo(
title=title,
@ -146,11 +322,11 @@ async def parse_avatar_data(lang: Lang):
description=description,
association=association,
seuyu=seuyu,
stories=stories,
stories=avatar_stories,
)
# 角色基础属性
attribute = AvatarAttribute(
attributes = AvatarAttribute(
HP=data["hpBase"],
Attack=data["attackBase"],
Defense=data["defenseBase"],
@ -159,117 +335,6 @@ async def parse_avatar_data(lang: Lang):
ChargeEfficiency=data["chargeEfficiency"],
)
def get_skill_attributes(proud_skill_group_id: int) -> list[TalentAttribute]:
proud_skill_datas = sorted(
filter(
lambda x: x["proudSkillGroupId"] == proud_skill_group_id,
proud_skill_json_data,
),
key=lambda x: x["level"],
)
result: list[TalentAttribute] = []
for proud_skill_data in proud_skill_datas:
param_descriptions = list(
filter(
lambda x: x is not None,
map(
lambda x: manager.get_text(x),
proud_skill_data["paramDescList"],
),
)
)
param_num = len(param_descriptions)
for param_description in param_descriptions:
param_num = max(
param_num,
*map(int, re.findall(r"param(\d*)\:", param_description)),
)
result.append(
TalentAttribute(
level=proud_skill_data["level"],
param_descriptions=param_descriptions,
param_list=proud_skill_data["paramList"][:param_num],
break_level=proud_skill_data.get("breakLevel", 0),
coin=proud_skill_data.get("coinCost", 0),
cost_items=list(
map(
lambda x: ItemCount(
item_id=x["id"],
count=x["count"],
),
filter(lambda x: x, proud_skill_data["costItems"]),
)
),
)
)
return result
def parse_skill(skill_id: int, skill_cls: type[CombatTalent]) -> CombatTalent:
skill_data = next(filter(lambda x: x["id"] == skill_id, skill_json_data))
_name = manager.get_text(skill_data["nameTextMapHash"])
_description = manager.get_text(skill_data["descTextMapHash"])
icon = skill_data["skillIcon"]
cooldown = (
skill_data.get("cdTime", 0)
if "cooldown" in skill_cls.__fields__.keys()
else None
)
attributes = get_skill_attributes(skill_data["proudSkillGroupId"])
return skill_cls(
**{
i[0]: i[1]
for i in zip(
["name", "description", "icon", "cooldown", "attributes"],
[_name, _description, icon, cooldown, attributes],
)
if i is not None
}
)
def parse_passive_talent(
talent_data: dict, talent_cls: type[PassiveTalent]
) -> PassiveTalent:
group_id = talent_data["proudSkillGroupId"]
_promote_level = talent_data.get("needAvatarPromoteLevel", 0)
skill_data = next(
filter(
lambda x: x["proudSkillGroupId"] == group_id, proud_skill_json_data
)
)
param_descriptions = list(
filter(
lambda x: x is not None,
map(
lambda x: manager.get_text(x),
skill_data["paramDescList"],
),
)
)
_description = manager.get_text(skill_data["descTextMapHash"])
_param_list = skill_data["paramList"][
: len(
re.findall(
r"(\d+)|(?:(\d+)%)|(?:(\d+\.\d+))",
re.sub(
r"(<(?P<tag_name>[a-z]+?)=(?P<value>.+?)>.+</(?P=tag_name)>)",
"",
_description,
),
)
)
]
return talent_cls(
name=manager.get_text(skill_data["nameTextMapHash"]),
description=_description,
icon=skill_data["icon"],
promote_level=_promote_level,
attribute=TalentAttribute(
param_descriptions=param_descriptions,
param_list=_param_list,
break_level=skill_data.get("breakLevel", 0),
),
)
# 天赋
skill_depot_data = next(
filter(lambda x: x["id"] == data["skillDepotId"], skill_depot_json_data)
@ -278,36 +343,47 @@ async def parse_avatar_data(lang: Lang):
# 普通攻击
normal_attack = parse_skill(skill_ids[0], NormalAttack)
# 元素战技
elemental_skill = parse_skill(skill_ids[1], ElementalSkill)
elemental_skill = (
parse_skill(skill_ids[1], ElementalSkill)
if id not in [10000005, 10000007]
else None
)
# 冲刺技能
alternate_sprint = (
parse_skill(skill_ids[2], AlternateSprint) if len(skill_ids) == 3 else None
)
# 元素爆发
burst_skill = parse_skill(skill_depot_data["energySkill"], ElementalBurst)
burst_skill = (
parse_skill(skill_depot_data["energySkill"], ElementalBurst)
if id not in [10000005, 10000007]
else None
)
# 第一次突破被动天赋
first_passive = parse_passive_talent(
skill_depot_data["inherentProudSkillOpens"][0], FirstAscensionPassive
first_passive = (
parse_passive_talent(
skill_depot_data["inherentProudSkillOpens"][0], FirstAscensionPassive
)
if id not in [10000005, 10000007]
else None
)
# 第四次突破被动天赋
fourth_passive = parse_passive_talent(
skill_depot_data["inherentProudSkillOpens"][1], FourthAscensionPassive
fourth_passive = (
parse_passive_talent(
skill_depot_data["inherentProudSkillOpens"][1], FourthAscensionPassive
)
if id not in [10000005, 10000007]
else None
)
# 实用固有天赋
utility_passive = parse_passive_talent(
skill_depot_data["inherentProudSkillOpens"][2], UtilityPassive
utility_passive = (
parse_passive_talent(
skill_depot_data["inherentProudSkillOpens"][2], UtilityPassive
)
if id not in [10000005, 10000007]
else None
)
# 杂项固有天赋
if (
len(
list(
filter(
lambda x: x != 0, skill_depot_data["inherentProudSkillOpens"]
)
)
)
== 4
):
if skill_depot_data["inherentProudSkillOpens"][3]:
miscellaneous_passive = parse_passive_talent(
skill_depot_data["inherentProudSkillOpens"][3], MiscellaneousPassive
)
@ -335,7 +411,7 @@ async def parse_avatar_data(lang: Lang):
for promote_data in promote_datas:
items = []
for item_data in promote_data["costItems"]:
if item_data:
if item_data and id not in [10000005, 10000007]:
items.append(
ItemCount(item_id=item_data["id"], count=item_data["count"])
)
@ -347,4 +423,47 @@ async def parse_avatar_data(lang: Lang):
cost_items=items,
)
)
breakpoint()
# 角色命座信息
constellations: list[AvatarConstellation] = []
for constellation_id in filter(lambda x: x != 0, skill_depot_data["talents"]):
constellation_data = next(
filter(lambda x: x["talentId"] == constellation_id, talent_json_data)
)
constellation_description = manager.get_text(
constellation_data["descTextMapHash"]
)
# noinspection PyTypeChecker
constellations.append(
AvatarConstellation(
name=manager.get_text(constellation_data["nameTextMapHash"]),
description=constellation_description,
icon=constellation_data["icon"],
param_list=list(
filter(lambda x: x != 0.0, constellation_data["paramList"])
),
)
)
avatar = Avatar(
id=id,
name=name,
element=element,
quality=quality,
weapon_type=weapon_type,
information=information,
attributes=attributes,
talents=avatar_talents,
promotes=promotes,
constellations=constellations,
)
avatar_list.append(avatar)
async with async_open(out_path / "avatar.json", encoding="utf-8", mode="w") as file:
await file.write(
json.dumps(
[i.dict() for i in avatar_list],
ensure_ascii=False,
encode_html_chars=False,
indent=4,
),
)
return out_path, avatar_list

14
utils/funcs.py Normal file
View File

@ -0,0 +1,14 @@
try:
import regex as re
except ImportError:
import re
__all__ = ("remove_rich_tag",)
def remove_rich_tag(string: str | None) -> str:
"""去除富文本标签"""
if string is not None:
return re.sub(
r"(<(?P<tag_name>[a-z]+?)=(?P<value>.+?)>.+?</(?P=tag_name)>)", "", string
)