Spaces:
Runtime error
Runtime error
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 | |
} | |
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) | |