"""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")