Definitive island prefab -> in-game name link: each island_* prefab has a child Landmark GameObject (LandmarkBehaviour.name) = the Toponym key, localized via i2 Toponyms/<name>. New bundle/extract_island_names.py -> extracted/island_names.json. Key results: Demo_Wunderinsel=Strudel, Demo_Marktinsel=Segen, Gartenfreude=Insel St. Clemens, DeusExMashineSmall=Rauchwolke, and island_Factorio = Sprengstofffabrik (the explosives factory). The LittleFactory/LittleFactoryArmory prefabs are the Forts. Updates docs/PRODUCTION_LINES.md with in-game names and corrects the earlier Sprengstofffabrik note (it IS the explosives factory -> Factorio, not the Armory islands). Supersedes the name-guesses (e.g. DeusExMashine is Rauchwolke, not Maschineninsel).
86 lines
3.4 KiB
Python
86 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Map each island prefab to its in-game display name (Toponym).
|
|
|
|
The internal prefab name (e.g. island_Demo_Wunderinsel) often differs from the name
|
|
shown in-game. The authoritative link is a child `Landmark` GameObject carrying a
|
|
`LandmarkBehaviour` (Hologryph.Sand.Shared.World.DesignedEnvironment.Configuration)
|
|
whose `name` field IS the Toponym key. The English display string is then
|
|
i2 `Toponyms/<name>`.
|
|
|
|
Example: island_Demo_Wunderinsel -> Landmark.name "Strudel" -> Toponyms/Strudel.
|
|
|
|
Writes extracted/island_names.json.
|
|
"""
|
|
import os, sys, json, UnityPy
|
|
from UnityPy.helpers.TypeTreeGenerator import TypeTreeGenerator
|
|
|
|
GAME = "/mnt/d/SteamLibrary/steamapps/common/Sand Playtest"
|
|
META = os.path.join(GAME, "Sand_Data/il2cpp_data/Metadata/global-metadata.dat")
|
|
DLL = os.path.join(GAME, "GameAssembly.dll")
|
|
BUNDLES = "/home/downloadpizza/sand_tools/bundles"
|
|
I2 = "/home/downloadpizza/sand_tools/i2_terms_en.json"
|
|
OUT = "/home/downloadpizza/sand_tools/extracted/island_names.json"
|
|
LM_FULL = "Hologryph.Sand.Shared.World.DesignedEnvironment.Configuration.LandmarkBehaviour"
|
|
|
|
|
|
def main():
|
|
gen = TypeTreeGenerator("6000.0.40f1")
|
|
gen.load_il2cpp(open(DLL, "rb").read(), open(META, "rb").read())
|
|
env = UnityPy.load(os.path.join(BUNDLES, "islands_assets_all.bundle"),
|
|
os.path.join(BUNDLES, "sand_monoscripts.bundle"))
|
|
nodes = [None]
|
|
|
|
def landmark_name(go, seen):
|
|
for c in go.m_Components:
|
|
try:
|
|
co = c.read()
|
|
except Exception:
|
|
continue
|
|
r = co.object_reader
|
|
if r.type.name == "MonoBehaviour":
|
|
try:
|
|
sc = co.m_Script.read()
|
|
if sc.m_ClassName == "LandmarkBehaviour":
|
|
if nodes[0] is None:
|
|
nodes[0] = json.loads(gen.get_nodes_as_json(sc.m_AssemblyName, LM_FULL))
|
|
nm = r.read_typetree(nodes[0]).get("name")
|
|
if nm:
|
|
return nm
|
|
except Exception:
|
|
pass
|
|
elif r.type.name == "Transform":
|
|
for ch in co.m_Children:
|
|
try:
|
|
g = ch.read().m_GameObject.read()
|
|
pid = g.object_reader.path_id
|
|
if pid not in seen:
|
|
seen.add(pid)
|
|
res = landmark_name(g, seen)
|
|
if res:
|
|
return res
|
|
except Exception:
|
|
pass
|
|
return None
|
|
|
|
i2 = json.load(open(I2)) if os.path.exists(I2) else {}
|
|
rows = {}
|
|
for path, obj in env.container.items():
|
|
n = path.split("/")[-1].replace(".prefab", "")
|
|
if obj.type.name == "GameObject" and n.startswith("island_"):
|
|
lm = landmark_name(obj.read(), set())
|
|
rows[n] = {"toponym": lm, "display_en": i2.get("Toponyms/%s" % lm) if lm else None}
|
|
|
|
out = {
|
|
"_source": "islands_assets_all.bundle island_* prefab -> child Landmark "
|
|
"(LandmarkBehaviour.name) -> i2 Toponyms/<name>",
|
|
"islands": dict(sorted(rows.items())),
|
|
}
|
|
json.dump(out, open(OUT, "w"), indent=1, ensure_ascii=False)
|
|
print("wrote %s\n" % OUT)
|
|
for n, d in out["islands"].items():
|
|
print(" %-34s -> %s" % (n, d["toponym"]))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|