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.
108 lines
5.6 KiB
Python
108 lines
5.6 KiB
Python
"""Generate config/paxi/datapacks/onion-fixes from the audit findings.
|
|
Run from repo root after extract.py has built /tmp/onion/data.pkl."""
|
|
import json, os, pickle, shutil, copy
|
|
D = pickle.load(open("/tmp/onion/data.pkl", "rb"))
|
|
orig = {}
|
|
for jar, p, j in D["files"]:
|
|
orig.setdefault(p, {})[jar.split("-")[0]] = j
|
|
OUT = "config/paxi/datapacks/onion-fixes"
|
|
shutil.rmtree(OUT, ignore_errors=True)
|
|
def write(path, obj):
|
|
f = os.path.join(OUT, path)
|
|
os.makedirs(os.path.dirname(f), exist_ok=True)
|
|
with open(f, "w") as fh:
|
|
json.dump(obj, fh, indent=2); fh.write("\n")
|
|
def recipe(rid, obj):
|
|
ns, p = rid.split(":")
|
|
write(f"data/{ns}/recipe/{p}.json", obj)
|
|
def disable(rid):
|
|
recipe(rid, {"neoforge:conditions": [{"type": "neoforge:false"}]})
|
|
def src(path, mod):
|
|
return copy.deepcopy(orig[path][mod])
|
|
|
|
write("pack.mcmeta", {"pack": {"pack_format": 48,
|
|
"description": "Onion MC cross-mod recipe/tag fixes"}})
|
|
|
|
KNIFE = {"tag": "c:tools/knife"}
|
|
def cut(ing, out, n):
|
|
return {"type": "farmersdelight:cutting", "ingredients": [ing],
|
|
"result": [{"item": {"id": out, "count": n}}], "tool": KNIFE}
|
|
|
|
# 1. Potato: one board recipe per input, chained so each mod keeps its yield.
|
|
# potato -> 2 rustic slices (rustic's recipe, untouched)
|
|
# rustic slice -> 2 extradelight sliced potato (4/potato, as before)
|
|
# 2 rustic slices -> 1 moredelight diced potatoes (1/potato, as before;
|
|
# moredelight's Create saw recipe still gives 2/potato)
|
|
recipe("extradelight:cutting/sliced_potato",
|
|
cut({"item": "rusticdelight:potato_slices"}, "extradelight:sliced_potato", 2))
|
|
disable("moredelight:cutting/diced_potatoes")
|
|
recipe("onion:diced_potatoes_from_potato_slices", {
|
|
"type": "minecraft:crafting_shapeless", "category": "misc",
|
|
"ingredients": [{"item": "rusticdelight:potato_slices"}] * 2,
|
|
"result": {"id": "moredelight:diced_potatoes", "count": 1}})
|
|
# Slices are not whole potatoes (dupe loop via stews / re-cutting).
|
|
write("data/c/tags/item/crops/potato.json", {"replace": True, "values": [
|
|
"minecraft:potato", "veggiesdelight:sweet_potato",
|
|
{"id": "#forge:crops/potato", "required": False}]})
|
|
|
|
# 2. Bread: extradelight's slice wins; moredelight's sandwiches use c:bread_slices.
|
|
# Widen extradelight's input to c:foods/bread so cauliflower bread still slices.
|
|
r = src("data/extradelight/recipe/cutting/bread_knife.json", "extradelight")
|
|
r["ingredients"] = [{"tag": "c:foods/bread"}]
|
|
recipe("extradelight:cutting/bread_knife", r)
|
|
disable("moredelight:cutting/bread_slice")
|
|
|
|
# 3. Coffee: raw rustic beans are not roasted beans; crates use their own items.
|
|
write("data/c/tags/item/crops/coffee/cooked.json", {"replace": True, "values": [
|
|
"extradelight:coffee_beans", "rusticdelight:roasted_coffee_beans"]})
|
|
for rid, item in [("extradelight:coffee_cherries_to_block", "extradelight:coffee_cherries"),
|
|
("extradelight:coffee_beans_to_block", "extradelight:coffee_beans")]:
|
|
ns, p = rid.split(":")
|
|
r = src(f"data/{ns}/recipe/{p}.json", "extradelight")
|
|
r["ingredients"] = [{"item": item}] * 9
|
|
recipe(rid, r)
|
|
|
|
# 4. Twilight Forest knives: twilightdelight owns them; drop dungeonsdelight's copies.
|
|
for k in ["fiery_knife", "fiery_iron_knife", "ironwood_knife", "knightmetal_knife", "steeleaf_knife"]:
|
|
disable(f"dungeonsdelight:integration/twilightforest/crafting_table/{k}")
|
|
|
|
# 5. Crates: keep one crafting recipe per crate (uncrafting recipes untouched).
|
|
disable("minecraft:poisonous_potato_crate") # dungeonsdelight's; frightsdelight keeps it
|
|
disable("minecraft:rotten_tomato_crate") # dungeonsdelight's; frightsdelight keeps it
|
|
disable("fruitsdelight:apple_crate") # extradelight keeps it
|
|
disable("adorablehamsterpets:cucumber_crate") # extradelight's accepts any c:crops/cucumber
|
|
|
|
# 6. Handcrafted sheets: shapeless 3 wool collided with Comforts' vertical
|
|
# sleeping bags; make sheets a horizontal row.
|
|
COLORS = "white orange magenta light_blue yellow lime pink gray light_gray cyan purple blue brown green red black".split()
|
|
for c in COLORS:
|
|
r = src(f"data/handcrafted/recipe/{c}_sheet.json", "handcrafted")
|
|
recipe(f"handcrafted:{c}_sheet", {"type": "minecraft:crafting_shaped",
|
|
"category": r.get("category", "misc"), "key": {"#": r["ingredients"][0]},
|
|
"pattern": ["###"], "result": r["result"]})
|
|
|
|
# 7. Handcrafted wood plate (any 3 slabs in a row) shadowed all TF drying racks.
|
|
r = src("data/handcrafted/recipe/wood_plate.json", "handcrafted")
|
|
r["pattern"] = ["##"]
|
|
r["result"]["count"] = 2
|
|
recipe("handcrafted:wood_plate", r)
|
|
|
|
# 8. Fisherman's Haven worms can: one recipe, plus 1:1 worm conversions.
|
|
disable("fishermans_haven:recipe_worms_aquaculture")
|
|
for a, b in [("fishermans_haven:worm", "aquaculture:worm"), ("aquaculture:worm", "fishermans_haven:worm")]:
|
|
recipe(f"onion:{b.split(':')[0]}_worm_from_{a.split(':')[0]}_worm", {
|
|
"type": "minecraft:crafting_shapeless", "category": "misc",
|
|
"ingredients": [{"item": a}], "result": {"id": b, "count": 1}})
|
|
|
|
# 9. Twilight Delight ice creams need Neapolitan (absent): gate instead of log errors.
|
|
for k in ["rainbow_ice_cream", "refreshing_ice_cream", "twilight_ice_cream"]:
|
|
r = src(f"data/twilightdelight/recipe/{k}.json", "twilightdelight")
|
|
r = {"neoforge:conditions": [{"type": "neoforge:mod_loaded", "modid": "neapolitan"}], **r}
|
|
recipe(f"twilightdelight:{k}", r)
|
|
|
|
# 10. Beef stew: rustic replaces it, extradelight disables it -> load-order roulette.
|
|
# Pin rustic's version so the cooking pot recipe always exists.
|
|
recipe("farmersdelight:cooking/beef_stew",
|
|
src("data/farmersdelight/recipe/cooking/beef_stew.json", "rusticdelight"))
|
|
print("ok")
|