ScriptCore: Properly use nullable

This commit is contained in:
Simon Lübeß
2024-01-12 00:17:40 +01:00
parent 3d0c010139
commit 55b4be05c2
6 changed files with 109 additions and 76 deletions
+6 -6
View File
@@ -87,15 +87,15 @@ public class DictionaryEditor
if (isEntryOpen) if (isEntryOpen)
{ {
object newKey = EntityEditor.ShowFieldEditor(entry.Key, entry.Key?.GetType() ?? keyType, "Key"); object? newKey = EntityEditor.ShowFieldEditor(entry.Key, entry.Key?.GetType() ?? keyType, "Key");
if (newKey != EntityEditor.DidNotChange) if (newKey != EntityEditor.DidNotChange && newKey != null)
{ {
keysToDelete.Add(entry.Key!); keysToDelete.Add(entry.Key!);
newEntries.Add(new DictionaryEntry(newKey, entry.Value)); newEntries.Add(new DictionaryEntry(newKey, entry.Value));
} }
object newValue = EntityEditor.ShowFieldEditor(entry.Value, entry.Value?.GetType() ?? valueType, "Value"); object? newValue = EntityEditor.ShowFieldEditor(entry.Value, entry.Value?.GetType() ?? valueType, "Value");
if (newValue != EntityEditor.DidNotChange) if (newValue != EntityEditor.DidNotChange)
{ {
@@ -129,9 +129,9 @@ public class DictionaryEditor
if (isEntryOpen) if (isEntryOpen)
{ {
object newKey = EntityEditor.ShowFieldEditor(_newDictionaryValue.Key, keyType, "Key"); object? newKey = EntityEditor.ShowFieldEditor(_newDictionaryValue.Key, keyType, "Key");
if (newKey != EntityEditor.DidNotChange) if (newKey != EntityEditor.DidNotChange && newKey != null)
{ {
newEntries.Add(new DictionaryEntry(newKey, _newDictionaryValue.Value)); newEntries.Add(new DictionaryEntry(newKey, _newDictionaryValue.Value));
_dictionaryForNewValue = null; _dictionaryForNewValue = null;
@@ -139,7 +139,7 @@ public class DictionaryEditor
_keyLastCreated = newKey; _keyLastCreated = newKey;
} }
object newValue = EntityEditor.ShowFieldEditor(_newDictionaryValue.Value, _newDictionaryValue.Value?.GetType() ?? valueType, "Value"); object? newValue = EntityEditor.ShowFieldEditor(_newDictionaryValue.Value, _newDictionaryValue.Value?.GetType() ?? valueType, "Value");
if (newValue != EntityEditor.DidNotChange) if (newValue != EntityEditor.DidNotChange)
{ {
+72 -44
View File
@@ -23,7 +23,7 @@ internal class EntityEditor
{ {
public static readonly DidNotChange DidNotChange = new DidNotChange(); public static readonly DidNotChange DidNotChange = new DidNotChange();
private delegate object? ShowCustomEditorMethod(object reference, Type fieldType, string fieldName); private delegate object? ShowCustomEditorMethod(object? reference, Type fieldType, string fieldName);
private static Dictionary<Type, ShowCustomEditorMethod> _customEditors = new(); private static Dictionary<Type, ShowCustomEditorMethod> _customEditors = new();
@@ -51,7 +51,7 @@ internal class EntityEditor
} }
} }
private static bool TryShowCustomEditor(object reference, Type fieldType, string fieldName, out object? editedValue) private static bool TryShowCustomEditor(object? reference, Type fieldType, string fieldName, out object? editedValue)
{ {
editedValue = DidNotChange; editedValue = DidNotChange;
@@ -332,11 +332,11 @@ internal class EntityEditor
return newValue; return newValue;
} }
private static object ShowEnumEditor(object reference, Type fieldType, string fieldName) private static object ShowEnumEditor(object? reference, Type fieldType, string fieldName)
{ {
object newValue = DidNotChange; object newValue = DidNotChange;
if (ImGui.BeginCombo(fieldName, reference.ToString())) if (ImGui.BeginCombo(fieldName, reference?.ToString()))
{ {
foreach (object enumValue in Enum.GetValues(fieldType)) foreach (object enumValue in Enum.GetValues(fieldType))
{ {
@@ -352,13 +352,13 @@ internal class EntityEditor
return newValue; return newValue;
} }
public static object ShowFieldEditor(object reference, Type fieldType, string fieldName, IEnumerable<Attribute>? attributes = null) public static object? ShowFieldEditor(object? reference, Type fieldType, string fieldName, IEnumerable<Attribute>? attributes = null)
{ {
ReadonlyAttribute readonlyAttribute = GetAttribute<ReadonlyAttribute>(attributes); ReadonlyAttribute? readonlyAttribute = GetAttribute<ReadonlyAttribute>(attributes);
ImGui.BeginDisabled(readonlyAttribute != null); ImGui.BeginDisabled(readonlyAttribute != null);
object? newValue = DidNotChange; object? newValue;
if (TryShowCustomEditor(reference, fieldType, fieldName, out newValue)) if (TryShowCustomEditor(reference, fieldType, fieldName, out newValue))
{ {
@@ -396,7 +396,7 @@ internal class EntityEditor
} }
else if (fieldType == typeof(bool2)) else if (fieldType == typeof(bool2))
{ {
bool2 value = (bool2)reference; bool2 value = (bool2)reference!;
ImGui.TextUnformatted(fieldName); ImGui.TextUnformatted(fieldName);
@@ -496,14 +496,14 @@ internal class EntityEditor
return newValue; return newValue;
} }
private static object ShowComponentDropTarget(string fieldName, Type fieldType, object currentValue) private static object? ShowComponentDropTarget(string fieldName, Type fieldType, object? currentValue)
{ {
object newValue = DidNotChange; object? newValue = DidNotChange;
ImGui.Text($"{fieldName}: "); ImGui.Text($"{fieldName}: ");
ImGui.SameLine(); ImGui.SameLine();
Component component = currentValue as Component; Component? component = currentValue as Component;
string entityName = "None"; string entityName = "None";
@@ -512,7 +512,7 @@ internal class EntityEditor
entityName = component.Entity.Name; entityName = component.Entity.Name;
} }
Type actualType = component?.GetType(); Type? actualType = component?.GetType();
entityName += $" ({(actualType ?? fieldType).Name})"; entityName += $" ({(actualType ?? fieldType).Name})";
@@ -570,23 +570,23 @@ internal class EntityEditor
return newValue; return newValue;
} }
private static object ShowEntityDropTarget(string fieldName, Type fieldType, object currentValue) private static object? ShowEntityDropTarget(string fieldName, Type fieldType, object? currentValue)
{ {
object newValue = DidNotChange; object? newValue = DidNotChange;
ImGui.Text($"{fieldName}: "); ImGui.Text($"{fieldName}: ");
ImGui.SameLine(); ImGui.SameLine();
string entityName = "None"; string entityName = "None";
Entity entity = currentValue as Entity; Entity? entity = currentValue as Entity;
if (entity != null) if (entity != null)
{ {
entityName = entity.Name; entityName = entity.Name;
} }
Type actualType = entity?.GetType(); Type? actualType = entity?.GetType();
entityName += $" ({(actualType ?? fieldType).Name})"; entityName += $" ({(actualType ?? fieldType).Name})";
@@ -620,7 +620,7 @@ internal class EntityEditor
} }
else else
{ {
Entity scriptInstance = Entity.GetScriptReference(draggedId, typeof(Entity)); Entity? scriptInstance = Entity.GetScriptReference(draggedId, typeof(Entity));
allowDrop = fieldType.IsInstanceOfType(scriptInstance); allowDrop = fieldType.IsInstanceOfType(scriptInstance);
} }
@@ -661,11 +661,11 @@ internal class EntityEditor
return newValue; return newValue;
} }
private static object ShowStringEditor(object reference, Type fieldType, string fieldName, IEnumerable<Attribute> attributes) private static object ShowStringEditor(object? reference, Type fieldType, string fieldName, IEnumerable<Attribute>? attributes)
{ {
object newValue = DidNotChange; object newValue = DidNotChange;
TextFieldAttribute textField = GetAttribute<TextFieldAttribute>(attributes); TextFieldAttribute? textField = GetAttribute<TextFieldAttribute>(attributes);
string value = reference as string ?? $"{float.MinValue}"; string value = reference as string ?? $"{float.MinValue}";
@@ -684,7 +684,7 @@ internal class EntityEditor
return newValue; return newValue;
} }
public static void ShowEditor(Type type, object reference) public static void ShowEditor(Type type, object? reference)
{ {
int i = 0; int i = 0;
@@ -700,7 +700,7 @@ internal class EntityEditor
IEnumerable<Attribute> attributes = field.GetCustomAttributes(); IEnumerable<Attribute> attributes = field.GetCustomAttributes();
object newValue = ShowFieldEditor(value, value?.GetType() ?? field.FieldType, field.Name, attributes); object? newValue = ShowFieldEditor(value, value?.GetType() ?? field.FieldType, field.Name, attributes);
if (newValue != DidNotChange) if (newValue != DidNotChange)
{ {
@@ -748,12 +748,14 @@ internal class EntityEditor
public int Element; public int Element;
} }
private static object ShowListEditor(Type fieldType, object fieldValue, string fieldName) private static object? ShowListEditor(Type fieldType, object? fieldValue, string fieldName)
{ {
Type elementType = fieldType.GenericTypeArguments[0]; Type elementType = fieldType.GenericTypeArguments[0];
void AddElement(IList list, ref object newList) void AddElement(IList? list, out object? newList)
{ {
newList = DidNotChange;
if (list == null) if (list == null)
{ {
newList = Activator.CreateInstance(fieldType); newList = Activator.CreateInstance(fieldType);
@@ -762,36 +764,50 @@ internal class EntityEditor
Debug.Assert(list != null); Debug.Assert(list != null);
} }
object newElement = ActivatorExtension.CreateInstanceSafe(elementType); object? newElement = ActivatorExtension.CreateInstanceSafe(elementType);
list.Add(newElement); list?.Add(newElement);
} }
void RemoveElement(IList list, ref object newList) void RemoveElement(IList? list, out object? newList)
{
newList = DidNotChange;
if (list == null)
return;
if (list.Count == 0)
{
newList = null;
}
else
{ {
list.RemoveAt(list.Count - 1); list.RemoveAt(list.Count - 1);
} }
}
return ShowGenericListEditor(fieldType, elementType, (IEnumerable)fieldValue, fieldName, return ShowGenericListEditor(fieldType, elementType, (IEnumerable?)fieldValue, fieldName,
AddElement, RemoveElement); AddElement, RemoveElement);
} }
private static object ShowArrayEditor(Type fieldType, object fieldValue, string fieldName) private static object? ShowArrayEditor(Type fieldType, object? fieldValue, string fieldName)
{ {
Debug.Assert(fieldType.IsArray); Debug.Assert(fieldType.IsArray);
Type elementType = fieldType.GetElementType(); Type? elementType = fieldType.GetElementType();
Debug.Assert(elementType != null); Debug.Assert(elementType != null);
Array myArray = fieldValue as Array; Array? myArray = fieldValue as Array;
if (myArray?.Rank > 1) if (myArray?.Rank > 1)
{ {
throw new NotImplementedException("Multidimensional arrays are not yet supported."); throw new NotImplementedException("Multidimensional arrays are not yet supported.");
} }
void AddElement(IList list, ref object newList) void AddElement(IList? list, out object? newList)
{ {
newList = DidNotChange;
int newIndex = 0; int newIndex = 0;
if (list == null) if (list == null)
@@ -812,25 +828,37 @@ internal class EntityEditor
((IList)newList)[newIndex] = newElement; ((IList)newList)[newIndex] = newElement;
} }
void RemoveElement(IList list, ref object newList) void RemoveElement(IList? list, out object? newList)
{
newList = DidNotChange;
if (list == null)
return;
if (list.Count == 0)
{
newList = null;
}
else
{ {
Array newArray = Array.CreateInstance(elementType, list.Count - 1); Array newArray = Array.CreateInstance(elementType, list.Count - 1);
Array.Copy((Array)list, newArray, newArray.Length); Array.Copy((Array)list, newArray, newArray.Length);
newList = newArray; newList = newArray;
} }
}
return ShowGenericListEditor(fieldType, elementType, (IEnumerable)fieldValue, fieldName, return ShowGenericListEditor(fieldType, elementType!, (IEnumerable?)fieldValue, fieldName,
AddElement, RemoveElement); AddElement, RemoveElement);
} }
public delegate void ModifyList(IList currentList, ref object oldList); public delegate void ModifyList(IList? currentList, out object? oldList);
private static object ShowGenericListEditor(Type listType, Type elementType, IEnumerable list, string fieldName, private static object? ShowGenericListEditor(Type listType, Type elementType, IEnumerable? list, string fieldName,
ModifyList addElement, ModifyList removeElement) ModifyList addElement, ModifyList removeElement)
{ {
object newList = DidNotChange; object? newList = DidNotChange;
IList myList = list as IList; IList? myList = list as IList;
// The buttons should always be visible -> save whether the node is open // The buttons should always be visible -> save whether the node is open
// If we have no instance, the user shouldn't be able to open the list // If we have no instance, the user shouldn't be able to open the list
@@ -847,7 +875,7 @@ internal class EntityEditor
if (ImGui.SmallButton("+")) if (ImGui.SmallButton("+"))
{ {
addElement(myList, ref newList); addElement(myList, out newList);
} }
ImGuiExtension.AttachTooltip("Add a new Element at the end of the list."); ImGuiExtension.AttachTooltip("Add a new Element at the end of the list.");
@@ -858,7 +886,7 @@ internal class EntityEditor
if (ImGui.SmallButton("-")) if (ImGui.SmallButton("-"))
{ {
removeElement(myList, ref newList); removeElement(myList, out newList);
} }
ImGuiExtension.AttachTooltip("Remove the last Element from the list."); ImGuiExtension.AttachTooltip("Remove the last Element from the list.");
@@ -869,7 +897,7 @@ internal class EntityEditor
{ {
Debug.Assert(myList != null, "Opened tree node even though it should have been a leaf!"); Debug.Assert(myList != null, "Opened tree node even though it should have been a leaf!");
/// Returns true if something was dropped into the droptarget // Returns true if something was dropped into the droptarget
bool DropTarget(int insertIndex, string tooltip) bool DropTarget(int insertIndex, string tooltip)
{ {
bool dropped = false; bool dropped = false;
@@ -887,7 +915,7 @@ internal class EntityEditor
ref ListPayload payload = ref Unsafe.AsRef<ListPayload>((void*)payloadPtr.Data); ref ListPayload payload = ref Unsafe.AsRef<ListPayload>((void*)payloadPtr.Data);
// Make sure the index is still correct // Make sure the index is still correct
if (payload.Element < myList.Count) if (payload.Element < myList!.Count)
{ {
object item = myList[payload.Element]; object item = myList[payload.Element];
@@ -917,7 +945,7 @@ internal class EntityEditor
bool orderChanged = false; bool orderChanged = false;
for (int i = 0, id = 0; i < myList.Count; i++, id++) for (int i = 0, id = 0; i < myList!.Count; i++, id++)
{ {
ImGui.PushID(id); ImGui.PushID(id);
@@ -957,7 +985,7 @@ internal class EntityEditor
ImGui.SameLine(); ImGui.SameLine();
object newValue = ShowFieldEditor(element, element?.GetType() ?? elementType, $"Element {i}"); object? newValue = ShowFieldEditor(element, element?.GetType() ?? elementType, $"Element {i}");
// Don't apply changes, when the order changed // Don't apply changes, when the order changed
if (newValue != DidNotChange && !orderChanged) if (newValue != DidNotChange && !orderChanged)
@@ -981,7 +1009,7 @@ internal class EntityEditor
private static T ReadStaticField<T>(string name) private static T ReadStaticField<T>(string name)
{ {
FieldInfo field = typeof(T).GetField(name, BindingFlags.Public | BindingFlags.Static); FieldInfo? field = typeof(T).GetField(name, BindingFlags.Public | BindingFlags.Static);
if (field == null) if (field == null)
{ {
+1 -1
View File
@@ -18,5 +18,5 @@ public sealed class ShowInEditorAttribute : Attribute
/// The label with which the field will be shown in the editor. /// The label with which the field will be shown in the editor.
/// If not specified, the fields name will be used. /// If not specified, the fields name will be used.
/// </summary> /// </summary>
public string DisplayName { get; set; } = null; public string? DisplayName { get; set; } = null;
} }
@@ -277,7 +277,7 @@ public class DeserializationObject
object currentValue = field.GetValue(obj); object currentValue = field.GetValue(obj);
object deserializeValue = DeserializeField(currentValue, field.FieldType, field.Name); object? deserializeValue = DeserializeField(currentValue, field.FieldType, field.Name);
if (deserializeValue != NoValueDeserialized) if (deserializeValue != NoValueDeserialized)
{ {
@@ -347,7 +347,10 @@ public class DeserializationObject
} }
if (fieldType.IsValueType) if (fieldType.IsValueType)
{ {
return DeserializeStruct(fieldName, fieldValue); // Null Value doesn't make any sense, because we need a value to deserialize into!
Debug.Assert(fieldValue != null);
return DeserializeStruct(fieldName, fieldValue!);
} }
if (fieldType.IsClass) if (fieldType.IsClass)
{ {
@@ -79,9 +79,9 @@ public static class DictionarySerializer
return null; return null;
// Get serialization container for the instance // Get serialization container for the instance
DeserializationObject deserializedObject = container.GetDeserializedObject(id); DeserializationObject? deserializedObject = container.GetDeserializedObject(id);
Type type = deserializedObject.StoredType; Type? type = deserializedObject?.StoredType;
if (type?.IsAssignableTo(fieldType) != true) if (type?.IsAssignableTo(fieldType) != true)
return DeserializationObject.NoValueDeserialized; return DeserializationObject.NoValueDeserialized;
@@ -89,7 +89,7 @@ public static class DictionarySerializer
Type keyType = fieldType.GetGenericArguments()[0]; Type keyType = fieldType.GetGenericArguments()[0];
Type valueType = fieldType.GetGenericArguments()[1]; Type valueType = fieldType.GetGenericArguments()[1];
int count = deserializedObject.GetFieldValue<int>("Count", SerializationType.Int32); int count = deserializedObject!.GetFieldValue<int>("Count", SerializationType.Int32);
// Create instance, pass in capacity // Create instance, pass in capacity
object? instance = ActivatorExtension.CreateInstanceSafe(type, count); object? instance = ActivatorExtension.CreateInstanceSafe(type, count);
@@ -103,7 +103,7 @@ public static class DictionarySerializer
deserializedObject.PushScope(i.ToString()); deserializedObject.PushScope(i.ToString());
object? key = deserializedObject.DeserializeField(null, keyType, "Key"); object? key = deserializedObject.DeserializeField(null, keyType, "Key");
object value = deserializedObject.DeserializeField(null, valueType, "Value"); object? value = deserializedObject.DeserializeField(null, valueType, "Value");
if (key != null) if (key != null)
{ {
+17 -15
View File
@@ -18,7 +18,7 @@ public class SerializedObject
private Stack<string> _structScope = new(); private Stack<string> _structScope = new();
private string _structScopeName; private string _structScopeName = "";
private delegate void SerializeMethod(SerializedObject container, string fieldName, object? fieldValue, Type fieldType); private delegate void SerializeMethod(SerializedObject container, string fieldName, object? fieldValue, Type fieldType);
@@ -86,7 +86,7 @@ public class SerializedObject
_structScopeName = _structScopeName.Remove(_structScopeName.Length - scopeToRemove.Length - 1); _structScopeName = _structScopeName.Remove(_structScopeName.Length - scopeToRemove.Length - 1);
} }
public void AddField(string fieldName, SerializationType serializationType, object value, string? fullTypeName = null) public void AddField(string fieldName, SerializationType serializationType, object? value, string? fullTypeName = null)
{ {
string completeFieldName = $"{_structScopeName}{fieldName}"; string completeFieldName = $"{_structScopeName}{fieldName}";
@@ -107,14 +107,14 @@ public class SerializedObject
if (!EntitySerializer.SerializeField(field)) if (!EntitySerializer.SerializeField(field))
continue; continue;
object fieldValue = field.GetValue(obj); object? fieldValue = field.GetValue(obj);
Type fieldType = fieldValue?.GetType() ?? field.FieldType; Type fieldType = fieldValue?.GetType() ?? field.FieldType;
SerializeField(field.Name, fieldValue, fieldType); SerializeField(field.Name, fieldValue, fieldType);
} }
} }
private bool TryCustomSerializer(string fieldName, object fieldValue, Type fieldType) private bool TryCustomSerializer(string fieldName, object? fieldValue, Type fieldType)
{ {
try try
{ {
@@ -142,11 +142,12 @@ public class SerializedObject
return false; return false;
} }
public void SerializeField(string fieldName, object fieldValue, Type fieldType) public void SerializeField(string fieldName, object? fieldValue, Type fieldType)
{ {
if (fieldType.IsPrimitive || fieldType == typeof(decimal)) if (fieldType.IsPrimitive || fieldType == typeof(decimal))
{ {
SerializePrimitive(fieldName, fieldValue, fieldType); // Primitives can't be null
SerializePrimitive(fieldName, fieldValue!, fieldType);
} }
else if (fieldType == typeof(string)) else if (fieldType == typeof(string))
{ {
@@ -158,14 +159,14 @@ public class SerializedObject
} }
else if (fieldType.IsArray) else if (fieldType.IsArray)
{ {
Array myArray = fieldValue as Array; Array? myArray = fieldValue as Array;
if (myArray?.Rank > 1) if (myArray?.Rank > 1)
{ {
throw new NotImplementedException("Serializing multidimensional arrays is not yet supported."); throw new NotImplementedException("Serializing multidimensional arrays is not yet supported.");
} }
SerializeList(fieldName, fieldValue, fieldType, fieldType.GetElementType()); SerializeList(fieldName, fieldValue, fieldType, fieldType.GetElementType()!);
} }
else if (fieldType.IsGenericType) else if (fieldType.IsGenericType)
{ {
@@ -191,7 +192,8 @@ public class SerializedObject
if (TryCustomSerializer(fieldName, fieldValue, fieldType)) if (TryCustomSerializer(fieldName, fieldValue, fieldType))
return; return;
SerializeStruct(fieldName, fieldValue, fieldType); // Value Types cant be null
SerializeStruct(fieldName, fieldValue!, fieldType);
} }
else if (fieldType.IsClass) else if (fieldType.IsClass)
{ {
@@ -206,7 +208,7 @@ public class SerializedObject
} }
} }
public void SerializeList(string fieldName, object listObject, Type fieldType, Type elementType) public void SerializeList(string fieldName, object? listObject, Type fieldType, Type elementType)
{ {
if (listObject == null) if (listObject == null)
{ {
@@ -274,9 +276,9 @@ public class SerializedObject
AddField(fieldName, type, fieldValue); AddField(fieldName, type, fieldValue);
} }
public void SerializeEnum(string fieldName, object fieldValue, Type fieldType) public void SerializeEnum(string fieldName, object? fieldValue, Type fieldType)
{ {
AddField(fieldName, SerializationType.Enum, fieldValue.ToString()); AddField(fieldName, SerializationType.Enum, fieldValue?.ToString());
} }
public void SerializeStruct(string fieldName, object fieldValue, Type fieldType) public void SerializeStruct(string fieldName, object fieldValue, Type fieldType)
@@ -288,15 +290,15 @@ public class SerializedObject
PopScope(); PopScope();
} }
public void SerializeClass(string fieldName, object fieldValue, Type fieldType) public void SerializeClass(string fieldName, object? fieldValue, Type fieldType)
{ {
if (typeof(Entity).IsAssignableFrom(fieldType)) if (typeof(Entity).IsAssignableFrom(fieldType))
{ {
AddField(fieldName, SerializationType.EntityReference, ((Entity)fieldValue)?.UUID ?? UUID.Zero, fieldValue?.GetType().FullName); AddField(fieldName, SerializationType.EntityReference, ((Entity?)fieldValue)?.UUID ?? UUID.Zero, fieldValue?.GetType().FullName);
} }
else if (fieldType.IsSubclassOf(typeof(Component))) else if (fieldType.IsSubclassOf(typeof(Component)))
{ {
AddField(fieldName, SerializationType.ComponentReference, ((Component)fieldValue)?.UUID ?? UUID.Zero, fieldValue?.GetType().FullName); AddField(fieldName, SerializationType.ComponentReference, ((Component?)fieldValue)?.UUID ?? UUID.Zero, fieldValue?.GetType().FullName);
} }
else else
{ {