production lines: resolve conveyor -> island placement mapping
The recipe conveyors (game_conveyor_<product>_epb) are placed as named child GameObjects in the island_* prefabs (islands_assets_all.bundle), NOT via energy_grid (power grid only) or any config asset. New extractor bundle/extract_conveyor_placements.py walks every island prefab and cross-references production_lines.json -> extracted/conveyor_placements.json. Result: Factorio (energyRods, 80mmT3Cannon, contactGrenades, armorPiercingRocket), Kaiserplatz (energyRods, 40mmT3Cannon), Demo_Wunderinsel (70mmT3Cannon), DeusExMashineSmall (computingModules, coralDust), testIsland(+Tramplers) (the 4 base test conveyors). Corrects the earlier "Armory = Sprengstofffabrik hosts explosives" guess: the LittleFactory/LittleFactoryArmory islands place NO recipe conveyors; grenades/rockets are on Factorio. Unplaced blueprints: explosiveSmall, mechanicalParts (+ the plural armorPiercingRockets, whose singular-named instance is on Factorio).
This commit is contained in:
101
bundle/extract_conveyor_placements.py
Normal file
101
bundle/extract_conveyor_placements.py
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Map each world island/location to the production-line conveyors placed on it.
|
||||
|
||||
The recipe-bearing conveyors (game_conveyor_<product>_epb) are placed as named child
|
||||
GameObjects inside the island_* prefabs in islands_assets_all.bundle (NOT via energy_grid,
|
||||
which is only the power grid, and NOT in any config/designed-environment asset). This walks
|
||||
every island prefab's Transform hierarchy, collects the conveyor instances (with local
|
||||
position), and cross-references each recipe conveyor against extracted/production_lines.json.
|
||||
|
||||
Writes extracted/conveyor_placements.json.
|
||||
"""
|
||||
import os, sys, json, UnityPy
|
||||
|
||||
BUNDLES = "/home/downloadpizza/sand_tools/bundles"
|
||||
PL = "/home/downloadpizza/sand_tools/extracted/production_lines.json"
|
||||
OUT = "/home/downloadpizza/sand_tools/extracted/conveyor_placements.json"
|
||||
|
||||
|
||||
def walk(go, seen, out):
|
||||
"""Yield (name, localPosition) for every descendant GameObject."""
|
||||
for c in go.m_Components:
|
||||
try:
|
||||
co = c.read()
|
||||
except Exception:
|
||||
continue
|
||||
if co.object_reader.type.name != "Transform":
|
||||
continue
|
||||
for ch in co.m_Children:
|
||||
try:
|
||||
tr = ch.read()
|
||||
cgo = tr.m_GameObject.read()
|
||||
except Exception:
|
||||
continue
|
||||
pid = cgo.object_reader.path_id
|
||||
if pid in seen:
|
||||
continue
|
||||
seen.add(pid)
|
||||
pos = getattr(tr, "m_LocalPosition", None)
|
||||
xyz = [round(pos.x, 2), round(pos.y, 2), round(pos.z, 2)] if pos else None
|
||||
out.append((getattr(cgo, "m_Name", "?"), xyz))
|
||||
walk(cgo, seen, out)
|
||||
|
||||
|
||||
def main():
|
||||
pl = json.load(open(PL))["production_lines"]
|
||||
env = UnityPy.load(os.path.join(BUNDLES, "islands_assets_all.bundle"))
|
||||
islands = {p.split("/")[-1].replace(".prefab", ""): obj
|
||||
for p, obj in env.container.items()
|
||||
if obj.type.name == "GameObject" and p.split("/")[-1].startswith("island_")}
|
||||
|
||||
result = {}
|
||||
placed_recipes = set()
|
||||
for iname in sorted(islands):
|
||||
acc = []
|
||||
walk(islands[iname].read(), set(), acc)
|
||||
recipe_conv = []
|
||||
unmatched = []
|
||||
infra = []
|
||||
for name, pos in acc:
|
||||
base = name.replace("_epb", "")
|
||||
# product conveyors are game_conveyor_<product> (underscore); the slot/switch/
|
||||
# out/in pieces are game_conveyorXxx (no underscore) = generic infrastructure.
|
||||
if base.startswith("game_conveyor_"):
|
||||
if base in pl:
|
||||
recipe_conv.append({"conveyor": base, "pos": pos, "recipe": pl[base]})
|
||||
placed_recipes.add(base)
|
||||
else:
|
||||
unmatched.append({"conveyor": base, "pos": pos}) # placed, no recipe key (name mismatch?)
|
||||
elif name.startswith("game_conveyor"):
|
||||
infra.append(name)
|
||||
if recipe_conv or unmatched:
|
||||
result[iname] = {"recipes": recipe_conv,
|
||||
"product_conveyors_without_matching_recipe": unmatched,
|
||||
"infrastructure": sorted(set(infra))}
|
||||
|
||||
unplaced = sorted(set(pl) - placed_recipes)
|
||||
out = {
|
||||
"_source": "islands_assets_all.bundle island_* prefab hierarchy "
|
||||
"(game_conveyor_<product>_epb child GameObjects); recipes from production_lines.json",
|
||||
"_unplaced_recipes": unplaced,
|
||||
"islands": result,
|
||||
}
|
||||
json.dump(out, open(OUT, "w"), indent=1)
|
||||
|
||||
def fmt(r):
|
||||
i = " + ".join("%sx %s" % (x["amount"], x["itemId"]) for x in r["inputs"])
|
||||
o = " + ".join("%sx %s" % (x["amount"], x["itemId"]) for x in r["outputs"])
|
||||
return "%s -> %s (%ss)" % (i, o, r["craftTimeSeconds"])
|
||||
|
||||
print("wrote %s\n" % OUT)
|
||||
for iname, d in result.items():
|
||||
print("### %s" % iname.replace("island_", ""))
|
||||
for rc in d["recipes"]:
|
||||
print(" %-34s %s" % (rc["conveyor"].replace("game_conveyor_", ""), fmt(rc["recipe"])))
|
||||
for u in d["product_conveyors_without_matching_recipe"]:
|
||||
print(" %-34s (placed, no recipe blueprint of this exact name)" % u["conveyor"].replace("game_conveyor_", ""))
|
||||
print("\nrecipe blueprints NOT placed on any island:", unplaced)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user