- Home /
ScriptableObject not saving data to asset
Hi,
I'm struggling to perform a simple task: save List data to asset in the custom editor code. I want to do it only via the script and not via the Unity menu.
Can someone experienced assist ? Many thanks.
The following code:
Defines a list item called ScriptableObjectData
Defines a data container List<> ScriptableObjectDataManager
Creates a simple custom editor window with a button to add items to the list.
What works:
The asset file gets created in the desired folder
When I click on the asset file in the Project window I can see the empty list in the Inspector
What is not working:
After I click the Add button I enter the AddItem() method, the item is added to the list in the memory (debugger) but not to the file.
Additionally I get warning: Assets/Editor/ScriptableObjectData.cs(13,17): warning CS0436: The type `ScriptableObjectData' conflicts with the imported type of same name'. Ignoring the imported type definition.
What is this ??
The data definition file:
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class ScriptableObjectData {
public int ExecutionOrder;
}
[CreateAssetMenu (fileName = "Assets/Editor/MyData1.asset")]
public class ScriptableObjectDataManager : ScriptableObject {
public List<ScriptableObjectData> scriptableObjectDataList;
private void OnEnable() {
scriptableObjectDataList = new List<ScriptableObjectData>();
}
}
The EditorWindow code:
using UnityEngine;
using UnityEditor;
public class ScriptableObjectUser : EditorWindow {
public ScriptableObjectDataManager dataManager;
bool clickedAdd;
int counter;
[MenuItem("Window/My Window")]
public static void Start() {
ScriptableObjectUser window = GetWindow<ScriptableObjectUser>();
window.Show();
}
private void OnEnable() {
counter = 0;
Init();
}
public void OnGUI() {
clickedAdd = GUILayout.Button("Add item to list");
if (clickedAdd) {
AddItem();
}
}
public void Init() {
dataManager = ScriptableObject.CreateInstance<ScriptableObjectDataManager>();
string[] result = AssetDatabase.FindAssets("MyData1");
Debug.Log(result);
if (result.Length != 0) {
Debug.Log("Found Asset File !!!");
foreach (ScriptableObjectData dataItem in dataManager.scriptableObjectDataList) {
Debug.Log(dataItem.ToString());
}
} else {
Debug.Log("NOT Found MyData.asset :(");
AssetDatabase.CreateAsset(dataManager, "Assets/Editor/MyData1.asset");
}
}
void AddItem() {
Debug.Log("Adding Item !!!");
ScriptableObjectData data = new ScriptableObjectData();
data.ExecutionOrder = ++counter;
dataManager.scriptableObjectDataList.Add(data);
Debug.Log(dataManager.scriptableObjectDataList.ToString());
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
Answer by PizzaPie · Sep 10, 2017 at 06:03 PM
For starters you never utilize the result array thus each time you open the editor it uses a new instance of the dataManager. Change the code to something like this->
public void Init()
{
//dataManager = ScriptableObject.CreateInstance<ScriptableObjectDataManager>(); //remove this
string[] result = AssetDatabase.FindAssets("MyData1");
Debug.Log(result);
if (result.Length != 0)
{
string path = AssetDatabase.GUIDToAssetPath(result[0]);
dataManager =(ScriptableObjectDataManager) AssetDatabase.LoadAssetAtPath(path, typeof(ScriptableObjectDataManager)); //this will only load the first Asset that found with that name
Debug.Log("Found Asset File !!!");
foreach (ScriptableObjectData dataItem in dataManager.scriptableObjectDataList)
{
Debug.Log(dataItem.ToString());
}
}
else {
Debug.Log("NOT Found MyData.asset :(");
dataManager = ScriptableObject.CreateInstance<ScriptableObjectDataManager>();
AssetDatabase.CreateAsset(dataManager, "Assets/Editor/MyData1.asset");
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
So you have an active instance of the dataManager. Now to force the editor to save the changes on the AddItem() method add EditorUtility.SetDirty(dataManager); above the AssetDataBase.SaveAssets(); This should do the trick.
Lastly on the ScriptableObjectManager class
public class ScriptableObjectDataManager : ScriptableObject {
public List<ScriptableObjectData> scriptableObjectDataList = new List<ScriptableObjectData>();
}
change it to this otherwise the List will be cleared each time you open the editor unless that is something you want to happen.
Oh and about the warning you obviously have 2 definitions of the same class. Change the name of either one to get it fixed, apparently the editor checks if there are definition conflicts and ignores the one from the import... needless to say it will create a ton of problems when you use a script that needs the second definition but gets the one you created. To resolve it properly change the name of the class/file you created or put it inside a namespace. (i would go with the second one)
Cheers hope that helps!
$$anonymous$$alimera :)
Awesome. Thanks mate. Works even without the SetDirty() invoke.
Re warning - indeed I had another script of the same name in a different directory.
There are two very $$anonymous$$or tweaks needed to make your code working:
line 9 - spelling of the GUIDToAssetPath(...)
line 10 - (ScriptableObjectData$$anonymous$$anager) AssetDatabase.LoadAssetAtPath(...)
$$anonymous$$alispera(GoodEvening) Happy to help!
I ll fix the mistakes, my bad, should had loaded the assembly to check for mistakes. If you close and re open the editor it keeps the changes on the Scriptable? I ve spend couple days trying to figure a way to force it to save the changes, only SetDirty() would work, i guess they changed something.
Answer by Olinus · Sep 12, 2017 at 08:40 PM
One more question.
Now I'm trying to make an asset containing list of GameObjects. Below is the code changes comparing to the initial one.
What is working:
The asset gets saved with new list item created.
The Execution Order fields gets populated correctly.
What is not working:
When I press the Add button the item is added to the list but in the "Game Object" field I get message: "Type mismatch"
I cannot drag & drop objects from the Hierarchy onto "Game Object" field in the asset opened in the Inspector.
What am I doing wrong ??
Data code:
[System.Serializable]
public class ScriptableObjectData {
public GameObject gameObject;
public int ExecutionOrder;
}
[CreateAssetMenu(fileName = "Assets/Editor/MyData1.asset")]
public class ScriptableObjectDataManager : ScriptableObject {
public List<ScriptableObjectData> scriptableObjectDataList = new List<ScriptableObjectData>();
}
The AddItem() method:
void AddItem() {
Debug.Log("Adding Item !!!");
ScriptableObjectData data = new ScriptableObjectData();
data.ExecutionOrder = ++counter;
data.gameObject = new GameObject("Test");
dataManager.scriptableObjectDataList.Add(data);
Debug.Log(dataManager.scriptableObjectDataList.ToString());
//EditorUtility.SetDirty(dataManager);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
Many thanks.
Post the whole error log of the Type $$anonymous$$issmatch and in which line it happens. Nothing seems wrong but i would remove the data.gameObject = new GameObject("Test"); if you need to fill the field with an existing GameObject, as the constructor of GameObject class will add the new object in current scene a quite annoying behaviour. Also if possible post a screen shot of the inspector. Cheers.
Donno why the page is not attaching files after clicking the "Upload buton" so I'll write down what happens. Lame on me.
The GameObject does not exist. I create it in the AddItem() method.
Scenario 1. It is a blank project, the $$anonymous$$yData1.asset does not exist, Hierarchy is clean. Warning shows in the inspector.
LOG: I get: NOT Found $$anonymous$$yData.asset :(
LOG: Warning: No script asset for ScriptableObjectData$$anonymous$$anager. Check that the definition is in a file of the same name The warning is not related to any line i.e. double click does not shift me to the code.
No other LOG entries - just the above
PROJECT: the $$anonymous$$yData1 asset gets created with empty list.
WINDOW opens.
Scenario 2. It is right after I click Add button.
LOG: Adding Item !!!
LOG: System.Collections.Generic.List`1[ScriptableObjectData]
No other LOG entries - just the above.
HIERACHY: Test Game Object gets created
INSPECTOR: Scriptable object Data List -> SIZE = 1 Element 0 -> Game Object = Type $$anonymous$$ismatch Element 0 -> Execution Order = 1
Funny thing: when I click on the "Type missmatch" in the ispector it takes me to the Test object in the hierarchy.
Hope this helps. Efcharistó.
Not sure, try to look around for the Type $$anonymous$$issmatch i ve never encountered it. Anyway remove the line data.gameObject = new GameObject("Test"); to see if the issue persists and if you can fill the field manually through the Inspector. Also make sure you ve fixed the issue with the Definition conflict you had before. Can't see what s actually at fault here. Cheers
PS: if you can't figure it out create a new Question, but make sure to search for solutions first!
Your answer
Follow this Question
Related Questions
Converting XML-files into assets 1 Answer
Prevent changes in ScriptableObject type Asset in Editor. Dont save it. 0 Answers
Unity recompilation time slowly increases each time it's recompiled. Why? 0 Answers
How to create custom asset icons for ScriptableObject instances 2 Answers
RenameAsset does not change the name of asset in Project Window in Awake() or OnEnable() 1 Answer