mirror of
https://github.com/PaiGramTeam/PaiGram.git
synced 2024-11-30 19:31:47 +00:00
260 lines
8.4 KiB
Python
260 lines
8.4 KiB
Python
from typing import TYPE_CHECKING, Dict, List, Any, Optional
|
|
|
|
from enkanetwork import Assets, CharacterStats
|
|
|
|
from utils.log import logger
|
|
|
|
if TYPE_CHECKING:
|
|
from simnet.models.genshin.chronicle.character_detail import (
|
|
GenshinDetailCharacters,
|
|
GenshinDetailCharacter,
|
|
PropertyValue,
|
|
DetailArtifact,
|
|
ArtifactProperty,
|
|
DetailCharacterWeapon,
|
|
)
|
|
|
|
|
|
class HashMapRev:
|
|
HASH_MAP_REV: Dict[str, Dict[str, str]] = {}
|
|
|
|
@classmethod
|
|
def get_hash_map(cls, name: str) -> Optional[str]:
|
|
cls.reload_assets()
|
|
for key in cls.HASH_MAP_REV:
|
|
if name in cls.HASH_MAP_REV[key]:
|
|
return cls.HASH_MAP_REV[key][name]
|
|
return ""
|
|
|
|
@classmethod
|
|
def get_artifacts_data(cls, artifact_id: int) -> Dict:
|
|
cls.reload_assets()
|
|
return Assets.DATA["artifacts"][str(artifact_id)]
|
|
|
|
@classmethod
|
|
def get_weapon_data(cls, weapon_id: int) -> Dict:
|
|
cls.reload_assets()
|
|
return Assets.DATA["weapons"][str(weapon_id)]
|
|
|
|
@classmethod
|
|
def reload_assets(cls) -> None:
|
|
# Load assets
|
|
if not Assets.HASH_MAP:
|
|
Assets.reload_assets()
|
|
if not cls.HASH_MAP_REV:
|
|
cls.HASH_MAP_REV = {key: {v["CHS"]: k for k, v in value.items()} for key, value in Assets.HASH_MAP.items()}
|
|
|
|
|
|
def get_prop_name_from_id(prop_id: int) -> str:
|
|
for k, v in CharacterStats.__fields__.items():
|
|
if v.default.id == prop_id:
|
|
return k
|
|
return ""
|
|
|
|
|
|
def get_equip_list_single_artifact_stats(data: "DetailArtifact") -> Dict:
|
|
main_stat = data.main_property
|
|
sub_stats = data.sub_property_list
|
|
|
|
def _get_stat(v: "ArtifactProperty", key: str) -> Dict:
|
|
return {
|
|
key: get_prop_name_from_id(v.property_type),
|
|
"statValue": float(v.value.replace("%", "")),
|
|
}
|
|
|
|
return {
|
|
"reliquaryMainstat": _get_stat(main_stat, "mainPropId"),
|
|
"reliquarySubstats": [_get_stat(v, "appendPropId") for v in sub_stats],
|
|
}
|
|
|
|
|
|
def get_equip_list_single_weapon_stats(data: "DetailCharacterWeapon") -> List[Dict]:
|
|
stats = [data.main_property]
|
|
if data.sub_property:
|
|
stats.append(data.sub_property)
|
|
|
|
def _get_stat(v: "PropertyValue") -> Dict:
|
|
return {
|
|
"appendPropId": get_prop_name_from_id(v.property_type),
|
|
"statValue": float(v.final.replace("%", "")),
|
|
}
|
|
|
|
return [_get_stat(v) for v in stats]
|
|
|
|
|
|
def get_equip_list_single_artifact(data: "DetailArtifact") -> Dict:
|
|
item_id = data.id
|
|
item_data = HashMapRev.get_artifacts_data(item_id)
|
|
reliquary = {
|
|
"appendPropIdList": [],
|
|
"level": data.level + 1,
|
|
}
|
|
flat = {
|
|
"equipType": item_data["equipType"],
|
|
"icon": item_data["icon"],
|
|
"itemType": item_data["itemType"],
|
|
"nameTextMapHash": str(item_data["nameTextMapHash"]),
|
|
"rankLevel": item_data["rankLevel"],
|
|
"setNameTextMapHash": HashMapRev.get_hash_map(data.set.name),
|
|
**get_equip_list_single_artifact_stats(data),
|
|
}
|
|
return {
|
|
"flat": flat,
|
|
"itemId": item_id,
|
|
"reliquary": reliquary,
|
|
}
|
|
|
|
|
|
def get_equip_list_single_weapon(data: "DetailCharacterWeapon") -> Dict:
|
|
item_id = data.id
|
|
item_data = HashMapRev.get_weapon_data(item_id)
|
|
weapon = {
|
|
"affixMap": {"0": data.refinement - 1},
|
|
"level": data.level,
|
|
"promoteLevel": data.ascension,
|
|
}
|
|
flat = {
|
|
"icon": item_data["icon"],
|
|
"itemType": "ITEM_WEAPON",
|
|
"nameTextMapHash": str(item_data["nameTextMapHash"]),
|
|
"rankLevel": item_data["rankLevel"],
|
|
"weaponStats": get_equip_list_single_weapon_stats(data),
|
|
}
|
|
return {
|
|
"flat": flat,
|
|
"itemId": item_id,
|
|
"weapon": weapon,
|
|
}
|
|
|
|
|
|
def get_equip_list_single(index: int, data: "GenshinDetailCharacter") -> Dict:
|
|
if index >= len(data.artifacts):
|
|
return get_equip_list_single_weapon(data.weapon)
|
|
return get_equip_list_single_artifact(data.artifacts[index])
|
|
|
|
|
|
def get_equip_list_loop(data: "GenshinDetailCharacter") -> List[Dict]:
|
|
return [get_equip_list_single(index, data) for index in range(len(data.artifacts) + 1)]
|
|
|
|
|
|
def get_fetter_info(data: "GenshinDetailCharacter") -> Dict[str, int]:
|
|
return {"expLevel": data.base.friendship}
|
|
|
|
|
|
def get_fight_prop_map(data: "GenshinDetailCharacter") -> Dict[str, float]:
|
|
f = []
|
|
f.extend(data.base_properties)
|
|
f.extend(data.extra_properties)
|
|
f.extend(data.element_properties)
|
|
f.sort(key=lambda k: k.property_type)
|
|
|
|
def _prop_to_value(v: "PropertyValue") -> float:
|
|
if "%" not in v.final:
|
|
return float(v.final)
|
|
return float(v.final.replace("%", "")) / 100
|
|
|
|
return {str(prop.property_type): _prop_to_value(prop) for prop in f}
|
|
|
|
|
|
def get_inherent_proud_skill_list(data: "GenshinDetailCharacter") -> List[int]:
|
|
return [(skill.id * 100 + 1) for skill in data.skills if skill.skill_type == 2]
|
|
|
|
|
|
def get_prop_map(data: "GenshinDetailCharacter") -> Dict[str, Dict[str, Any]]:
|
|
level = str(data.base.level)
|
|
return {
|
|
"1001": {"ival": "0", "type": 1001}, # XP
|
|
"1002": {"ival": "6", "type": 1002, "val": "6"}, # Ascension
|
|
"4001": {"ival": level, "type": 4001, "val": level}, # Level
|
|
}
|
|
|
|
|
|
def get_skill_depot_id(data: "GenshinDetailCharacter") -> int:
|
|
skill = data.skills[0]
|
|
skill_id = skill.id % 10
|
|
if data.base.id in [10000005, 10000007]:
|
|
skill_id += 1
|
|
skill_id_pre = (data.base.id - 10000000) * 100
|
|
return skill_id_pre + skill_id
|
|
|
|
|
|
def get_skill_level_map(data: "GenshinDetailCharacter", proud_skill_extra_level_map: Dict[str, int]) -> Dict:
|
|
_data = {}
|
|
for skill in data.skills:
|
|
if skill.skill_type != 1:
|
|
continue
|
|
|
|
_skill = Assets.skills(skill.id)
|
|
if not _skill:
|
|
continue
|
|
|
|
level = skill.level
|
|
if proud_skill_extra_level_map:
|
|
boost_level = proud_skill_extra_level_map.get(str(_skill.pround_map), None)
|
|
if boost_level is not None:
|
|
level -= boost_level
|
|
_data[str(skill.id)] = level
|
|
return _data
|
|
|
|
|
|
def get_talent_id_list(data: "GenshinDetailCharacter") -> List[int]:
|
|
return [constellation.id for constellation in data.constellations if constellation.activated]
|
|
|
|
|
|
def get_proud_skill_extra_level_map(avatar_id: int, talent_count: int) -> Dict[str, int]:
|
|
level_map = Assets.DATA["talents"].get(str(avatar_id), {})
|
|
data = {}
|
|
for k, v in level_map.items():
|
|
if talent_count >= int(k):
|
|
if talent_data := level_map.get(k):
|
|
data[str(talent_data["proud_skill_group_id"])] = talent_data["extra_level"]
|
|
return data
|
|
|
|
|
|
def from_simnet_to_enka_single(index: int, data: "GenshinDetailCharacters") -> Dict:
|
|
character = data.characters[index]
|
|
avatar_id = character.base.id
|
|
equip_list = get_equip_list_loop(character)
|
|
fetter_info = get_fetter_info(character)
|
|
fight_prop_map = get_fight_prop_map(character)
|
|
inherent_proud_skill_list = get_inherent_proud_skill_list(character)
|
|
prop_map = get_prop_map(character)
|
|
skill_depot_id = get_skill_depot_id(character)
|
|
talent_id_list = get_talent_id_list(character)
|
|
proud_skill_extra_level_map = get_proud_skill_extra_level_map(avatar_id, len(talent_id_list))
|
|
skill_level_map = get_skill_level_map(character, proud_skill_extra_level_map)
|
|
if not skill_level_map:
|
|
logger.warning("解析技能等级数据失败 ch_id[%s]", avatar_id)
|
|
return {}
|
|
return {
|
|
"avatarId": avatar_id,
|
|
"equipList": equip_list,
|
|
"fetterInfo": fetter_info,
|
|
"propMap": prop_map,
|
|
"talentIdList": talent_id_list,
|
|
"skillDepotId": skill_depot_id,
|
|
"inherentProudSkillList": inherent_proud_skill_list,
|
|
"fightPropMap": fight_prop_map,
|
|
"skillLevelMap": skill_level_map,
|
|
"proudSkillExtraLevelMap": proud_skill_extra_level_map,
|
|
}
|
|
|
|
|
|
def from_simnet_to_enka_loop(data: "GenshinDetailCharacters") -> List[Dict]:
|
|
d = []
|
|
for index, ch in enumerate(data.characters):
|
|
try:
|
|
if parsed_data := from_simnet_to_enka_single(index, data):
|
|
d.append(parsed_data)
|
|
except Exception as e:
|
|
cid = ch.base.id
|
|
logger.error("从 simnet 模型转换为 enka 模型时出现错误 cid[%s]", cid, exc_info=e)
|
|
logger.success("成功转换 %s 个角色", len(d))
|
|
return d
|
|
|
|
|
|
def from_simnet_to_enka(data: "GenshinDetailCharacters") -> Dict:
|
|
return {
|
|
"avatarInfoList": from_simnet_to_enka_loop(data),
|
|
}
|