Shared chat
Converting Gameloft BDAE Game Assets
This is a shared TryAI chat. Sign in to start your own conversation.
Sign in to TryAIShared chat
This is a shared TryAI chat. Sign in to start your own conversation.
Sign in to TryAI.bdae is Gameloft's proprietary "Binary DAE" — a compiled, pointer-relocated COLLADA-ish scene graph used by their in-house engine (N.O.V.A., Modern Combat, Asphalt, Dungeon Hunter, Order & Chaos, Total Conquest)..bdae..bdae, the right move is a one-way migration: extract once → convert to glTF 2.0 → never touch bdae again.A .bdae is not a text COLLADA file. Typical layout:
Two gotchas that break most people:
.bdae files are containers. They're zlib/zip-wrapped. If they don't open, extract them as a zip first and then open the little_endian bdae file inside..tga files that are actually PVR containers. Extract them, then open the PVR files with PowerVR Graphics Tools. Some split RGB and alpha into separate PVRs that you have to recombine.3ds Max has no bdae plugin and never will. Your chain is:
Animations are the weak link. Expect to re-rig and re-animate by hand, or write your own parser.
This is where Claude Code is genuinely useful — format reverse-engineering is a great LLM task because it's iterative hypothesis testing against a hex dump.
Start it with a probe script:
Then have Claude Code iterate: identify the string table, find float triplets that look like normalized normals (magnitude ≈ 1.0), locate index buffers as monotonic uint16 runs, and cross-validate vertex_count * stride. Give it 5–10 sample files including one you know is a simple static building — a static building mesh is exactly the right file to learn the format on.
Ask it to output glTF 2.0, not FBX. glTF is JSON + binary, trivially writable from Python, and every engine reads it.
Split this honestly into three things:
❌ What it cannot do: Look at a PNG and produce good 3D geometry. Claude Code has no image-to-mesh capability. Anything it "models" procedurally from a description will look like programmer art — boxes and cylinders.
⚠️ What it can orchestrate: Image-to-3D AI as a subprocess — Hunyuan3D, TRELLIS, TripoSR (local), or Meshy/Rodin (API). Claude Code can script the call, then run automatic cleanup in headless Blender: decimate, remesh, UV unwrap, bake the PNG as the albedo, export glTF. Output quality is mediocre-to-decent and always needs human cleanup for a hero building.
✅ What it can do perfectly: Everything around the asset.
It can write that script, generate the metadata, register the building in your data tables, hook up upgrade tiers, hitboxes, placement rules, and the isometric sort order — all of it, reliably.
The pragmatic insight: Total Conquest is a fixed-camera isometric base builder. You do not need real 3D. Pre-render or hand-paint each building as a sprite with a defined footprint and depth-sort key. If you go sprite-based, then yes — hand Claude Code a PNG and it can integrate it fully and correctly, because the whole problem collapses into data plumbing, which is its strength.
A workable manifest it can author and consume:
.glb) for 3D, PNG/WebP for 2D, plus a JSON/YAML side-car for gameplay metadata.tools/legacy_import/, run it once, commit only the converted output. Nothing in the runtime should ever know bdae exists.CLAUDE.md stating: "The runtime must never read .bdae. All assets are .glb or .png with a JSON manifest. Legacy conversion lives in tools/legacy_import/ and is not shipped." It will hold that line consistently.Extracted Gameloft models, textures, and animations remain Gameloft's copyrighted work. Converting them for private study or personal modding is one thing; shipping them in "the new game" — free or paid — is straightforward infringement, and Gameloft does issue takedowns.
If the goal is a real product, use the extracted assets only as reference for scale, proportion, and grid metrics, then replace all art with your own. That also happens to be the reason the PNG-based sprite pipeline above is the right architecture: it's built around your art from day one.
No — most games do not have their own engine. The vast majority license or use an existing one. Writing an engine is years of work that produces zero gameplay.
Two different worlds:
.bdae exists), EA Frostbite, Ubisoft Anvil, Rockstar RAGE, id Tech. Proprietary engines are exactly what create proprietary formats like .bdae — nobody outside the company needs to read them, so they're optimized for load speed, not interoperability."Open source engine" isn't a category of one engine. There are several, and you pick one.
Not engines but relevant: libGDX, MonoGame, SDL3, raylib — these are frameworks. You get rendering and input; you write the scene system, editor, and asset pipeline yourself. More control, far more work.
Reasons specific to what you're doing:
.glb in the project folder and it imports. This directly serves your "nothing related to .bdae" goal..tscn scenes, .tres resources, and project.godot are all human-readable and diff-friendly.That last point matters enormously for your workflow. Claude Code can read, write, and diff Godot scene files directly:
Unity's .prefab and .asset files are YAML with GUID references into .meta files — editable, but fragile. Unreal's .uasset is opaque binary; Claude Code effectively can't touch it. Godot is the only major engine where an AI agent can author real scenes as text. Given that you're building this on Claude Code, that's arguably the deciding factor.
"Open source" does not mean you'll be reading engine source. In practice you'll use Godot exactly like Unity — editor, scripts, ship. The benefits are subtler but real: no license rug-pull (remember Unity's 2023 runtime-fee attempt), you can patch a bug yourself if you hit a blocker, and the format is documented rather than reverse-engineered.
Which is the whole reason you're in this mess with .bdae to begin with.
You're describing it as one operation. It's actually two completely unrelated jobs, and only one of them is a "conversion."
Also, small terminology fix: there is no .godot asset format. project.godot is just a config file. Godot's actual formats are .glb (3D), .png (2D), .tscn (scenes), .tres (resources). So "bdae → godot" isn't a format pair the way you're picturing it.
You cannot swap an engine underneath an existing game. Total Conquest ships as:
The engine and the game logic are the same compiled artifact. There's no seam to cut. You can't remove Gameloft's engine and slot Godot in, because the game code calls Gameloft engine APIs directly, and that code is machine instructions you don't have the source to.
So "editing the engine from bdae to Godot" isn't a task that exists. What you're actually signing up for is a reimplementation.
This is the part that resembles what you were imagining.
Mechanical, scriptable, finite. Run it once, commit the output, delete the tooling from the runtime path. After this, .bdae is genuinely gone from your project forever — which was your actual goal.
Scope: days to a few weeks, depending on how hard the format fights you.
Everything that makes it a game has no conversion path at all:
None of this is in the .bdae files. It's in the compiled binary. You reimplement it in GDScript by observing the original game's behavior and re-deriving the numbers.
Scope: this is the actual project. Months.
Your mental model should shift from "convert the game" to:
"Build a new isometric base-builder in Godot, using the original as a design reference."
That reframing matters because it changes what you ask Claude Code to do. It's not a migration agent. It's implementing a game, with the old game as the spec.
A structure that reflects reality:
The data/ folder is where the honesty lives. Those numbers aren't converted from anything — you or Claude Code write them, tune them, and own them.
A rewrite sounds worse than a conversion, but it's better here:
.tscn text, generating JSON data tables, and building tooling is squarely in its strengths. Reverse-engineering a compiled ARM binary is not.Don't start with the bdae extractor. Start here:
An isometric grid in Godot where you can place one placeholder building from a PNG, with correct footprint, anchor, and Y-sorting.
If that works, every remaining building is data entry. If it doesn't, no amount of asset extraction helps you. Get the pipeline proven before you invest in the archaeology.
I'd been assuming you were working from an APK. If you have official access, the whole approach inverts. Let me redo it properly.
.bdae is an output, not a sourceThis is the single most important thing. Gameloft artists never authored .bdae files. The internal pipeline looked like:
So you should never convert a .bdae at all. Every one of them was generated from an upstream .ma/.max/.dae that lives in Gameloft's asset repository or Perforce depot. Converting bdae → glTF is lossy reverse-engineering of a file that has a pristine ancestor sitting on a server somewhere.
Your ask isn't "how do I decode this format." It's "where is the pre-compile art, and can I have it?"
Prioritized, because you may not get all of it:
.ma/.max/.dae per model, plus source textures as PSD/TGA/PNG before PVR compression. This alone deletes 90% of the problem.bdae_format.h or similar in the engine source.If the title has been sunset for a while, be prepared for archive gaps — old mobile projects get partially lost, build machines get decommissioned, and Perforce depots get pruned. Ask early, because that determines your fallback.
Still true: you cannot mechanically transform Gameloft's engine into Godot. Different renderer, scene graph, threading model, allocator, input, audio. No tool does that.
Now different: with source, this becomes a port rather than a blind reimplementation. Concretely:
Porting logic from C++ to GDScript/C# is tedious but deterministic. That's exactly the kind of work Claude Code does well — feed it a C++ system and the target Godot idioms, and it translates faithfully. That's a fundamentally different proposition from guessing at a compiled binary.
And a hard rule for CLAUDE.md:
One narrow case: verification. If archives are incomplete, or you need to confirm the shipped asset matches the source art, a read-only parser is useful — pivot points, scale, node naming, and grid alignment are the things that silently drift and are painful to rediscover by eye.
Build it read-only, keep it in tools/legacy_only/, and treat its output as reference data, never as shipping assets. With the exporter source or format header in hand, Claude Code can write that parser in an afternoon.
One question that shapes the rest: do you have engine/game source access, or only the asset archive? The answer moves this between "port" and "remake with good reference," and they're very different plans.
Correct — and that's exactly the risk of any approach where you convert .bdae at runtime or ship a converter inside the app instead of doing the conversion offline, once, at build time.
If your pipeline looks like this:
...then anyone who unzips your APK finds .bdae files sitting right there, byte-identical to Gameloft's originals. That's not a "trace" — that's the literal proprietary asset, discoverable by anyone with unzip and no reverse-engineering skill at all. Worse than a fingerprint; it's the whole file.
If you do this correctly, someone unzipping the APK finds .glb, .png, .tscn, .gd — nothing that says bdae anywhere, because the file never entered the package.
.bdae in the repo path that gets packaged. Keep them only in tools/legacy_only/ or a completely separate conversion repo, and add it to .gitignore/build excludes for the shippable project.libbdaeloader.so or any bdae-reading code ends up statically linked into your release build, a reverse engineer will find bdae parsing logic in the disassembly even if no .bdae files are present — that's still a trace, just a subtler one (string tables often leak format names even when stripped)..glb. Rename during the conversion pass, not after..glb metadata. glTF exporters sometimes embed the exporting tool's name/version and source file paths in the JSON chunk. Strip that before packaging — gltf-transform or a quick JSON edit handles it.unzip -l app-release.apk | grep -i bdae, then strings libgame.so | grep -i bdae, then decompile with a tool like apktool/jadx and search for "bdae" as a string across everything, including native libs. If both come back empty, you're clean.Since you have official access, the moment you convert an asset from its .max/.dae source to .glb, the .bdae intermediate never has to exist in your build tree at all — you go source → glTF directly, skipping bdae entirely rather than converting bdae → glTF. That's the cleanest way to guarantee reverse engineers find nothing, because there's genuinely nothing to find.
[header: magic/endianness/version/offsets][string table][data blob: vertex buffers, index buffers, matrices][metadata tree: nodes, meshes, materials, texture refs, skin, anim curves][relocation table: offsets fixed up into real pointers at load time]game APK/OBB → QuickBMS (unpack .dat) → unzip (if wrapped) → Noesis (bdae → .fbx) → 3ds Maximport sys, zlib, struct, pathlib
def probe(p: pathlib.Path): d = p.read_bytes() print(f"{p.name} size={len(d)}") print(" magic:", d[:8].hex(" "), repr(d[:4]))
# container check if d[:2] == b"PK": print(" -> zip container") for off in range(0, min(len(d), 256)): if d[off:off+2] in (b"\x78\x9c", b"\x78\x01", b"\x78\xda"): try: out = zlib.decompress(d[off:]) print(f" -> zlib at {off}, inflated {len(out)} bytes") d = out break except zlib.error: pass
# header word dump, both endians for i in range(0, 64, 4): le = struct.unpack_from("<I", d, i)[0] be = struct.unpack_from(">I", d, i)[0] print(f" +{i:02x} LE={le:<12} BE={be:<12}" f"{' <- plausible offset' if 0 < le < len(d) else ''}")
for a in sys.argv[1:]: probe(pathlib.Path(a))blender --background --python import_building.py -- \ --texture assets/raw/barracks_lv3.png \ --grid 4x4 --anchor bottom-center \ --out assets/gltf/barracks_lv3.glb{ "id": "barracks", "level": 3, "sprite": "buildings/barracks_lv3.png", "footprint": { "w": 4, "h": 4 }, "anchor_px": { "x": 256, "y": 412 }, "sort_offset": 0.5, "shadow": "buildings/barracks_lv3_shadow.png", "occupies_walkable": false}[gd_scene load_steps=3 format=3]
[ext_resource type="Texture2D" path="res://assets/buildings/barracks_lv3.png" id="1"]
[node name="Barracks" type="Node2D"]
[node name="Sprite" type="Sprite2D" parent="."]texture = ExtResource("1")offset = Vector2(0, -206)libgameloft.so ← compiled native engine (C++), no sourcegame logic ← compiled into that binaryassets/*.dat ← bdae + PVR insidebdae → [extract, once] → .glb / .png → GodotPVR → [extract, once] → .png → Godotproject/├── project.godot├── CLAUDE.md ← "runtime never reads .bdae"├── tools/legacy_import/ ← run once, never shipped│ ├── unpack_dat.bms│ ├── bdae_probe.py│ └── bdae_to_gltf.py├── assets/ ← .glb / .png only, committed│ └── buildings/├── data/ ← YOUR values, hand-authored│ ├── buildings.json│ └── troops.json├── scenes/ ← .tscn, Claude Code writes these└── scripts/ ← .gd, the actual gameMaya / 3ds Max scene → COLLADA (.dae) → bdae compiler → .bdae ↑ the real source ↑ build stepPerforce/asset repo (.max/.ma) ↓ 3ds Max — you're already set up for this FBX / glTF export ↓ .glb → Godot ← bdae never appears anywhere## Asset policy- Source of truth: DCC files in art/source/ (.max, .ma)- Runtime format: .glb (3D), .png/.webp (2D)- .bdae is FORBIDDEN in runtime, build scripts, and importers.- Legacy bdae extraction, if ever needed, lives in tools/legacy_only/ and is excluded from all builds.APK ships: assets/models/*.bdae ← original files, untouched libbdaeloader.so ← runtime parserBUILD TIME (your machine, never shipped) source.max/.dae → export → .glb │ ▼RUNTIME (inside the APK) assets/models/*.glb ← only this exists in the package