Everything the next agent needs to run the Phase 2 optimisation loop on a machine that can launch the client: - analysis/client-perf/: LEVERS (ranked levers + corrections), BENCH-MATRIX (world, scenes, config IDs, blocks B0-B14 with decision rules), PLAYER-TUNING, SPAWN-TUNING, research briefs, the jar scanner and its output, observed default configs, and proposed-configs/ (build.py generates tiers and bench variants and fails on unknown keys; apply_variant.py applies a variant and merges options.txt). - analysis/client-perf/bench/onion-bench/: bench-world datapack (scene teleports, Create grid, mob pen, sound storm, 120 s teleport tour). - analysis/audit/: the static recipe/dependency audit, including gen_fixes.py, which generates the shipped Paxi datapack and was never tracked. - phase0/: per-machine measurement harness (Steam Deck, 7700K/1060, 6700K/1080 Ti). - .pi/journal.md: running work log; read it first. All of it is packwizignored, so nothing here ships to players.
162 lines
7.3 KiB
Python
162 lines
7.3 KiB
Python
import pickle,json,collections,re,itertools
|
|
D=pickle.load(open("data.pkl","rb"))
|
|
mods=set(D["mods"])|{"minecraft","c","neoforge"}
|
|
files=D["files"]
|
|
# ---------- resource-level overrides ----------
|
|
byres=collections.defaultdict(list)
|
|
for jar,path,j in files: byres[path].append((jar,j))
|
|
legacy=collections.Counter()
|
|
for path,l in byres.items():
|
|
p=path.split("/")
|
|
if p[2]=="recipes" or (p[2]=="tags" and p[3] in("items","blocks")): legacy[l[0][0]]+=1
|
|
# ---------- tags ----------
|
|
def is_tag_path(p): return p[2]=="tags" and p[3]=="item"
|
|
tagdefs=collections.defaultdict(list) # tag -> [(jar, values, replace)]
|
|
for path,l in byres.items():
|
|
p=path.split("/")
|
|
if not is_tag_path(p): continue
|
|
tag=p[1]+":"+"/".join(p[4:])[:-5]
|
|
for jar,j in l:
|
|
if not isinstance(j,dict): continue
|
|
tagdefs[tag].append((jar,j.get("values",[]),j.get("replace",False)))
|
|
items=set()
|
|
for k in D["lang"]:
|
|
_,ns,pa=k.split("."); items.add(ns+":"+pa)
|
|
items|=D["models"]
|
|
def ns(x): return x.split(":")[0] if ":" in x else "minecraft"
|
|
def full(x): return x if ":" in x else "minecraft:"+x
|
|
tagcache={}; tagissues=[]
|
|
def resolve(tag,stack=()):
|
|
if tag in tagcache: return tagcache[tag]
|
|
if tag in stack: return set()
|
|
out=set()
|
|
for jar,vals,rep in tagdefs.get(tag,[]):
|
|
if rep: out=set()
|
|
for v in vals:
|
|
req=True
|
|
if isinstance(v,dict): req=v.get("required",True); v=v.get("id")
|
|
if not isinstance(v,str): continue
|
|
if v.startswith("#"):
|
|
t=full(v[1:])
|
|
if req and t not in tagdefs: tagissues.append((tag,jar,v,"missing-tag"))
|
|
out|=resolve(t,stack+(tag,))
|
|
else:
|
|
v=full(v)
|
|
if v not in items:
|
|
if req: tagissues.append((tag,jar,v,"missing-item" if ns(v) in mods else "missing-mod-item"))
|
|
continue
|
|
out.add(v)
|
|
tagcache[tag]=out; return out
|
|
for t in list(tagdefs): resolve(t)
|
|
# ---------- conditions ----------
|
|
unknown_cond=collections.Counter()
|
|
def cond(c):
|
|
if isinstance(c,list): return all(cond(x) for x in c)
|
|
t=c.get("type","")
|
|
if t in("neoforge:mod_loaded","forge:mod_loaded"): return c.get("modid") in mods
|
|
if t in("neoforge:not","forge:not"): return not cond(c["value"])
|
|
if t in("neoforge:and","forge:and"): return all(cond(x) for x in c["values"])
|
|
if t in("neoforge:or","forge:or"): return any(cond(x) for x in c["values"])
|
|
if t in("neoforge:item_exists","forge:item_exists"): return full(c["item"]) in items
|
|
if t in("neoforge:tag_empty","forge:tag_empty"): return not resolve(full(c["tag"]))
|
|
if t in("neoforge:true","forge:true"): return True
|
|
if t in("neoforge:false","forge:false"): return False
|
|
unknown_cond[t]+=1; return True
|
|
# ---------- ingredients ----------
|
|
def ing(x):
|
|
"""-> frozenset of items, or None if unknown type"""
|
|
if x is None: return frozenset()
|
|
if isinstance(x,str):
|
|
return frozenset(resolve(full(x[1:]))) if x.startswith("#") else frozenset([full(x)])
|
|
if isinstance(x,list):
|
|
s=set()
|
|
for y in x:
|
|
r=ing(y)
|
|
if r is None: return None
|
|
s|=r
|
|
return frozenset(s)
|
|
if isinstance(x,dict):
|
|
if "item" in x and isinstance(x["item"],str): return frozenset([full(x["item"])])
|
|
if "tag" in x: return frozenset(resolve(full(x["tag"])))
|
|
if "id" in x and "count" in x and isinstance(x["id"],str): return frozenset([full(x["id"])])
|
|
if "ingredient" in x: return ing(x["ingredient"])
|
|
t=x.get("type","")
|
|
if t in("neoforge:compound",): return ing(x.get("children"))
|
|
if t=="neoforge:components": return ing(x.get("items"))
|
|
if "items" in x: return ing(x["items"])
|
|
if t=="neoforge:difference":
|
|
b=ing(x.get("base")); s=ing(x.get("subtracted"))
|
|
return None if b is None or s is None else b-s
|
|
if t=="neoforge:intersection":
|
|
ch=[ing(c) for c in x.get("children",[])]
|
|
if None in ch or not ch: return None
|
|
return frozenset(set.intersection(*map(set,ch)))
|
|
return None
|
|
def result(j):
|
|
r=j.get("result")
|
|
if r is None: return None
|
|
if isinstance(r,str): return (full(r),1)
|
|
if isinstance(r,dict):
|
|
i=r.get("id") or r.get("item")
|
|
if isinstance(i,dict): i=i.get("id") or i.get("item")
|
|
return (full(i) if isinstance(i,str) else str(i), r.get("count",1))
|
|
if isinstance(r,list):
|
|
return tuple(sorted(result({"result":(e.get("item",e) if isinstance(e,dict) else e)}) + ((e.get("chance",1),) if isinstance(e,dict) else ()) for e in r))
|
|
return str(r)
|
|
# ---------- active recipes (last jar wins per path; note collisions) ----------
|
|
active={}; overrides=[]; missingrefs=[]
|
|
for path,l in byres.items():
|
|
p=path.split("/")
|
|
if p[2]!="recipe" or not path.endswith(".json"): continue
|
|
rid=p[1]+":"+"/".join(p[3:])[:-5]
|
|
live=[]
|
|
for jar,j in l:
|
|
if not isinstance(j,dict): continue
|
|
c=j.get("neoforge:conditions")
|
|
if c is not None and not cond(c): continue
|
|
live.append((jar,j))
|
|
if len(live)>1:
|
|
uniq={json.dumps(j,sort_keys=True) for _,j in live}
|
|
if len(uniq)>1: overrides.append((rid,[jr for jr,_ in live]))
|
|
if live: active[rid]=live[-1]
|
|
# cross-mod overrides of another namespace's recipes (single providing jar from other mod)
|
|
owner={}
|
|
for m,l in D["mods"].items():
|
|
for x in l: owner.setdefault(x["jar"].split("!")[0],set()).add(m)
|
|
foreign=collections.defaultdict(list)
|
|
for rid,(jar,j) in active.items():
|
|
n=ns(rid)
|
|
if n not in owner.get(jar,set()) and jar not in("base_minecraft.jar",) and n not in("c",):
|
|
foreign[(jar,n)].append(rid)
|
|
# ---------- unknown refs in active recipes ----------
|
|
def refs(o,acc):
|
|
if isinstance(o,dict):
|
|
for k,v in o.items():
|
|
if k in("item","id","tag") and isinstance(v,str) and k!="type": acc.append((k,v))
|
|
else: refs(v,acc)
|
|
elif isinstance(o,list):
|
|
for v in o: refs(v,acc)
|
|
return acc
|
|
for rid,(jar,j) in active.items():
|
|
if j.get("type","").startswith(("neoforge:","forge:")) and "conditional" in j.get("type",""): continue
|
|
for k,v in refs({kk:vv for kk,vv in j.items() if kk not in("neoforge:conditions",)},[]):
|
|
if k=="tag": continue
|
|
if ":" in v and ns(v) not in mods and not v.startswith("#"):
|
|
missingrefs.append((rid,jar,v)); break
|
|
pickle.dump(dict(active=active,tagcache=tagcache,items=items),open("active.pkl","wb"))
|
|
print("== legacy (pre-1.21 'recipes/' or 'tags/items/') files, inert ==")
|
|
for k,v in legacy.most_common(): print(f" {k}: {v}")
|
|
print("== recipe path collisions with differing content (load order decides) ==",len(overrides))
|
|
for r,js in overrides: print(" ",r,js)
|
|
print("== jars overriding another namespace's recipes ==")
|
|
for (jar,n),l in sorted(foreign.items(),key=lambda x:-len(x[1])): print(f" {jar} -> {n}: {len(l)} e.g. {l[:3]}")
|
|
print("== active recipes referencing items from absent mods (will fail to load) ==",len(missingrefs))
|
|
for x in missingrefs[:80]: print(" ",x)
|
|
print("== tag issues (required entry missing => whole tag fails to load) ==")
|
|
seen=set()
|
|
for t,jar,v,k in tagissues:
|
|
if (t,v) in seen: continue
|
|
seen.add((t,v)); print(" ",k,t,"<-",v,"from",jar)
|
|
print("== unknown condition types (assumed true) ==",dict(unknown_cond))
|
|
print("active recipes",len(active))
|