- Home /
Unity loses association to ScriptableObject after exiting playmode
I wrote a ScriptableObject that can be serialized. I can do all of the fancy things with it, create an Asset of it via the creation menu, edit it with the Inspector or use a custom EditorWindow for easier editing. The ScriptableObject is derived from a generic ScriptableObject and serializes an enum array and 2 ints. In the EditorWindow I use the AssetDatabase to create the Assets if that matters.
And everything seems to be fine. Until I enter and exit playmode.
After that all Assets of the ScriptableObject show an Error:
The Associated script can't be loaded. Please fix any compile errors and assign a valid script.
The interesting thing is this: When I have an Asset selected so that I can see it in the Inspector when I exit playmode it does not get that error. It will still work like nothing happened.
That made me curious. So I forced text serialization and created a few ScriptableObject Assets. I gave them some values and copied the Asset-files as well as the Meta-files somewhere else on disk. Then I entered and exited playmode and compared the pre-Playmode files with the ones in the Assets folder.
There was absolutely no difference.
So my question is, why does this happen and how do I prevent it?
Why does Unity suddenly lose the association to files that haven't changed?
And why doesn't ithappen when I haven't got the Asset visible in the editor?
UPDATE: I just did a bit of trying around and found out some new things:
The association is only lost when I have an asset saved via the EditorScript in the scene.
I can restore the associations simply by having all assets selected when entering playmode
This leads me to think that my saving process is somehow messing with the AssetDatabase in a way that is reversed by what ever unity does when it converts all it's stuff for the engine. So I'm just gonna paste the code I use for saving here:`
public static void Save(UnityEngine.Object asset, string path, string name=null){
path = RelPath (path);
if (name == null)
name = Path.GetFileNameWithoutExtension (path);
asset.name = name;
AssetDatabase.CreateAsset (asset, path);
EditorUtility.SetDirty (asset);
AssetDatabase.SaveAssets ();
AssetDatabase.Refresh ();
}
Hi, to make sure I understand what you do: you create a new ScriptableObject with a context menu, then you modify the content of the ScriptableObject while the game is playing, then you save it at the end of the game ? (Not sure about the last saving action). ScriptableObjects need to be created (using CreateAsset like you did), but they don't need to be saved using CreateAsset. If you want to modify them, during gameplay or with an editor script (EditorWindow or custom Inspector), just do modify the data/members/arrays and use EditorUtility.SetDirty() on the ScriptableObject. Then, when the scene is saved (ctrl+s) or using AssetDatabase.SaveAssets(), the changes will be written to disk.
I do everything in the Editor, before entering playmode. I create the script, I edit it and save it with the above code before playmode. I do nothing in playmode and then exit it again. Now the association to the script is lost.
In that usage scenario: -to create the asset: add a CreateAsset$$anonymous$$enu attribute just before the class definition
[CreateAsset$$anonymous$$enu(fileName = "$$anonymous$$yScriptableObject", menuName = "Sub$$anonymous$$enu/$$anonymous$$yScriptableObject")]
public class $$anonymous$$yScriptableObject : ScriptableObject
and after that right click in the project window to create an asset (but i guess you did that already)
-Alternatively, use ScriptableObject.CreateInstance() to create an object by scrtipt in memory, then AssetDatabase.CreateAsset() to create it on disk (but this operation should be done only once to create the asset, never again)
-Now, modify the asset by an editor script or even in game ($$anonymous$$yFloat = 3.0f; etc...). Use EditorUtility.SetDirty() to notify unity that the asset was modified (and that's all)
-When you want to save the modifications on disk, just like with a scene, use ctrl+s. Even before saving the scene, going to play mode & back should not lose any data or modifications.
-You can still force the save on disk by calling AssetDatabase.SaveAssets() if you want, but never call CreateAsset() on the same asset once more (because it's already created).
I use ScriptableObject.CreateInstance() to create a new instance in the script. And I get the same bug even when I don't call CreateAsset multiple times (which by the way just seems to throw an error if the asset already exists and then allows me to continue my script without problems).
Ok, must be something else then. Have you tried creating a new project and trying to reproduce the same behavior, it should not be long. Doing this step by step and checking if everything works at each step should help you find the problem. There is some simple source code in unity's tutorial website that also may help you compare with your scripts (https://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/scriptable-objects).
I suspect this is a simple mistake because the description of what you do seems ok. It's not always possible but if you share more code, maybe me/the community can have other idea of the source of the problem.