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

View File

@ -112,16 +112,16 @@ class AvatarTalents(BaseModel):
normal_attack: NormalAttack normal_attack: NormalAttack
"""普通攻击""" """普通攻击"""
elemental_skill: ElementalSkill elemental_skill: ElementalSkill | None
"""元素战技""" """元素战技"""
elemental_burst: ElementalBurst elemental_burst: ElementalBurst | None
"""元素爆发""" """元素爆发"""
alternate_sprint: AlternateSprint | None = 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 utility_passive: UtilityPassive | None = None
"""实用固有天赋""" """实用固有天赋"""

View File

@ -1,10 +1,15 @@
from itertools import chain from itertools import chain
from typing import TypeVar from typing import TypeVar
import ujson as json
from aiofiles import open as async_open
from model.avatar import ( from model.avatar import (
AlternateSprint, AlternateSprint,
Avatar,
AvatarAttribute, AvatarAttribute,
AvatarBirth, AvatarBirth,
AvatarConstellation,
AvatarInfo, AvatarInfo,
AvatarPromote, AvatarPromote,
AvatarStories, AvatarStories,
@ -26,6 +31,7 @@ from model.avatar import (
from model.enums import Association, AvatarQuality, Element, WeaponType from model.enums import Association, AvatarQuality, Element, WeaponType
from model.other import ItemCount from model.other import ItemCount
from utils.const import PROJECT_ROOT from utils.const import PROJECT_ROOT
from utils.funcs import remove_rich_tag
from utils.manager import ResourceManager from utils.manager import ResourceManager
from utils.typedefs import Lang from utils.typedefs import Lang
@ -38,20 +44,184 @@ TalentType = TypeVar("TalentType", bound=Talent)
OUT_DIR = PROJECT_ROOT.joinpath("out") OUT_DIR = PROJECT_ROOT.joinpath("out")
elements = { elements_map = {
3057990932: Element.Cryo, (
467004516: Element.Anemo, 230082676,
821712868: Element.Null, 313529204,
2480172868: Element.Electro, 627825788,
4022324356: Element.Hydro, 1247335084,
627825788: Element.Pyro, 1646245548,
2596397668: Element.Dendro, 1740638908,
967031460: Element.Geo, 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): 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 = OUT_DIR.joinpath(f"{lang}")
out_path.mkdir(exist_ok=True, parents=True) 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_depot_json_data = manager.fetch("AvatarSkillDepotExcelConfigData")
skill_json_data = manager.fetch("AvatarSkillExcelConfigData") skill_json_data = manager.fetch("AvatarSkillExcelConfigData")
proud_skill_json_data = manager.fetch("ProudSkillExcelConfigData") proud_skill_json_data = manager.fetch("ProudSkillExcelConfigData")
talent_json_data = manager.fetch("AvatarTalentExcelConfigData")
avatar_list = [] avatar_list = []
for data in avatar_json_data: for data in avatar_json_data:
@ -71,25 +242,36 @@ async def parse_avatar_data(lang: Lang):
if ( if (
info_data := next( info_data := next(
chain( chain(
filter(lambda x: x["avatarId"] == id, fetter_info_json_data), filter(lambda x: x["avatarId"] == id, fetter_info_json_data), [None]
[
None,
],
) )
) )
) is None: ) is None:
continue continue
name = manager.get_text(data["nameTextMapHash"]) name = manager.get_text(data["nameTextMapHash"])
element = elements[info_data["avatarVisionBeforTextMapHash"]] element = next(
quality = AvatarQuality(data["qualityType"].removeprefix("QUALITY_")) 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( 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"]) title = manager.get_text(info_data["avatarTitleTextMapHash"])
birth = AvatarBirth( birth = (
month=info_data["infoBirthMonth"], day=info_data["infoBirthDay"] AvatarBirth(
month=info_data["infoBirthMonth"], day=info_data["infoBirthDay"]
)
if id not in [10000005, 10000007]
else None
) )
occupation = manager.get_text(info_data["avatarNativeTextMapHash"]) occupation = manager.get_text(info_data["avatarNativeTextMapHash"])
vision = manager.get_text(info_data["avatarVisionBeforTextMapHash"]) 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"]), en=manager.get_text(info_data["cvEnglishTextMapHash"]),
kr=manager.get_text(info_data["cvKoreanTextMapHash"]), kr=manager.get_text(info_data["cvKoreanTextMapHash"]),
) )
story_data = sorted( story_datas = sorted(
filter(lambda x: x["avatarId"] == id, story_json_data), filter(lambda x: x["avatarId"] == id, story_json_data),
key=lambda x: x["fetterId"], key=lambda x: x["fetterId"],
) )
stories = AvatarStories( stories = []
**{ for story_data in sorted(
i[0]: i[1] filter(lambda x: x["avatarId"] == id, story_datas),
for i in zip( key=lambda x: x["fetterId"],
AvatarStories.__fields__.keys(), ):
map( tips = list(
lambda x: Story( filter(
title=manager.get_text(x["storyTitleTextMapHash"]), lambda x: x is not None,
content=manager.get_text(x["storyContextTextMapHash"]), map(lambda x: manager.get_text(x), story_data["tips"]),
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"],
),
),
) )
} )
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( information = AvatarInfo(
title=title, title=title,
@ -146,11 +322,11 @@ async def parse_avatar_data(lang: Lang):
description=description, description=description,
association=association, association=association,
seuyu=seuyu, seuyu=seuyu,
stories=stories, stories=avatar_stories,
) )
# 角色基础属性 # 角色基础属性
attribute = AvatarAttribute( attributes = AvatarAttribute(
HP=data["hpBase"], HP=data["hpBase"],
Attack=data["attackBase"], Attack=data["attackBase"],
Defense=data["defenseBase"], Defense=data["defenseBase"],
@ -159,117 +335,6 @@ async def parse_avatar_data(lang: Lang):
ChargeEfficiency=data["chargeEfficiency"], 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( skill_depot_data = next(
filter(lambda x: x["id"] == data["skillDepotId"], skill_depot_json_data) 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) 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 = ( alternate_sprint = (
parse_skill(skill_ids[2], AlternateSprint) if len(skill_ids) == 3 else None 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( first_passive = (
skill_depot_data["inherentProudSkillOpens"][0], FirstAscensionPassive parse_passive_talent(
skill_depot_data["inherentProudSkillOpens"][0], FirstAscensionPassive
)
if id not in [10000005, 10000007]
else None
) )
# 第四次突破被动天赋 # 第四次突破被动天赋
fourth_passive = parse_passive_talent( fourth_passive = (
skill_depot_data["inherentProudSkillOpens"][1], FourthAscensionPassive parse_passive_talent(
skill_depot_data["inherentProudSkillOpens"][1], FourthAscensionPassive
)
if id not in [10000005, 10000007]
else None
) )
# 实用固有天赋 # 实用固有天赋
utility_passive = parse_passive_talent( utility_passive = (
skill_depot_data["inherentProudSkillOpens"][2], UtilityPassive parse_passive_talent(
skill_depot_data["inherentProudSkillOpens"][2], UtilityPassive
)
if id not in [10000005, 10000007]
else None
) )
# 杂项固有天赋 # 杂项固有天赋
if ( if skill_depot_data["inherentProudSkillOpens"][3]:
len(
list(
filter(
lambda x: x != 0, skill_depot_data["inherentProudSkillOpens"]
)
)
)
== 4
):
miscellaneous_passive = parse_passive_talent( miscellaneous_passive = parse_passive_talent(
skill_depot_data["inherentProudSkillOpens"][3], MiscellaneousPassive skill_depot_data["inherentProudSkillOpens"][3], MiscellaneousPassive
) )
@ -335,7 +411,7 @@ async def parse_avatar_data(lang: Lang):
for promote_data in promote_datas: for promote_data in promote_datas:
items = [] items = []
for item_data in promote_data["costItems"]: for item_data in promote_data["costItems"]:
if item_data: if item_data and id not in [10000005, 10000007]:
items.append( items.append(
ItemCount(item_id=item_data["id"], count=item_data["count"]) ItemCount(item_id=item_data["id"], count=item_data["count"])
) )
@ -347,4 +423,47 @@ async def parse_avatar_data(lang: Lang):
cost_items=items, 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
)