Editor.Log crash log attached on bottom, taken from allowing Unity to crash from running out of memory.
I have this (simplified for understanding) hierarchy for a utility AI system:
Intelligence
List<ActionSet>
List<Action>
Evaluator
List<Consideration>
The problem I’m having is that when setting things up in the editor, once I get to the list of considerations and try adding one to the list, the editor freezes, stuck in an apparent recursive loop. Memory will eventually be consumed until Unity crashes.
The SelectType attribute works for a SerializeReferenced Action, and if I add a List at the Intelligence level that works as well. I assume SelectType is not the issue.
I can remove [SerializeReference] in ConsiderationAuthoringProxy and it doesn’t freeze but [SerializeReference] is required. Oddly I can add it back after the list element was added so SelectType works, modify the element, save and restart Unity and the data persists. It seems like whatever is extending the array can’t handle this situation, but I can’t pinpoint the cause.
Relevant portion of the serialized file, up to the list of considerations:
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1803438630}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 19a0239faa0a95f49b460bec5f2ff682, type: 3}
m_Name:
m_EditorClassIdentifier:
ActionSets:
- Name:
Value:
Actions:
- Name:
ValueAsAsset: {fileID: 0}
Value:
id: 0
ValueAsAsset: {fileID: 0}
references:
version: 1
00000000:
type: {class: ActionTest, ns: WOM.IAUS, asm: WOM.IAUS}
data:
Evaluator:
Name:
Value:
Weight: 0
Considerations: []
ValueAsAsset: {fileID: 0}
Code dump of anything potentially relevant(hopefully in order of importance, sorry it’s a lot):
[Serializable]
public abstract class GenericAsset<T> : ScriptableObject {
public T Value;
}
[Serializable]
public abstract class ScriptableObjectProxy<T, U> where U : GenericAsset<T> {
public string Name;
public T Value;
public U ValueAsAsset;
}
/// <summary>
/// Contains all action sets an ai agent can perform.
/// </summary>
public class Intelligence : MonoBehaviour, IConvertGameObjectToEntity {
public List<ActionSetProxy> ActionSets;
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) {}
}
public class ActionSetAsset : GenericAsset<ActionSet> {}
[Serializable]
public class ActionSet {
public List<ActionProxy> Actions;
}
[Serializable]
public class ActionSetProxy : ScriptableObjectProxy<ActionSet, ActionSetAsset> {}
/// <summary>
/// Editor authoring for an action, contains all considerations for performing the given action type.
/// </summary>
[Serializable]
public abstract class ActionAuthoring : IConvertGameObjectToEntity {
public EvaluatorProxy Evaluator;
public abstract void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem);
}
[Serializable]
public class ActionAuthoringAsset : GenericAsset<ActionAuthoring> {}
[Serializable]
public class ActionProxy : ScriptableObjectProxy<ActionAuthoring, ActionAuthoringAsset> {
[SerializeReference, SelectType(typeof(ActionAuthoring))]
public new ActionAuthoring Value;
}
//TODO, remove, used for testing
public class ActionTest : ActionAuthoring {
public override void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) {}
}
public class ConsiderationAuthoringAsset : GenericAsset<ConsiderationAuthoring> {}
/// <summary>
/// Base for authoring consideration components in editor. This is necessary as long as
/// there are missing inspectors for some types, ie: dots AnimationCurve. It's also
/// convenient for adding other components if needed.
/// </summary>
[Serializable]
public abstract class ConsiderationAuthoring : IConvertGameObjectToEntity {
public abstract void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem);
}
[Serializable]
public class ConsiderationAuthoringProxy : ScriptableObjectProxy<ConsiderationAuthoring, ConsiderationAuthoringAsset> {
[SerializeReference, SelectType(typeof(ConsiderationAuthoring))]
public new ConsiderationAuthoring Value;
}
//TODO, remove, for testing
public class ConsiderationTest : ConsiderationAuthoring {
public float ConsiderationFloat;
public override void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) {}
}
[CustomPropertyDrawer(typeof(SelectTypeAttribute))]
public class SelectTypeDrawer : PropertyDrawer {
Type[] implementationTypes;
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
return EditorGUI.GetPropertyHeight(property);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
if(implementationTypes is null) {
implementationTypes = GetImplementations(((SelectTypeAttribute)attribute).FieldType)
.Where(impl => !impl.IsSubclassOf(typeof(Object)))
.OrderBy(impl => impl.Name)
.ToArray();
}
EditorGUI.BeginProperty(position, label, property);
if(implementationTypes.Length > 0) {
string[] implementationNames = implementationTypes.Select(type => $"{type.FullName}").ToArray();
string propertyFullName = property.managedReferenceFullTypename.Split(' ').ElementAtOrDefault(1);
int selectedTypeIndex = Array.IndexOf(implementationNames, propertyFullName);
EditorGUI.BeginChangeCheck();
Rect selectTypePopupRect = position;
selectTypePopupRect.xMin += EditorGUIUtility.labelWidth;
selectTypePopupRect.height = EditorGUIUtility.singleLineHeight;
selectedTypeIndex = EditorGUI.Popup(selectTypePopupRect, selectedTypeIndex, implementationNames);
if(EditorGUI.EndChangeCheck()) {
property.managedReferenceValue = Activator.CreateInstance(implementationTypes[selectedTypeIndex]);
}
}
EditorGUI.PropertyField(position, property, label, includeChildren:true);
EditorGUI.EndProperty();
}
Type[] GetImplementations(Type interfaceType) {
return AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(x => interfaceType.IsAssignableFrom(x) && x != interfaceType && !x.IsAbstract)
.OrderBy(x => x.Name)
.ToArray();
}
}
6867062–801155–Editor.txt (290 KB)