SuperTiled2Unity
SuperTiled2Unity copied to clipboard
Manual "Reimport Tiled Assets" required on every Prefab Replacement components' code change
I was chatting with other devs using st2u, and discovered they've run into this issue often also. I checked here, and couldn't find an issue, so here goes: asically, to repro:
- write a custom C# component and put it on a prefab
- create a scene with a tiled map that uses that prefab in the Prefab replacement config.
- make a change to the C# component (e.g., add a public field) in your editor (e.g., vscode) and save
- return to the Unity editor
- observe that all the prefabs are replaced with vanilla st2u gameObjects - with SuperObject/SuperCustomProperties instead of the custom one(s) from the prefab.
- (note: if you were in "Play Mode" then the prefabs will not vanish from the map/scene until you exit play mode)
In case it matters, I'm using st2u 1.9.1 and Unity 2019.3.15f1
Thankfully, it is easy to temporarily restore the prefabs by hitting Edit > Project Settings > SuperTiled2Unity > Reimport Tiled Assets.
That said, this is pretty jarring to new developers as it manifests as everything unexpectedly breaking, hot-reloading becoming unreliable, and once you know how to "restore", it can take a while if you've got a large number of tiled maps and prefabs.
I run into this often, so I advise keeping the Project Settings tab permanently docked in my bottom panel in the editor and avoiding edits to custom components that are part of the prefabs when possible.
I have also run into this problem as well and it's becoming a workflow issue (this is also the reason I made a github account just now). Any time a prefab is modified, that change is not picked up until Tiled assets are re-imported.
I used to be on ST2U 1.9.1 (Unity version 2019.1.14f1) but just updated to the latest on 2020.3.1f1 and the issue persists. Here's something I've noticed that may better illustrate the cause of the problem:
When an Object in Tiled is replaced with a "prefab" using the Prefab Replacements, that prefab is instantiated as a "Model" instead of a Prefab. An example of a scene-instance replacement: https://i.imgur.com/Y02Vnyy.png
An actual prefab with an "Overrides" menu is seen here: https://i.imgur.com/7R8W8Vj.png
I don't know if the presence of an Overrides menu/Revert feature is necessarily part of the issue, but it seems to me that by importing as a model instead of a prefab, the values of that prefab "break the link" from their source
It sounds like there is a dependency missing somewhere. Next time I have some time I'll try to replicate what is being reported but if you have happen to have a small example project I could debug with that could help.
Thanks for the quick reply! I made a quick sample project and uploaded it here: https://puu.sh/HukHb/0029b834f1.zip
I don't know if it helps but I'll mention it now: when importing the SuperTiled2Unity unitypackage, I unticked the Examples folder but left everything else intact.
In the sample project there's a tilemap with 4 copies of the same prefab in the scene. The lower 3 prefabs are created via the prefab replacement tool, whereas the 1 prefab in the "sky" is placed directly in the scene. When you launch the play mode, a script changes the sprite the prefab uses. The one in the sky uses the sprite index that is defined in the prefab itself, while the 3 below use an "old" version. If you change the map or reimport all assets, they'll all update to the current prefab settings. If you then change the prefab's "DesiredFrame" value, only the one in the sky updates.
As noted, the one in the sky is considered by Unity as a Prefab, while the ones imported by SuperTiled2Unity are considered Models.
Thanks for the example. This appears to be a bug with Unity where, for some reason, prefab instances on custom imported objects are not updating. I've tried to work around this with explicit custom importer dependencies but there are two issues with this:
- Any edit made to the prefab source forces the map to be reimported (this can be real pain when you have a large number of maps using prefab replacements)
- It doesn't really work. It looks like the prefab is initiating a reimport just before it is resaved. This results in "the last edit" you made to the prefab not being reflected in the prefab replacements.
I'm going to reach out to Unity and see what they say. Thanks.
It doesn't really work. It looks like the prefab is initiating a reimport just before it is resaved. This results in "the last edit" you made to the prefab not being reflected in the prefab replacements.
I've gone down a deep rabbit hole relating to this in my ScriptedImporter. I personally think that it should always be necessary to add a source asset dependency on the prefabs so that the ScriptedImporter reimports when the prefab reimports, to stay as updated as possible.
But anyways, after my experimenting, I have come to an explanation for why this just doesn't work. If at any given point that a ScriptedImporter and a prefab are both reimported at the same time (ie. Multiselection, Source asset dependency), then the prefab is just simply null. The reason why this is the case is that the ScriptedImporter is imported before the prefabs are imported. This explains why the ScriptedImporter would need a reimport for a second time because the prefab is now available at that point in time.
I've proven my theory in SuperTiled2Unity as well by multi selecting these assets, reimporting them all at once, and logging what the prefabs were during the DoPrefabReplacements function:




