Custom Editor - MemoryStream Corrupt

I’m making a custom inspector using serializedObject.update() to initialize my target.

I set up a list of two arrays side by side, with a delete button along side each one, and an add button at the end.
Enter an object on the top of the element, adjust a value or delete it on the bottom.

When going to delete it, no matter how I try to accomplish this, I get an error of -

The line being referenced is the “ApplyModifiedProperties” line.
The code executing when the error happens is that I’m deleting an element from an array using -

if (ind != list.arraySize - 1)
			{
				list.GetArrayElementAtIndex(ind).objectReferenceValue = list.GetArrayElementAtIndex(list.arraySize - 1).objectReferenceValue;
			}
			list.arraySize--;

I’ve tried about four different methods of deleting the entry, it’s not the script for deleting it. What reasons might I get this error? I don’t think it’s as simple as an index out of bounds as the error suggests.

Any reason why you’re not simply using DeleteArrayElementAtIndex?

I had done that in a combination of ways. Using it first null’s the element rather than removing it, so I thought perhaps this method would solve my error, however it seems the code is not the error’s problem, or at least not the deletion code.

Ah yes, the weird nulling delete. I mention this in my Custom List editor tutorial. You can work around that by simply calling delete twice in a row. To be save, delete once and check whether the array’s size has been reduced. If not, they it nulled instead so delete again, for real this time.

Oh, you wrote that tutorial! Amazing piece of work that, makes things very simple. I had actually tried your method first, however it gives me the same error. I even get this memorystream corruption error when I set a button to just delete once, and then hit the button twice. When it goes to actually remove the array element and not just null it, that’s when I’m getting this error, though, no change in the deletion code seems to alter this.

Thanks!
Then the deletion process in isolation isn’t causing the problem. What else are you doing?

Ha, well, a number of things, here’s the editor at the moment:

using UnityEngine;
using UnityEditor;
using System.Collections;
using System;


[CustomEditor(typeof(citygenerator)), CanEditMultipleObjects]
public class CityGenEditor : Editor {

	public void OnEnable(){



	}

	public override void OnInspectorGUI () {
		serializedObject.Update();

		GUIContent sizeLabel = new GUIContent("City Size:");
		EditorList.Show (serializedObject.FindProperty("size"),sizeLabel,EditorListOption.IntSlider);

		GUIContent scaleLabel = new GUIContent("City Scale:");
		EditorList.Show (serializedObject.FindProperty("scale"),scaleLabel,EditorListOption.IntSlider);

		GUIContent axesLabel = new GUIContent("Starting Axes:");
		EditorList.Show (serializedObject.FindProperty("Axes"),axesLabel,EditorListOption.Prop);

		serializedObject.ApplyModifiedProperties();

		EditorGUILayout.Space() ;

		GUIContent sbsarLabel = new GUIContent("Use .sbsar's:");
		EditorList.Show (serializedObject.FindProperty("UseProceduralTextures"),sbsarLabel,EditorListOption.Prop);

		GUIContent btextLabel = new GUIContent("Use one Texture:");
		EditorList.Show (serializedObject.FindProperty("UseBaseTexturesOnly"),btextLabel,EditorListOption.Prop);

		GUIContent collLabel = new GUIContent("Use Colliders:");
		EditorList.Show (serializedObject.FindProperty("UseColliders"),collLabel ,EditorListOption.Prop);

		serializedObject.ApplyModifiedProperties();
		
		EditorGUILayout.Space() ;

		GUIContent bmeshLabel = new GUIContent("Building Meshes");
		EditorList.Show (serializedObject.FindProperty("BuildingMeshes"),serializedObject.FindProperty("BuildingSizes"),serializedObject.FindProperty("BuildingArrSize"),serializedObject.FindProperty("BuildingArrBool"),bmeshLabel ,EditorListOption.ParentList);

		serializedObject.ApplyModifiedProperties();

	}

}

public static class EditorList {
	
	public static void Show (SerializedProperty list, GUIContent label, EditorListOption options) {

		bool
			asIntSlide = (options  EditorListOption.IntSlider) != 0,
			asProp = (options  EditorListOption.Prop) != 0,
			asList = (options  EditorListOption.List) != 0;

		if(asIntSlide){
			EditorGUILayout.IntSlider(list,0,50,label);

		} else if(asProp){
			EditorGUILayout.PropertyField(list,label);

		} else if(asList){

			EditorGUILayout.PropertyField (list);

			if(list.isExpanded){

				EditorGUI.indentLevel++;

				EditorGUILayout.PropertyField(list.FindPropertyRelative("Array.size"));

				for(int i = 0;i < list.arraySize;i++){

					EditorGUILayout.PropertyField (list.GetArrayElementAtIndex(i));

				}

				EditorGUI.indentLevel--;

			}
		}
	}

