E服就是换个url…
json的hash都是一样的…
import os
import requests
import json
BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
BASE64_VALUES = [0] * 128
for idx, char in enumerate(BASE64_CHARS):
BASE64_VALUES[ord(char)] = idx
HEX_CHARS = list('0123456789abcdef')
_t = ['', '', '', '']
UUID_TEMPLATE = _t + _t + ['-'] + _t + ['-'] + _t + ['-'] + _t + ['-'] + _t + _t + _t
INDICES = [i for i, x in enumerate(UUID_TEMPLATE) if x != '-']
def decode_uuid(base64_str):
if len(base64_str) != 22:
return base64_str
result = UUID_TEMPLATE.copy()
result[0] = base64_str[0]
result[1] = base64_str[1]
j = 2
for i in range(2, 22, 2):
lhs = BASE64_VALUES[ord(base64_str[i])]
rhs = BASE64_VALUES[ord(base64_str[i + 1])]
result[INDICES[j]] = HEX_CHARS[lhs >> 2]
j += 1
result[INDICES[j]] = HEX_CHARS[((lhs & 3) << 2) | (rhs >> 4)]
j += 1
result[INDICES[j]] = HEX_CHARS[rhs & 0xF]
j += 1
return ''.join(result)
def has_sp_skeleton_data(obj):
if isinstance(obj, list):
if len(obj) > 0 and obj[0] == "sp.SkeletonData":
return obj
for item in obj:
found = has_sp_skeleton_data(item)
if found:
return found
elif isinstance(obj, dict):
for value in obj.values():
found = has_sp_skeleton_data(value)
if found:
return found
return None
def getspresjson(bundle):
url1 = "https://cpev.fhaqlbp.com/eow-jp-game/proj.confg.json"
response1 = requests.get(url1)
response1.raise_for_status()
data1 = response1.json()
special_value = data1.get("Config", {}).get(bundle)
if not special_value:
raise ValueError(f"无法获取 Config -> {bundle} 的值")
print(f"{bundle} = {special_value}")
url2 = f"https://cpev.fhaqlbp.com/eow-jp-game/bundle_sp/{bundle}/config.{special_value}.json"
response2 = requests.get(url2)
response2.raise_for_status()
return response2.json()
def getresjson(bundle):
url1 = "https://cpev.fhaqlbp.com/eow-jp-game/bundle/version.json"
response1 = requests.get(url1)
response1.raise_for_status()
data1 = response1.json()
anima_entry = next((item for item in data1 if item.get("abName") == bundle), None)
if not anima_entry:
raise ValueError(f"未找到 abName 为 '{bundle}' 的数据")
anima_version = anima_entry.get("version")
if not anima_version:
raise ValueError(f"{bundle} 的 version 字段为空")
print(f"anima version = {anima_version}")
url2 = f"https://cpev.fhaqlbp.com/eow-jp-game/bundle/{bundle}/cc.config.{anima_version}.json"
response2 = requests.get(url2)
response2.raise_for_status()
return response2.json()
def resdownloader(BASE, data,output_dir):
uuids = data["uuids"]
vers_imp = data["versions"]["import"]
vers_nat = data["versions"]["native"]
paths = data["paths"]
types = data["types"]
if "sp.SkeletonData" not in types:
print(f"[!] 未找到 sp.SkeletonData 数据")
return
SpriteFrameint = types.index("sp.SkeletonData")
vimp = {vers_imp[i]: vers_imp[i + 1] for i in range(0, len(vers_imp), 2)}
vnat = {vers_nat[i]: vers_nat[i + 1] for i in range(0, len(vers_nat), 2)}
os.makedirs(output_dir, exist_ok=True)
for idx, sid in enumerate(uuids):
if paths.get(str(idx)) and paths.get(str(idx))[1] == SpriteFrameint:
if '@' in sid:
uuid_base64, ext = sid.split('@', 1)
else:
uuid_base64, ext = sid, None
uuid = decode_uuid(uuid_base64)
full_uuid = f"{uuid}@{ext}" if ext else uuid
imp_ver = f".{vimp.get(idx, '')}"
nat_ver = f".{vnat.get(idx, '')}"
json_url = f"{BASE}/import/{uuid[:2]}/{full_uuid}{imp_ver}.json"
skel_url = f"{BASE}/native/{uuid[:2]}/{full_uuid}{nat_ver}.bin"
base_name = os.path.basename(paths[str(idx)][0])
print(f'json - {base_name}.json -> {json_url} | skel - {base_name}.skel -> {skel_url}')
try:
response = requests.get(json_url)
response.raise_for_status()
json_data = response.json()
except Exception as e:
print(f"[!] 下载失败: {json_url} ({e})")
continue
if not has_sp_skeleton_data(json_data):
continue
res_path = paths[str(idx)][0]
folder = os.path.join(output_dir, *res_path.split("/"))
os.makedirs(folder, exist_ok=True)
try:
sp_type_block = next(item for item in json_data[3] if item[0] == "sp.SkeletonData")
field_names = sp_type_block[1]
except Exception as e:
print(f"[!] 无法解析字段名: {e}")
continue
try:
obj_data = json_data[5][0]
field_values = obj_data[1:]
sp_dict = dict(zip(field_names, field_values))
_name = sp_dict.get("_name", base_name)
_atlasText = sp_dict.get("_atlasText", "")
_skeletonJson = sp_dict.get("_skeletonJson", None)
atlas_path = os.path.join(folder, f"{_name}.atlas")
if os.path.exists(atlas_path): #and not overwrite:
print(f"[!] 已存在 atlas,跳过:{_name}.atlas")
continue
with open(atlas_path, "w", encoding="utf-8") as f:
f.write(_atlasText)
print(f"[+] 写入 atlas 成功:{_name}.atlas")
if _skeletonJson:
json_path = os.path.join(folder, f"{_name}.json")
with open(json_path, "w", encoding="utf-8") as f:
json.dump(_skeletonJson, f, ensure_ascii=False, indent=2)
print(f"[+] 写入 skeletonJson 成功:{_name}.json")
else:
skel_path = os.path.join(folder, f"{_name}.skel")
with open("eroeowurl.txt", "a", encoding="utf-8") as f:
f.write(f"{skel_url}\n out={skel_path}\n")
pngdata = json_data[1]
for i, pngsid in enumerate(pngdata):
pnguuid = decode_uuid(pngsid[:22])
try:
idxpng = uuids.index(pngsid[:22])
nat_verpng = vnat[idxpng]
pngurl = f"{BASE}/native/{pnguuid[:2]}/{pnguuid}.{nat_verpng}.png"
png_tempname = f"{_name}_{i + 1}" if i >= 1 else f"{_name}"
png_path = os.path.join(folder, png_tempname + ".png")
print(f'{png_tempname}.png -> {pngurl}')
with open("eroeowurl.txt", "a", encoding="utf-8") as f:
f.write(f"{pngurl}\n out={png_path}\n")
except Exception as e:
print(f"[!] PNG处理失败: {e}")
except Exception as e:
print(f"[!] 解包 sp.SkeletonData 数据失败: {e}")
if os.path.exists("eroeowurl.txt"):
os.remove("eroeowurl.txt")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle_sp/normal",getspresjson('normal'),"resdownload\\EroLab幻能边境\\bundle_sp\\normal")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle_sp/spdata",getspresjson('spdata'),"resdownload\\EroLab幻能边境\\bundle_sp\\spdata")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle_sp/special",getspresjson('special'),"resdownload\\EroLab幻能边境\\bundle_sp\\special")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle_sp/special2",getspresjson('special2'),"resdownload\\EroLab幻能边境\\bundle_sp\\special2")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/anima",getresjson('anima'),"resdownload\\EroLab幻能边境\\bundle\\anima")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/activity",getresjson('activity'),"resdownload\\EroLab幻能边境\\bundle\\activity")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/barner",getresjson('barner'),"resdownload\\EroLab幻能边境\\bundle\\barner")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/battle",getresjson('battle'),"resdownload\\EroLab幻能边境\\bundle\\battle")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/bgs",getresjson('bgs'),"resdownload\\EroLab幻能边境\\bundle\\bgs")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/career",getresjson('career'),"resdownload\\EroLab幻能边境\\bundle\\career")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/cat",getresjson('cat'),"resdownload\\EroLab幻能边境\\bundle\\cat")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/dictionary",getresjson('dictionary'),"resdownload\\EroLab幻能边境\\bundle\\dictionary")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/mp4",getresjson('mp4'),"resdownload\\EroLab幻能边境\\bundle\\mp4")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/ornament",getresjson('ornament'),"resdownload\\EroLab幻能边境\\bundle\\ornament")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/sd",getresjson('sd'),"resdownload\\EroLab幻能边境\\bundle\\sd")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/sound",getresjson('sound'),"resdownload\\EroLab幻能边境\\bundle\\sound")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/texture",getresjson('texture'),"resdownload\\EroLab幻能边境\\bundle\\texture")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/vd",getresjson('vd'),"resdownload\\EroLab幻能边境\\bundle\\vd")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/icon",getresjson('icon'),"resdownload\\EroLab幻能边境\\bundle\\icon")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/maps",getresjson('maps'),"resdownload\\EroLab幻能边境\\bundle\\maps")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/normal",getresjson('normal'),"resdownload\\EroLab幻能边境\\bundle\\normal")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/special",getresjson('special'),"resdownload\\EroLab幻能边境\\bundle\\special")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/spdata",getresjson('spdata'),"resdownload\\EroLab幻能边境\\bundle\\spdata")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/special2",getresjson('special2'),"resdownload\\EroLab幻能边境\\bundle\\special2")
os.system("aria2c -i eroeowurl.txt -j 32 -s 16 -x 16 --check-certificate=false")