So I dug deeper in my own importer and looked at the ScriptedImporterAttribute.importQueueOffset, which is what allows a customized import order over other native asset types.
The documentation didn't explain what the import order of the native asset types was, and there was nothing I could find at all relating to this info online, so I did my own testing and came to the conclusion that a prefab's importQueueOffset under the hood is 500/501, my findings from this post.
So there is indeed a way to make the importer reimport after the prefabs and does solve the problem.
It does however have a breaking side effect, where any ScriptedImporter assets that are placed in prefabs or prefab variants, lose prefab connection when both assets are reimported, which makes it an unsustainable solution.

I've tried a couple of solutions to work around either of these problems. At first, I would try to use AssetDatabase.ImportAsset with ImportAssetOptions.ForceSynchronousImport to make a prefab not null before the ScriptedImporter imports, but it simply doesn't seem to reimport the prefab, as it still remains null, so that would not work.
I've also attempted another solution, where the ScriptedImporter imports both before and after the prefabs reimport by using EditorApplication.delayCall, but it was impractical because it effectively doubles the import time, which is also not sustainable for large projects. I've detailed that journey in this post.
It really is a difficult situation when dealing with adding prefabs into the hierarchy of a ScriptedImporter, and there really isn't an easy way of going about it. I've personally decided to accept that my own importer ScriptedImporter would not be able to live inside prefabs, by choosing to make my importer import after prefabs, but I'm still wondering about finding a perfect solution eventually.
Hopefully, this explanation can help provide some insight on what's really going on here.
I'd be really interested in finding out a solution that works out without any issues. Were you able to reach out to Unity and get an answer back from them?
After some more learning on my end, I've found out that the reason why this is an issue is that the prefab dependencies are set up as DependsOnSourceAsset, which I was also guilty of using because it's the only function available in older versions of unity.
With DependsOnSourceAsset, it means that it only triggers a reimport because the actual prefab file data was changed.
To establish a proper import order, the ScriptedImporter needs to set up an artifact dependency with
AssetImportContext.DependsOnArtifact.
Though the ultimate solution I've found was to use ScriptedImporter.GatherDependenciesFromSourceFile which worked wonders for me.
(Is documented in Unity 2020.1, though GatherDependenciesFromSourceFile is still available in older unity versions, just undocumented for those older versions)
Apologies for reviving this thread, but I'm running into similar issues (albeit with my Custom Importer relying on Prefabs that are not yet loaded when it tries to use them after a fresh git pull or in my CI/CD pipeline). I've got a fleshed out Cutsom Importer that extends the CustomTmxImporter but am unsure where I would use the ScriptedImporter.GatherDependenciesFromSourceFile you mentioned above. Did you add this to the SuperTiled2Unity source files yourself? I'm so glad someone else has had this issue and am grateful that you have already looked into it so much, but I'm not sure how to implement your solution. Any help would be greatly appreciated! Thanks in advance.
@grebhun
Using GatherDependenciesFromSourceFile was something I used in my own scripted importer for LDtk.
But for it to work with STU, I'd wager that quite a bit of the source files would need to be changed.
- By switching to using
GatherDependenciesFromSourceFile, any instances of DependsOnSourceAsset can be discarded, as this is our new way of depending on assets. - The function attempts to retrieve all paths to assets that should be depended on. (It's called before the import process) This is however, a particular time in the import process this is called, where you are not allowed to access the importer asset, not even allowed to get the ScriptedImporter at the asset path. So what needs to be done, is load the tiled file's raw text, and then go digging from there in whatever way possible. If I remember correctly, the prefab replacements for STU are in a separate ScriptableObject in the project settings? If there's a way to load that up, you could dig into its raw text and parse it from there.
The goal is to only declare dependencies for prefabs that are actually used by a tiled map, as to reduce unnecessary reimports even if an unused prefab was changed.
Hopefully this helps 🙂