What this fixes
A .gltf names its .bin and its textures inside its own JSON, as relative URIs. Godot's dependency graph never parses that JSON, so it cannot see those files at all. Drag the .gltf alone in the FileSystem dock and it moves alone, leaving its buffer and textures behind and the asset broken.
Putting the missing file back does not fix it either. The failed import has already written a poisoned .import, and nothing invalidates that on its own — which is the part that costs people an hour, because the obvious remedy looks like it should work.
This is an open gap in the engine, not a matter of opinion. It has been reported repeatedly and remains open:
- godotengine/godot#43043 — moving a
.gltfleaves the.binbehind - godotengine/godot#111554 — the same for
.obj/.mtl - godotengine/godot#85177 — external textures, error spam
.glb is in scope too, for a reason worth knowing: a .glb carries the identical JSON document, just wrapped in a binary container. Embedding is the exporter's choice, not a property of the format. Only the first buffer is required to be embedded; any further buffer, and any image, may still legally name an external file. An exporter that does that produces a .glb with exactly the same failure mode.
What it does
Drag a .gltf or .glb in the FileSystem dock, anywhere you would normally drag a file. That is the whole feature — its .bin and textures follow, and nothing else about the gesture changes. No new UI, no new habit.
Two more actions live on the file's right-click menu:
- Copy with dependencies… — copies the asset and everything it references into a directory you pick, minting fresh uids so no two files on disk ever share one. The dialog opens where the asset lives, not at the project root.
- Repair mesh/model — fixes an asset a past move already broke, by reconciling the
.importfiles that the failed import poisoned.
Every operation prints what it did to the Output panel: each file moved, copied or reconciled, anything skipped and why. Nothing happens silently.
The surprising behaviour, stated up front
A sidecar that another asset also references is copied, never moved — even when you are moving the primary asset.
This matters more than it sounds. Kits routinely share one texture set across a dozen meshes. Moving the texture along with the one mesh you dragged would silently break every other mesh using it, and you would not find out until you next opened one of them. So the addon checks whether anything else references each sidecar, copies the shared ones, leaves the originals in place, and names each one in the report.
Repair's precondition
Repair fixes a poisoned .import. It does not fetch anything that is missing.
If the .bin or a texture is actually gone — because a previous move left it in the old directory — put it back beside the model first, then run Repair. Running Repair with files still missing will tell you exactly which ones it could not find, so you are not guessing.
How it works
The addon parses the glTF document's own buffers and images arrays for their URIs, carries the files they name alongside the primary asset, and rewrites each touched .import so the editor's reimport succeeds instead of poisoning itself.
Two rules carry all the risk, and they are opposites:
- A move preserves each file's existing uid. Scenes and resources elsewhere in your project reference these files by uid; changing one would silently repoint or break those references.
- A copy mints a fresh uid instead. Two files sharing a uid makes Godot load whichever it resolves first, silently, and rewrite paths to match on the next save.
Everything else in the .import is preserved verbatim — compression settings, skeleton retarget blocks, LOD flags, roughness limiters. That is the entire reason the file is edited rather than deleted and regenerated: a regenerated .import loses whatever you tuned.
Sidecars keep their path relative to the asset, so a texture in a textures/ subfolder lands in textures/ at the destination and the model's relative URI still resolves. A sidecar that lives outside the asset's own directory — reached by a ../ URI — is left where it is and reported, because relocating it would change what that URI points to.
An existing file at the destination is never overwritten. The operation skips it and says so. On a move that matters twice over: clobbering the destination would destroy that file and then delete the source that could have restored it.
Limitations, honestly
.obj/.mtlis not supported yet. The resolver interface exists for it; no implementation is wired in.- Folder moves are not hooked. Dragging a folder carries the sidecars along for free, because the whole directory moves, but the model's
.importis not reconciled — run Repair on it afterward. - No undo. File operations sit outside Godot's undo system. Every file the addon touches is named in the Output panel, which is what makes a manual revert possible.
- The first time a repair or copy brings new textures into a project, Godot may log
Task 'reimport' already existsalongside its owndetect_3dmessages. That is the engine's first-use-in-3D reimport pass overlapping this addon's. It is harmless and does not recur — running the same operation again is clean. - A self-contained
.glbhas no external dependencies, so a move of one does nothing at all, correctly. Copy still copies it.
Requirements
Godot 4.4 or newer. GDScript only — no C#, no GDExtension, no external tools, no configuration. Enable it under Project > Project Settings > Plugins and it works.
Testing
The addon ships with six headless test suites — covering the URI resolver, the .import rewriting, the move/copy/repair planner, the file executor, and a full end-to-end move — plus a probe that verifies the engine assumption the whole .import strategy rests on, rather than assuming it. They run in a real Godot instance with no editor. All of it is in the repository and excluded from the packaged download.
Licence and source
MIT. Source, issues and the test suite: https://github.com/ProtoForgeSystems/protoforge-godot-addon-mesh-material-copy-move-repair
Changelog for version Mesh+Material Copy/Move/Repair
No changelog provided for this version.