#!/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()
