Files
Asset_Inspectors/loaders/material_loader.py
2025-12-30 00:25:33 -06:00

122 lines
3.6 KiB
Python

from .ikv_loader import parse_ikv_text, extract_handles_recursive
def try_load_material_from_bytes(data):
try:
txt = data.decode("utf-8", errors="strict")
except Exception:
try:
txt = data.decode("utf-8", errors="ignore")
except Exception:
return None
s = txt.lstrip()
if not (s.startswith("ikv1") or s.startswith("{") or s.startswith('"')):
return None
obj = parse_ikv_text(txt)
root_handle = None
if isinstance(obj, dict) and "ihandle" in obj and isinstance(obj["ihandle"], dict):
d = obj["ihandle"]
if all(k in d for k in ("value", "type", "meta")) and all(
isinstance(d[k], int) for k in ("value", "type", "meta")
):
v = int(d["value"]) & 0xFFFFFFFF
t = int(d["type"]) & 0xFFFF
m = int(d["meta"]) & 0xFFFF
if t != 0:
root_handle = (v, t, m)
refs = extract_handles_recursive(obj)
if root_handle is not None:
rk = root_handle[0] | (root_handle[1] << 32) | (root_handle[2] << 48)
refs = [h for h in refs if ((h[0] | (h[1] << 32) | (h[2] << 48)) != rk)]
info = {}
if isinstance(obj, dict):
if "shader_id" in obj:
info["shader_id"] = obj.get("shader_id")
if "flags" in obj:
info["flags"] = obj.get("flags")
return {
"handle": root_handle,
"refs": refs,
"obj": obj,
"info": info,
"text_len": len(txt),
}
def pack_value_from_index_gen(index, generation):
return ((int(generation) & 0xFFFF) << 16) | (int(index) & 0xFFFF)
def extract_handles_recursive(node):
out = []
def is_valid_triplet(v, t, m):
v = int(v) & 0xFFFFFFFF
t = int(t) & 0xFFFF
m = int(m) & 0xFFFF
if t == 0:
return False
return True
def maybe_add_value_type_meta(d):
if not isinstance(d, dict):
return
if "value" in d and "type" in d and "meta" in d:
v = d["value"]
t = d["type"]
m = d["meta"]
if isinstance(v, int) and isinstance(t, int) and isinstance(m, int):
if is_valid_triplet(v, t, m):
out.append((int(v) & 0xFFFFFFFF, int(t) & 0xFFFF, int(m) & 0xFFFF))
def maybe_add_index_gen(d):
if not isinstance(d, dict):
return
if "index" in d and "generation" in d and "type" in d and "meta" in d:
idx = d["index"]
gen = d["generation"]
t = d["type"]
m = d["meta"]
if (
isinstance(idx, int)
and isinstance(gen, int)
and isinstance(t, int)
and isinstance(m, int)
):
if (idx == 0 and gen == 0) or int(t) == 0:
return
v = pack_value_from_index_gen(idx, gen)
if is_valid_triplet(v, t, m):
out.append((int(v) & 0xFFFFFFFF, int(t) & 0xFFFF, int(m) & 0xFFFF))
def visit(x):
if isinstance(x, dict):
if "ihandle" in x and isinstance(x["ihandle"], dict):
maybe_add_value_type_meta(x["ihandle"])
maybe_add_index_gen(x["ihandle"])
maybe_add_value_type_meta(x)
maybe_add_index_gen(x)
for vv in x.values():
visit(vv)
elif isinstance(x, list):
for vv in x:
visit(vv)
visit(node)
seen = set()
uniq = []
for h in out:
k = h[0] | (h[1] << 32) | (h[2] << 48)
if k not in seen:
seen.add(k)
uniq.append(h)
return uniq