	public static void Show (SerializedProperty list, SerializedProperty child, SerializedProperty size, SerializedProperty foldout, GUIContent label, EditorListOption options) {
		
		bool 
			asPList = (options  EditorListOption.ParentList) != 0;

		while (foldout.arraySize > list.arraySize) {
			foldout.DeleteArrayElementAtIndex(foldout.arraySize - 1);
		}
		
		while(foldout.arraySize < list.arraySize) {
			foldout.InsertArrayElementAtIndex(foldout.arraySize);
		}

		while (child.arraySize > list.arraySize) {
			child.DeleteArrayElementAtIndex(child.arraySize - 1);
		}

		while(child.arraySize < list.arraySize) {
			child.InsertArrayElementAtIndex(child.arraySize);
		}
		
		if(asPList){

			EditorGUILayout.PropertyField (list);
			
			if(list.isExpanded){
				
				EditorGUI.indentLevel++;
					
				for(int i = 0;i < list.arraySize;i++){

					GUIContent intLabel = new GUIContent("Building " + i.ToString());
					foldout.GetArrayElementAtIndex(i).boolValue = EditorGUILayout.Foldout(foldout.GetArrayElementAtIndex(i).boolValue, intLabel);

					if(foldout.GetArrayElementAtIndex(i).boolValue){
						EditorGUILayout.PropertyField (list.GetArrayElementAtIndex(i));

						EditorGUILayout.BeginHorizontal();
						EditorGUILayout.PropertyField (child.GetArrayElementAtIndex(i));
						DeleteButton (list,child,i);
						EditorGUILayout.EndHorizontal();
					}

				}

				AddButton(list);
				
				EditorGUI.indentLevel--;
				
			}
		}
	}

	private static GUIContent
		newEntry = new GUIContent("+", "Add a building"),
		deleteEntry = new GUIContent("-", "Remove building");

	private static GUILayoutOption miniButtonWidth = GUILayout.Width(20f);

	private static void AddButton (SerializedProperty list) {
		EditorGUILayout.BeginHorizontal();

		if(GUILayout.Button(newEntry,EditorStyles.miniButton,miniButtonWidth)){
			list.InsertArrayElementAtIndex(list.arraySize);
		}

		//GUILayout.Button(deleteEntry,EditorStyles.miniButton,miniButtonWidth);
		EditorGUILayout.EndHorizontal();
	}

	private static void DeleteButton (SerializedProperty list, SerializedProperty child, int ind) {
	
		if(GUILayout.Button(deleteEntry,EditorStyles.miniButton,miniButtonWidth)){

			if (ind != list.arraySize - 1)
			{
				list.GetArrayElementAtIndex(ind).objectReferenceValue = list.GetArrayElementAtIndex(list.arraySize - 1).objectReferenceValue;
			}
			list.arraySize--;

			if (ind != child.arraySize - 1)
			{
				child.GetArrayElementAtIndex(ind).objectReferenceValue = child.GetArrayElementAtIndex(child.arraySize - 1).objectReferenceValue;
			}
			child.arraySize--;

		}
	}

	private static void DeleteButton (SerializedProperty list, int ind) {

		if(GUILayout.Button(deleteEntry,EditorStyles.miniButton,miniButtonWidth)){
			
			if (ind != list.arraySize - 1)
			{
				list.GetArrayElementAtIndex(ind).objectReferenceValue = list.GetArrayElementAtIndex(list.arraySize - 1).objectReferenceValue;
			}
			list.arraySize--;
			
		}
	}


}

[Flags]
public enum EditorListOption {

	None = 0,
	IntSlider = 1,
	Prop = 2,
	List = 4,
	ParentList = 8,
	Default = 0
}

Looks like it’s time you renamed EditorList to something more grand. :slight_smile:

The first thing I would do is make sure that serializedObject.ApplyModifiedProperties(); is called exactly once, at the end of OnInspectorGUI. The pattern is update - modify, modify, modify - apply. I have no idea what could go wrong or accidentally still work when you deviate from that.

I found it with a hunch while staring at my code on the forum, funny how that works. The while loops I used to ensure that the arrays are all the same size, I changed those to use the .arraySize-- and ++ operators instead, works like a charm now. Not sure what the confliction was exactly there, but I figured the while loop might be continually running as a result of the insert/delete methods.

        while (foldout.arraySize > list.arraySize) {

            foldout.DeleteArrayElementAtIndex(foldout.arraySize - 1);

        }

       

        while(foldout.arraySize < list.arraySize) {

            foldout.InsertArrayElementAtIndex(foldout.arraySize);

        }

 

        while (child.arraySize > list.arraySize) {

            child.DeleteArrayElementAtIndex(child.arraySize - 1);

        }

 

        while(child.arraySize < list.arraySize) {

            child.InsertArrayElementAtIndex(child.arraySize);

        }

I changed this to use “child.arraySize++;” and “child.arraySize–;” instead of delete/insert.

I like the EditorList name, it’s just perfectly generic enough to always apply. It is grand! :smile:

Edit:
P.S. Thought about it some more. The issue is I was nulling the child and foldout entries during those loops, and not ensuring their deletion. So the delete while loop would conflict with the delete button instance.

Oh yes gotta be real careful with size changes in loops. Great that you made it work!