- Home /
Custom Editor not saving - atypical problem
I see this question a lot, and I have tried (I think) every solution proferred on this site. Basically it's this - I created a Custom Editor Window to modify a script in my scene, and when I hit play, none of the values are saved. I'm making a grid, and I'm trying to create a custom editor to set which grid squares are "blocked" I'm using a List on the main script and an Array in GridRow because, again, I've been trying everything I can to get this stupid thing to save. And for a while it wasn't saving GridSquares within a GridRow (although it seemed to be saving the GridRow). I think I solved that by explicitly checking the first GridRow to see if the squares were valid. Obviously not an ideal solution. Why even have GridRows? To start with, I just had a jagged array of GridSquares, I didn't have GridRows. But it wasn't saving, so I changed to GridRows.
I'm going to dump relevant code, but the code dump is mainly to demonstrate the following:
- I've got [SerializeField] on private fields
- None of my fields are static
- Hell I changed most of my private fields to public just to eliminate that as a possibility
- My types derive either from Monobehavior or from UnityEngine.Object
- I set the WorldGridManager to dirty in the EditorWindow (I tried setting the individual GridRows to dirty, but that caused null reference errors)
- My types all have [System.Serializable]
- I even tried the [ExecuteInEditMode()] attribute that someone suggested
I've got Gizmo code that basically reads List<GridRow> Squares and prints out red squares for blocked and white for unblocked. I can post that too if you really need it, but I figured it was superfluous.
I have been banging my head against this for a day and a half. I am stumped as to why this is not saving.
Basically what happens right now is that when I hit play it begins spamming errors: NullReferenceException: Object reference not set to an instance of an object On
public GridSquare this[int index]
{
get
{
return Squares[index];
}
In GridRow - sorry for the duplicate "Squares" variable there, but basically GridRow.Squares is null. So when it's getting checked below it calls WorldGridManager.Squares[X][Y].Blocked - the WorldGridManager.Squares isn't null, and is returning a GridRow, and then GridRow.Squares IS null, despite the fact that GridRow.Squares was created at the same time as GridRow.
Any and all help will be appreciated. I'm really starting to wonder if this is some kind of bug with Unity's serializer. (Something about Serializing fields within fields?)
I'd really prefer not to have to create my own serializer for this, as that's kind of beyond the scope of this particular project.
Thanks ahead of time. I'm not new to programming, but I'm pretty new to Unity, and some of the automagic stuff is giving me fits. Code dump!
using UnityEngine; using System.Collections; using System.Collections.Generic; [ExecuteInEditMode()] [System.Serializable] public class WorldGridManager : MonoBehaviour { public bool ShowGrid; public int GridZCount; public int GridXCount; public float SquareZLength; public float SquareXLength; [SerializeField] [HideInInspector] public List<GridRow> Squares; [SerializeField] [HideInInspector] protected bool _initialized; public void Init() { if (Squares == null || Squares.Count == 0 || Squares[0].Squares == null) { CreateGrid(); } } public void SetSquareBlocked(int X, int Y, bool Blocked) { Squares[X][Y].Blocked = Blocked; } public bool CheckBlocked(int X, int Y) { return Squares[X][Y].Blocked; } private void CreateGrid() { if (GridXCount > 0 && GridZCount > 0) { Debug.Log("Creating Grid - Squares reset"); Squares = new List<GridRow>(); for (int x = 0; x < GridXCount; x++) { GridRow innerRow = new GridRow(); innerRow.Squares = new GridSquare[GridZCount]; for (int z = 0; z < GridZCount; z++) { GridSquare square = new GridSquare(); square.GridPosition = new Vector3(x, 0f, z); square.WorldPosition = this.gameObject.transform.position + new Vector3(SquareXLength * x, 0f, 0f) //formatted for question - new Vector3(0f, 0f, SquareZLength * z); //formatted for question square.Blocked = false; square.Objects = new GameObject[1]; innerRow[z] = square; } Squares.Add(innerRow); } _initialized = true; } } }
using UnityEngine; using System.Collections; using System.Collections.Generic; [System.Serializable] public class GridSquare : Object { public Vector3 GridPosition; public Vector3 WorldPosition; public GameObject[] Objects; public bool Blocked; } [System.Serializable] public class GridRow : Object { [SerializeField] public GridSquare[] Squares; public GridSquare this[int index] { get { return Squares[index]; } set { Squares[index] = value; } } public void Add(GridSquare Square) { //Squares.Add(Square); } }
using UnityEngine; using System.Collections; using UnityEditor; public class WorldGridEditorWindow : UnityEditor.EditorWindow { protected WorldGridManager manager; protected static bool _initialized = false; [MenuItem("Window/World Grid Editor")] static void Init() { EditorWindow window = EditorWindow.GetWindow(typeof(WorldGridEditorWindow)); } void OnGUI() { manager = FindObjectOfType(typeof(WorldGridManager)) as WorldGridManager; manager.Init();
// The actual window code goes here
if (manager.GridXCount > 1 && manager.GridZCount > 1)
{
float overallZ = manager.GridZCount * (manager.SquareZLength * 5);
float overallX = manager.GridXCount * (manager.SquareXLength * 5);
GUI.Box(new Rect(0, 0, overallX, overallZ), GUIContent.none);
for (int x = 0; x < manager.GridXCount; x++)
{
for (int z = 0; z < manager.GridZCount; z++)
{
//bool blocked = manager.CheckBlocked(x, z);
if (GUI.Toggle(new Rect(x * (manager.SquareXLength * 5)
, z * (manager.SquareZLength * 5)
, (manager.SquareXLength * 5)
, (manager.SquareZLength * 5))
, manager.CheckBlocked(x, z), GUIContent.none)) //Formatted for question
{
Debug.Log("Set Blocked!");
manager.SetSquareBlocked(x, z, true);
EditorUtility.SetDirty(manager);
}
else
{
manager.SetSquareBlocked(x, z, false);
EditorUtility.SetDirty(manager);
}
}
}
}
}
}
Any chance of formatting your code to use more lines and indentation?
I think you just need more line-feeds. The indentation is actually not that bad!
Figured out how to edit it correctly. turns out the code tag screws everything up.
Answer by testure · Oct 07, 2011 at 03:20 AM
Sorry if this isn't relevant- Your code is kind of hard to read so I just skimmed it.
But anyway, Unity won't serialize a jagged or multidim array.. if you're doing that, you need to store the information in a single dimensional array and rebuild your jagged array at runtime.
Well, that's good to know, as I was going to rewrite stuff to try a multidimensional array - but no, I'm not using either at the moment. But I A$$anonymous$$ using a list of GridRows which in turn have a list of GridSquares. $$anonymous$$y guess is that Unity doesn't correctly serialize that either.
Your answer
![](https://koobas.hobune.stream/wayback/20220613000527im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Custom brush tool? 0 Answers
In search of a gradient editor tool.. 0 Answers
Different approach to loading XML data 1 Answer
Invert DrawLine direction in editor Window. 1 Answer
Working with SerializedObjects / Properties in EditorWindow 0 Answers