Back to Supersonic RC Revive
SOURCE / PINNED RELEASE

Made of little things.

Supersonic RC Revive

Release
1ba42f1ca1d6…
Author-recorded commit
baecad10b1cd…
License
LICENSE
Author’s source reference
nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.napplet.soy%2F/n-143146b0d6f

Archive hash verified: 90d22b206672eba4…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

tools/extract/lightmap_uvs.py
#!/usr/bin/env python3
"""Convert the decompiled UV_Lightmap_UVs movie script into JSON.

Dev-only tooling. The original game bakes lightmap UVs into a Lingo literal:
  ["Model": [#uvs: [[[u, v], ...per vertex...], ...per mesh...], #lightmap: "001"], ...]
Each inner list is indexed by meshDeform vertex index of that model's mesh
(shader group) and is applied as texture layer 2 by lightMapManager.

    python3 tools/extract/lightmap_uvs.py
"""
import json
import os
import re

ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
SRC = os.path.join(ROOT, "ref-out", "decompiled", "game", "casts", "Internal", "MovieScript 24 - UV_Lightmap_UVs.ls")
DST = os.path.join(ROOT, "ref-out", "assets", "lightmap_uvs.json")

TOKEN = re.compile(r'\s*(?:(\[)|(\])|(,)|(:)|"([^"]*)"|#(\w+)|(-?[0-9.]+(?:e-?\d+)?))')


def parse(text):
    pos = 0

    def tok():
        nonlocal pos
        m = TOKEN.match(text, pos)
        if not m:
            raise ValueError(f"bad token at {pos}: {text[pos:pos + 40]!r}")
        pos = m.end()
        return m

    def value():
        m = tok()
        if m.group(1):
            return lst()
        if m.group(5) is not None:
            return m.group(5)
        if m.group(6):
            return m.group(6)
        if m.group(7):
            return float(m.group(7))
        raise ValueError(f"unexpected {m.group(0)!r} at {pos}")

    def lst():
        nonlocal pos
        items, props = [], {}
        while True:
            save = pos
            m = tok()
            if m.group(2):
                return props if props else items
            if m.group(4) and not items and not props:  # [:] empty proplist
                tok()
                return {}
            pos = save
            v = value()
            save = pos
            m = tok()
            if m.group(4):
                props[v] = value()
                m = tok()
            else:
                items.append(v)
            if m.group(2):
                return props if props else items

    start = text.index("return ") + len("return ")
    pos = start
    m = tok()
    assert m.group(1)
    return lst()


def main():
    data = parse(open(SRC).read())
    out = {name: dict(lightmap=info.get("lightmap"), uvs=info["uvs"]) for name, info in data.items()}
    json.dump(out, open(DST, "w"))
    print(f"{len(out)} models -> {DST}")


if __name__ == "__main__":
    main()