diff --git a/ScriptCore/Editor/DictionaryEditor.cs b/ScriptCore/Editor/DictionaryEditor.cs index 7c2e077..bbfbf96 100644 --- a/ScriptCore/Editor/DictionaryEditor.cs +++ b/ScriptCore/Editor/DictionaryEditor.cs @@ -87,15 +87,15 @@ public class DictionaryEditor 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!); 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) { @@ -129,9 +129,9 @@ public class DictionaryEditor 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)); _dictionaryForNewValue = null; @@ -139,7 +139,7 @@ public class DictionaryEditor _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) { diff --git a/ScriptCore/Editor/EntityEditor.cs b/ScriptCore/Editor/EntityEditor.cs index b516128..370ba21 100644 --- a/ScriptCore/Editor/EntityEditor.cs +++ b/ScriptCore/Editor/EntityEditor.cs @@ -23,7 +23,7 @@ internal class EntityEditor { 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 _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; @@ -332,11 +332,11 @@ internal class EntityEditor 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; - if (ImGui.BeginCombo(fieldName, reference.ToString())) + if (ImGui.BeginCombo(fieldName, reference?.ToString())) { foreach (object enumValue in Enum.GetValues(fieldType)) { @@ -352,13 +352,13 @@ internal class EntityEditor return newValue; } - public static object ShowFieldEditor(object reference, Type fieldType, string fieldName, IEnumerable? attributes = null) + public static object? ShowFieldEditor(object? reference, Type fieldType, string fieldName, IEnumerable? attributes = null) { - ReadonlyAttribute readonlyAttribute = GetAttribute(attributes); + ReadonlyAttribute? readonlyAttribute = GetAttribute(attributes); ImGui.BeginDisabled(readonlyAttribute != null); - object? newValue = DidNotChange; + object? newValue; if (TryShowCustomEditor(reference, fieldType, fieldName, out newValue)) { @@ -396,7 +396,7 @@ internal class EntityEditor } else if (fieldType == typeof(bool2)) { - bool2 value = (bool2)reference; + bool2 value = (bool2)reference!; ImGui.TextUnformatted(fieldName); @@ -496,14 +496,14 @@ internal class EntityEditor 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.SameLine(); - Component component = currentValue as Component; + Component? component = currentValue as Component; string entityName = "None"; @@ -512,7 +512,7 @@ internal class EntityEditor entityName = component.Entity.Name; } - Type actualType = component?.GetType(); + Type? actualType = component?.GetType(); entityName += $" ({(actualType ?? fieldType).Name})"; @@ -570,23 +570,23 @@ internal class EntityEditor 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.SameLine(); string entityName = "None"; - Entity entity = currentValue as Entity; + Entity? entity = currentValue as Entity; if (entity != null) { entityName = entity.Name; } - Type actualType = entity?.GetType(); + Type? actualType = entity?.GetType(); entityName += $" ({(actualType ?? fieldType).Name})"; @@ -620,7 +620,7 @@ internal class EntityEditor } else { - Entity scriptInstance = Entity.GetScriptReference(draggedId, typeof(Entity)); + Entity? scriptInstance = Entity.GetScriptReference(draggedId, typeof(Entity)); allowDrop = fieldType.IsInstanceOfType(scriptInstance); } @@ -661,11 +661,11 @@ internal class EntityEditor return newValue; } - private static object ShowStringEditor(object reference, Type fieldType, string fieldName, IEnumerable attributes) + private static object ShowStringEditor(object? reference, Type fieldType, string fieldName, IEnumerable? attributes) { object newValue = DidNotChange; - TextFieldAttribute textField = GetAttribute(attributes); + TextFieldAttribute? textField = GetAttribute(attributes); string value = reference as string ?? $"{float.MinValue}"; @@ -684,7 +684,7 @@ internal class EntityEditor return newValue; } - public static void ShowEditor(Type type, object reference) + public static void ShowEditor(Type type, object? reference) { int i = 0; @@ -700,7 +700,7 @@ internal class EntityEditor IEnumerable 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) { @@ -748,12 +748,14 @@ internal class EntityEditor 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]; - void AddElement(IList list, ref object newList) + void AddElement(IList? list, out object? newList) { + newList = DidNotChange; + if (list == null) { newList = Activator.CreateInstance(fieldType); @@ -762,36 +764,50 @@ internal class EntityEditor Debug.Assert(list != null); } - object newElement = ActivatorExtension.CreateInstanceSafe(elementType); - list.Add(newElement); + object? newElement = ActivatorExtension.CreateInstanceSafe(elementType); + list?.Add(newElement); } - void RemoveElement(IList list, ref object newList) + void RemoveElement(IList? list, out object? newList) { - list.RemoveAt(list.Count - 1); + newList = DidNotChange; + + if (list == null) + return; + + if (list.Count == 0) + { + newList = null; + } + else + { + list.RemoveAt(list.Count - 1); + } } - return ShowGenericListEditor(fieldType, elementType, (IEnumerable)fieldValue, fieldName, + return ShowGenericListEditor(fieldType, elementType, (IEnumerable?)fieldValue, fieldName, 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); - Type elementType = fieldType.GetElementType(); + Type? elementType = fieldType.GetElementType(); Debug.Assert(elementType != null); - Array myArray = fieldValue as Array; + Array? myArray = fieldValue as Array; if (myArray?.Rank > 1) { 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; if (list == null) @@ -812,25 +828,37 @@ internal class EntityEditor ((IList)newList)[newIndex] = newElement; } - void RemoveElement(IList list, ref object newList) + void RemoveElement(IList? list, out object? newList) { - Array newArray = Array.CreateInstance(elementType, list.Count - 1); - Array.Copy((Array)list, newArray, newArray.Length); + newList = DidNotChange; - newList = newArray; + if (list == null) + return; + + if (list.Count == 0) + { + newList = null; + } + else + { + Array newArray = Array.CreateInstance(elementType, list.Count - 1); + Array.Copy((Array)list, newArray, newArray.Length); + + newList = newArray; + } } - return ShowGenericListEditor(fieldType, elementType, (IEnumerable)fieldValue, fieldName, + return ShowGenericListEditor(fieldType, elementType!, (IEnumerable?)fieldValue, fieldName, 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) { - object newList = DidNotChange; - IList myList = list as IList; + object? newList = DidNotChange; + IList? myList = list as IList; // 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 @@ -847,7 +875,7 @@ internal class EntityEditor if (ImGui.SmallButton("+")) { - addElement(myList, ref newList); + addElement(myList, out newList); } ImGuiExtension.AttachTooltip("Add a new Element at the end of the list."); @@ -858,7 +886,7 @@ internal class EntityEditor if (ImGui.SmallButton("-")) { - removeElement(myList, ref newList); + removeElement(myList, out newList); } 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!"); - /// 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 dropped = false; @@ -887,7 +915,7 @@ internal class EntityEditor ref ListPayload payload = ref Unsafe.AsRef((void*)payloadPtr.Data); // Make sure the index is still correct - if (payload.Element < myList.Count) + if (payload.Element < myList!.Count) { object item = myList[payload.Element]; @@ -917,7 +945,7 @@ internal class EntityEditor 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); @@ -957,7 +985,7 @@ internal class EntityEditor 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 if (newValue != DidNotChange && !orderChanged) @@ -981,7 +1009,7 @@ internal class EntityEditor private static T ReadStaticField(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) { diff --git a/ScriptCore/Editor/ShowInEditorAttribute.cs b/ScriptCore/Editor/ShowInEditorAttribute.cs index faa0be5..a0406b5 100644 --- a/ScriptCore/Editor/ShowInEditorAttribute.cs +++ b/ScriptCore/Editor/ShowInEditorAttribute.cs @@ -18,5 +18,5 @@ public sealed class ShowInEditorAttribute : Attribute /// The label with which the field will be shown in the editor. /// If not specified, the fields name will be used. /// - public string DisplayName { get; set; } = null; + public string? DisplayName { get; set; } = null; } diff --git a/ScriptCore/Serialization/DeserializationObject.cs b/ScriptCore/Serialization/DeserializationObject.cs index 019526b..3faa1aa 100644 --- a/ScriptCore/Serialization/DeserializationObject.cs +++ b/ScriptCore/Serialization/DeserializationObject.cs @@ -277,7 +277,7 @@ public class DeserializationObject object currentValue = field.GetValue(obj); - object deserializeValue = DeserializeField(currentValue, field.FieldType, field.Name); + object? deserializeValue = DeserializeField(currentValue, field.FieldType, field.Name); if (deserializeValue != NoValueDeserialized) { @@ -347,7 +347,10 @@ public class DeserializationObject } 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) { diff --git a/ScriptCore/Serialization/DictionarySerializer.cs b/ScriptCore/Serialization/DictionarySerializer.cs index 94b6038..4793fbb 100644 --- a/ScriptCore/Serialization/DictionarySerializer.cs +++ b/ScriptCore/Serialization/DictionarySerializer.cs @@ -79,9 +79,9 @@ public static class DictionarySerializer return null; // 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) return DeserializationObject.NoValueDeserialized; @@ -89,7 +89,7 @@ public static class DictionarySerializer Type keyType = fieldType.GetGenericArguments()[0]; Type valueType = fieldType.GetGenericArguments()[1]; - int count = deserializedObject.GetFieldValue("Count", SerializationType.Int32); + int count = deserializedObject!.GetFieldValue("Count", SerializationType.Int32); // Create instance, pass in capacity object? instance = ActivatorExtension.CreateInstanceSafe(type, count); @@ -103,7 +103,7 @@ public static class DictionarySerializer deserializedObject.PushScope(i.ToString()); object? key = deserializedObject.DeserializeField(null, keyType, "Key"); - object value = deserializedObject.DeserializeField(null, valueType, "Value"); + object? value = deserializedObject.DeserializeField(null, valueType, "Value"); if (key != null) { diff --git a/ScriptCore/Serialization/SerializedObject.cs b/ScriptCore/Serialization/SerializedObject.cs index 16e0e87..a42a7d3 100644 --- a/ScriptCore/Serialization/SerializedObject.cs +++ b/ScriptCore/Serialization/SerializedObject.cs @@ -18,7 +18,7 @@ public class SerializedObject private Stack _structScope = new(); - private string _structScopeName; + private string _structScopeName = ""; 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); } - 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}"; @@ -107,14 +107,14 @@ public class SerializedObject if (!EntitySerializer.SerializeField(field)) continue; - object fieldValue = field.GetValue(obj); + object? fieldValue = field.GetValue(obj); Type fieldType = fieldValue?.GetType() ?? field.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 { @@ -142,11 +142,12 @@ public class SerializedObject 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)) { - SerializePrimitive(fieldName, fieldValue, fieldType); + // Primitives can't be null + SerializePrimitive(fieldName, fieldValue!, fieldType); } else if (fieldType == typeof(string)) { @@ -158,14 +159,14 @@ public class SerializedObject } else if (fieldType.IsArray) { - Array myArray = fieldValue as Array; + Array? myArray = fieldValue as Array; if (myArray?.Rank > 1) { 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) { @@ -191,7 +192,8 @@ public class SerializedObject if (TryCustomSerializer(fieldName, fieldValue, fieldType)) return; - SerializeStruct(fieldName, fieldValue, fieldType); + // Value Types cant be null + SerializeStruct(fieldName, fieldValue!, fieldType); } 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) { @@ -274,9 +276,9 @@ public class SerializedObject 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) @@ -288,15 +290,15 @@ public class SerializedObject PopScope(); } - public void SerializeClass(string fieldName, object fieldValue, Type fieldType) + public void SerializeClass(string fieldName, object? fieldValue, Type 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))) { - 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 {