"""Study only (plain Python, no Blender): what stands in a region of a Season 1 demo map. python build/study_s1_dump.py x0 x1 y0 y1 [name-filter] """ import glob import json import math import os import sys KIT = r"D:\HADAL - The Descent\models\anchorage\kit_export" name, x0, x1, y0, y1 = sys.argv[1], float(sys.argv[2]), float(sys.argv[3]), float(sys.argv[4]), float(sys.argv[5]) flt = sys.argv[6] if len(sys.argv) > 6 else "" info = json.load(open(os.path.join(KIT, "meshes.json"), encoding="utf-8")) data = json.load(open(glob.glob(os.path.join(KIT, "maps", "*__%s.json" % name))[0], encoding="utf-8")) rows_out = [] for a in data["actors"]: if a.get("hidden") or a.get("hidden_in_game"): continue for m in a.get("meshes", []): rec = info.get(m["mesh"]) if rec is None or not m.get("visible", True): continue for rows in (m.get("instances") or [m["matrix"]]): X, Y, Z, W = rows lo = [1e9] * 3 hi = [-1e9] * 3 for cx in (rec["min"][0], rec["max"][0]): for cy in (rec["min"][1], rec["max"][1]): for cz in (rec["min"][2], rec["max"][2]): p = ((X[0] * cx + Y[0] * cy + Z[0] * cz + W[0]) / 100.0, -(X[1] * cx + Y[1] * cy + Z[1] * cz + W[1]) / 100.0, (X[2] * cx + Y[2] * cy + Z[2] * cz + W[2]) / 100.0) for i in range(3): lo[i] = min(lo[i], p[i]) hi[i] = max(hi[i], p[i]) c = [(lo[i] + hi[i]) / 2 for i in range(3)] if not (x0 <= c[0] <= x1 and y0 <= c[1] <= y1): continue nm = m["mesh"].split("/")[-1] if flt and flt not in nm: continue yaw = math.degrees(math.atan2(-X[1], X[0])) sc = [round(math.sqrt(sum(v * v for v in ax[:3])), 2) for ax in (X, Y, Z)] det = (X[0] * (Y[1] * Z[2] - Y[2] * Z[1]) - X[1] * (Y[0] * Z[2] - Y[2] * Z[0]) + X[2] * (Y[0] * Z[1] - Y[1] * Z[0])) defaults = [s["material"] for s in rec["slots"]] over = {i: mp.split("/")[-1] for i, mp in enumerate(m["materials"]) if i < len(defaults) and mp and mp != defaults[i]} rows_out.append((nm, [round(W[0] / 100, 2), round(-W[1] / 100, 2), round(W[2] / 100, 2)], round(yaw, 1), [round(v, 2) for v in lo], [round(v, 2) for v in hi], "" if sc == [1.0, 1.0, 1.0] and det > 0 else "s%s%s" % (sc, " MIRROR" if det < 0 else ""), over, m["mesh"].split("/")[3])) for l in a.get("lights", []): p = (l["matrix"][3][0] / 100, -l["matrix"][3][1] / 100, l["matrix"][3][2] / 100) if x0 <= p[0] <= x1 and y0 <= p[1] <= y1 and not flt: rows_out.append(("~LIGHT " + l["comp_class"].replace("Component", ""), [round(v, 2) for v in p], 0.0, [], [], "I=%s %s r=%s" % (l.get("intensity"), str(l.get("intensity_units", ""))[-12:], l.get("attenuation_radius")), {}, "")) for d in a.get("decals", []): p = (d["matrix"][3][0] / 100, -d["matrix"][3][1] / 100, d["matrix"][3][2] / 100) if x0 <= p[0] <= x1 and y0 <= p[1] <= y1 and not flt: rows_out.append(("~DECAL " + (d["material"] or "").split("/")[-1], [round(v, 2) for v in p], 0.0, [], [], str(d.get("size")), {}, "")) rows_out.sort(key=lambda r: (r[0], r[1])) print(len(rows_out), "items") for r in rows_out: print(" %-26s %-4s t %-22s yaw %6.1f lo %-22s hi %-22s %s %s" % (r[0], r[7][-4:], r[1], r[2], r[3], r[4], r[5], r[6] if r[6] else ""))