Formulator / get_assets.py
AngoHF's picture
04.17 commit
b76daae
raw
history blame
9.66 kB
import json
import os
from functools import cache
import requests
from tqdm import tqdm
from qt.constant import MAX_BASE_ATTR, MAX_MAGIC_ATTR, MAX_EMBED_ATTR, MAX_ENCHANT_ATTR
from qt.constant import ATTR_TYPE_MAP, ATTR_TYPE_TRANSLATE
from qt.constant import MAX_STONE_ATTR, STONE_ATTR, MAX_STONE_LEVEL
from qt.constant import EQUIPMENTS_DIR, ENCHANTS_DIR, STONES_DIR
from utils.parser import SUPPORT_SCHOOL
KINDS = set(sum([[school.kind, school.major] for school in SUPPORT_SCHOOL.values()], []))
SCHOOLS = set(["精简", "通用"] + [school.school for school in SUPPORT_SCHOOL.values()])
EQUIP_ATTR_MAP = {
"Overcome": "破防",
"Critical": "会心",
"CriticalDamage": "会效",
"Haste": "加速",
"Surplus": "破招",
"Strain": "无双"
}
POSITION_MAP = {
"hat": 3,
"jacket": 2,
"belt": 6,
"wrist": 10,
"bottoms": 8,
"shoes": 9,
"necklace": 4,
"pendant": 7,
"ring": 5,
"tertiary_weapon": 1,
"primary_weapon": 0
}
SUFFIX_MAP = {
3: 'armor',
2: 'armor',
6: 'armor',
10: 'armor',
8: 'armor',
9: 'armor',
4: 'trinket',
7: 'trinket',
5: 'trinket',
1: 'weapon',
0: 'weapon'
}
SPECIAL_ENCHANT_MAP = {
3: {
14350: [15436, 12],
12800: [15436, 11],
11500: [15436, 10],
10600: [15436, 9]
},
2: {
14350: [22151, 12],
12800: [22151, 11],
11500: [22151, 10],
10600: [22151, 9]
},
6: {
0: 22169
},
10: {
0: 22166
},
9: {
0: 33247
}
}
equip_min_level = 12000
equip_params = {
"client": "std",
"pv_type": 1,
"pz": 1,
"page": 1,
"per": 300,
"min_level": 9000,
"max_level": 17000
}
enchant_params = {
"client": "std",
"subtype": 1,
"latest_enhance": 1
}
# @cache
def get_equips_list(position):
position_id = POSITION_MAP[position]
url = f"https://node.jx3box.com/equip/{SUFFIX_MAP[position_id]}"
params = equip_params.copy()
params['position'] = position_id
equips = []
res = requests.get(url, params=params).json()
equips.extend(res['list'])
while res['pages'] > params['page']:
params['page'] += 1
res = requests.get(url, params=params).json()
equips.extend(res['list'])
result = {get_equip_name(row): get_equip_detail(row) for row in reversed(equips) if
row['SubType'] != "0" or row['DetailType'] != "9"}
result = {k: v for k, v in result.items() if v['level'] >= equip_min_level or v['max_strength'] == 8}
result = {k: v for k, v in result.items() if v['kind'] in KINDS}
result = {k: v for k, v in result.items() if v['school'] in SCHOOLS}
return result
def get_secondary_weapons():
params = equip_params.copy()
params['position'] = 0
params['DetailType'] = 9
url = f"https://node.jx3box.com/equip/weapon"
equips = []
res = requests.get(url, params=params).json()
equips.extend(res['list'])
while res['pages'] > params['page']:
params['page'] += 1
res = requests.get(url, params=params).json()
equips.extend(res['list'])
result = {get_equip_name(row): get_equip_detail(row) for row in reversed(equips)}
result = {k: v for k, v in result.items() if v['level'] >= equip_min_level or v['max_strength'] == 8}
result = {k: v for k, v in result.items() if v['kind'] in KINDS}
result = {k: v for k, v in result.items() if v['school'] in SCHOOLS}
return result
def get_equip_name(row):
name = row['Name']
if "无封" in name:
name = f"{row['MagicKind']}{name}"
attrs = " ".join([EQUIP_ATTR_MAP[attr] for attr in EQUIP_ATTR_MAP if attr in row['_Attrs']])
level = row['Level']
return f"{name} ({attrs}) {level}"
def get_equip_detail(row):
base_attrs, magic_attrs, embed_attrs = {}, {}, {}
set_id, set_attr, set_gain = "", {}, {}
level = int(row['Level'])
special_enchant = []
gains = []
for i in range(MAX_BASE_ATTR):
if not (attr_type := row[f'Base{i + 1}Type']):
break
if attr_type not in ATTR_TYPE_MAP:
continue
base_attrs[ATTR_TYPE_MAP[attr_type]] = int(row[f'Base{i + 1}Max'])
for i in range(MAX_MAGIC_ATTR):
if not (attr := row[f'_Magic{i + 1}Type']):
break
attr = attr['attr']
if attr[0] in ATTR_TYPE_MAP:
magic_attrs[ATTR_TYPE_MAP[attr[0]]] = int(attr[1])
elif attr[0] in ["atSetEquipmentRecipe", "atSkillEventHandler"]:
gains.append(int(attr[1]))
else:
continue
for i in range(MAX_EMBED_ATTR):
if not (attr := row[f'_DiamondAttributeID{i + 1}']):
break
if attr[0] not in ATTR_TYPE_MAP:
continue
embed_attrs[ATTR_TYPE_MAP[attr[0]]] = int(attr[1])
for k, v in SPECIAL_ENCHANT_MAP.get(row['SubType'], {}).items():
if level > k:
special_enchant = v
break
if row["SkillID"]:
gains.append((int(row['SkillID']), int(row['SkillLevel'])))
if set_id := row['_SetAttrbs']:
set_id = set_id['UiID']
for k, v in row['_SetData'].items():
if not v:
continue
count = k.split("_")[0]
attr = v['attr']
if attr[0] in ATTR_TYPE_MAP:
if count not in set_attr:
set_attr[count] = {}
set_attr[count][ATTR_TYPE_MAP[attr[0]]] = int(attr[1])
elif attr[0] in ["atSetEquipmentRecipe", "atSkillEventHandler"]:
if count not in set_gain:
set_gain[count] = []
set_gain[count].append(int(attr[1]))
return {
"id": row["ID"],
"school": row['BelongSchool'],
"kind": row['MagicKind'],
"level": level,
"max_strength": int(row['MaxStrengthLevel']),
"base": base_attrs,
"magic": magic_attrs,
"embed": embed_attrs,
"gains": gains,
"special_enchant": special_enchant,
"set_id": set_id,
"set_attr": set_attr,
"set_gain": set_gain
}
@cache
def get_enchants_list(position):
position_id = POSITION_MAP[position]
url = f"https://node.jx3box.com/enchant/primary"
params = enchant_params.copy()
params['position'] = position_id
res = requests.get(url, params=params)
enchants = [e for e in sorted(res.json(), key=lambda x: x['Score'], reverse=True) if
e['Attribute1ID'] in ATTR_TYPE_MAP]
result = {get_enchant_name(row): get_enchant_detail(row) for row in enchants}
return result
def get_weapon_enchants():
return get_enchants_list("primary_weapon")
def get_enchant_name(row):
if not row:
return ""
name = row['Name']
attr = row['AttriName']
return f"{name} {attr}"
def get_enchant_detail(row):
attrs = {}
for i in range(MAX_ENCHANT_ATTR):
if not (attr_type := row[f'Attribute{i + 1}ID']):
break
if attr_type not in ATTR_TYPE_MAP:
continue
attrs[ATTR_TYPE_MAP[attr_type]] = int(row[f'Attribute{i + 1}Value1'])
return {
"id": row['ID'],
"score": row['Score'],
"attr": attrs
}
def get_stones_list():
url = "https://node.jx3box.com/enchant/stone"
result = {}
for level in tqdm(range(MAX_STONE_LEVEL)):
level = level + 1
stones = []
params = {
"client": "std",
"level": level,
"page": 1,
"per": 100
}
res = requests.get(url, params=params).json()
stones.extend(res['list'])
while res['pages'] > params['page']:
params['page'] += 1
res = requests.get(url, params=params).json()
stones.extend(res['list'])
for row in stones:
if detail := get_stone_detail(row):
current = result
for attr in detail['attr']:
if attr not in current:
current[attr] = {}
current = current[attr]
current[level] = detail
return result
def get_stone_name(row):
name = row['Name']
attrs = " ".join([ATTR_TYPE_TRANSLATE[ATTR_TYPE_MAP[attr]] for attr in row['_Attrs'] if attr in ATTR_TYPE_MAP])
return f"{name} ({attrs})"
def get_stone_detail(row):
attrs = {}
for i in range(MAX_STONE_ATTR):
if not (attr_type := row[f'Attribute{i + 1}ID']):
break
if attr_type not in STONE_ATTR:
return
attrs[ATTR_TYPE_MAP[attr_type]] = int(row[f'Attribute{i + 1}Value1'])
return {
"level": row['stone_level'],
"attr": attrs
}
if __name__ == '__main__':
if not os.path.exists(EQUIPMENTS_DIR):
os.makedirs(EQUIPMENTS_DIR)
if not os.path.exists(ENCHANTS_DIR):
os.makedirs(ENCHANTS_DIR)
for pos in tqdm(POSITION_MAP):
json.dump(
get_equips_list(pos),
open(os.path.join(EQUIPMENTS_DIR, pos), "w", encoding="utf-8"), ensure_ascii=False
)
json.dump(
get_enchants_list(pos),
open(os.path.join(ENCHANTS_DIR, pos), "w", encoding="utf-8"), ensure_ascii=False
)
json.dump(
get_secondary_weapons(), open(os.path.join(EQUIPMENTS_DIR, "secondary_weapon"), "w", encoding="utf-8"),
ensure_ascii=False)
json.dump(
get_weapon_enchants(), open(os.path.join(ENCHANTS_DIR, "secondary_weapon"), "w", encoding="utf-8")
)
json.dump(get_stones_list(), open(STONES_DIR, "w", encoding="utf-8"), ensure_ascii=False)