- Home /
Data of prefab is not being saved on play mode despite serialization.
I have a problem saving data between the edit mode and the play mode in my project. The data I save in the editor's object is saved but only in certains cases.
This is the simplified structure of my code:
[System.Serializable]
public class Status {
public float x;
public float y;
public float width;
public float height;
public int index;
public Status(float x, float y, float width, float height, int index){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.index = index;
}
}
[ExecuteInEditMode()]
[System.Serializable]
public class Foo: MonoBehaviour {
public List<Status> status_list = new List<Status>();
public int active_x;
public int active_y;
public int active_height;
public int active_width;
public void setStatus(int kframe, float x, float y, float height, float width){
if (status_list.Count > kframe){
status_list[kframe] = new Status(x, y, width, height, kframe);
} else {
status_list.Insert(kframe, new Status(x, y, width, height, kframe);
}
}
}
I've also developed a custom editor to save some values on the status list.
As you can see, I have a slide to set the position inside the list where i want to update/set/get the values (X, Y, H, W).
When the slides moves, it shows the values of the variables in that position of the list (using the named varibles active_* for that matter).
To do the saving/updating of the values, I've put a button that saves the data (X, Y, H, W) at the position indicated by KF.
Editor Script
[CustomEditor(typeof(Foo))]
[CanEditMultipleObjects]
public class FooEditor : Editor{
SerializedProperty kframe_status, x, y, w, h;
private int max, idx;
void OnEnable(){
Foo foo = (Foo) target;
kframe_status = serializedObject.FindProperty ("active_kframe");
idx = 0;
x = serializedObject.FindProperty ("active_x");
y = serializedObject.FindProperty ("active_y");
h = serializedObject.FindProperty ("active_height");
w = serializedObject.FindProperty ("active_width");
}
public override void OnInspectorGUI(){
serializedObject.Update ();
Foo foo = (Foo) target;
EditorGUIUtility.labelWidth = 18;
EditorGUI.BeginChangeCheck();
idx = EditorGUILayout.IntSlider ("KF", idx, 0, 30);
if (EditorGUI.EndChangeCheck()){
updateActiveKframe(foo);
}
EditorGUILayout.Space ();
Rect r = EditorGUILayout.BeginHorizontal ();
x.intValue = EditorGUILayout.IntField("X", x.intValue);
y.intValue = EditorGUILayout.IntField("Y", y.intValue);
h.intValue = EditorGUILayout.IntField("H", h.intValue);
w.intValue = EditorGUILayout.IntField("W", w.intValue);
if (GUILayout.Button ("Guardar")) {
float xP = (x.intValue);
float yP = (y.intValue);
float hP = (h.intValue);
float wP = (w.intValue);
foo.setStatus (idx, xP, yP, hP, wP);
updateActiveKframe(panel);
}
serializedObject.ApplyModifiedProperties();
EditorGUILayout.EndHorizontal ();
}
public void updateActiveKframe(Foo f){
f.getActiveStatus (idx);
x.intValue = f.active_x;
y.intValue = f.active_y;
h.intValue = f.active_height;
w.intValue = f.active_width;
}
}
The problem is that if I save some data to one position in the list, the list inside the Foo object is updated, but not in play mode. On the other hand, if I save some data to the one positon in the list, and then I go to another position of the array then in Play mode it does save the data i've just loaded in the edit mode.
I've been strugglin with this issue for months now, and I have been looking out in the web and the forums but I've been unable of finding a solution for the issue. I think it has to be something related with the events that take place in the edit mode (Update, OnGui), but at this point i am not sure anymore.
Thank you all by the way.
Answer by clrbnnnbsch · Jul 10, 2019 at 07:22 PM
At the end I found what the problem was, I think it got to do with the fact i was changing serialized data from de Foo object, but never using a EditorGUILayout.PropertyField for that matter, that creates a Undo states and reloads the target, so the Foo object changed the data in the inspector window but that changes were never applied in play mode, unless i forced a change in the slide. (https://docs.unity3d.com/ScriptReference/EditorUtility.SetDirty.html)
I presume forcing a change in the slide it marked the target dirty as it was an update of the slide itself but I can't assure that's the correct anwser for that specific question.
The solution I found for my problem was to set the target dirty every time the button was pressed:
if (GUILayout.Button ("Guardar")) {
if (GUI.changed) EditorUtility.SetDirty (target);
float xP = (x.intValue);
float yP = (y.intValue);
float hP = (h.intValue);
float wP = (w.intValue);
foo.setStatus (idx, xP, yP, hP, wP);
updateActiveKframe(panel);
}