Kaynağa Gözat

Modifying struct members in inspector now properly persists the changes

Marko Pintera 10 yıl önce
ebeveyn
işleme
9776b4efa4

+ 23 - 2
MBansheeEngine/SerializableField.cs

@@ -56,8 +56,29 @@ namespace BansheeEngine
 
         public SerializableProperty GetProperty()
         {
-            SerializableProperty.Getter getter = () => Internal_GetValue(mCachedPtr, parent.referencedObject);
-            SerializableProperty.Setter setter = (object value) => Internal_SetValue(mCachedPtr, parent.referencedObject, value);
+            SerializableProperty.Getter getter = () =>
+            {
+                object parentObject = parent.GetReferencedObject();
+                
+                if (parentObject != null)
+                    return Internal_GetValue(mCachedPtr, parentObject);
+                else
+                    return null;
+            };
+
+            SerializableProperty.Setter setter = (object value) =>
+            {
+                object parentObject = parent.GetReferencedObject();
+
+                if (parentObject != null)
+                {
+                    Internal_SetValue(mCachedPtr, parentObject, value);
+
+                    // If value type we cannot just modify the parent object because it's just a copy
+                    if (parentObject.GetType().IsValueType && parent.parentProperty != null)
+                        parent.parentProperty.SetValue(parentObject);
+                }
+            };
 
             SerializableProperty newProperty = Internal_CreateProperty(mCachedPtr);
             newProperty.Construct(type, internalType, getter, setter);

+ 21 - 8
MBansheeEngine/SerializableObject.cs

@@ -10,20 +10,25 @@ namespace BansheeEngine
     #pragma warning disable 649
     public sealed class SerializableObject : ScriptObject
     {
-        internal object referencedObject;
+        internal SerializableProperty parentProperty;
+        internal object parentObject;
         private SerializableField[] _fields;
 
-        public SerializableObject(Type objectType, object instance)
+        // Note: Also called from native code
+        public SerializableObject(Type objectType, SerializableProperty parentProperty)
         {
-            Internal_CreateInstance(this, objectType, instance);
+            Internal_CreateInstance(this, objectType);
 
-            referencedObject = instance;
+            this.parentProperty = parentProperty;
+            this.parentObject = null;
         }
 
-        // Constructed from native code
-        private SerializableObject(object instance)
+        public SerializableObject(Type objectType, object parentObject)
         {
-            referencedObject = instance;
+            Internal_CreateInstance(this, objectType);
+
+            this.parentProperty = null;
+            this.parentObject = parentObject;
         }
 
         public SerializableField[] fields
@@ -31,7 +36,15 @@ namespace BansheeEngine
             get { return _fields; }
         }
 
+        public object GetReferencedObject()
+        {
+            if (parentProperty != null)
+                return parentProperty.GetValue<object>();
+            else
+                return parentObject;
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(SerializableObject instance, Type objectType, object objInstance);
+        private static extern void Internal_CreateInstance(SerializableObject instance, Type objectType);
     }
 }

+ 1 - 0
SBansheeEngine/Include/BsScriptEnginePrerequisites.h

@@ -68,6 +68,7 @@ namespace BansheeEngine
 	class ManagedSerializableDiff;
 	class ManagedResource;
 	class ManagedResourceMetaData;
+	class ScriptSerializableProperty;
 	class ScriptAssemblyManager;
 	class ScriptHString;
 	class ScriptContextMenu;

+ 2 - 2
SBansheeEngine/Include/BsScriptSerializableObject.h

@@ -10,10 +10,10 @@ namespace BansheeEngine
 	public:
 		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "SerializableObject")
 
-		static ScriptSerializableObject* create(const ManagedSerializableTypeInfoPtr& typeInfo, MonoObject* object);
+		static ScriptSerializableObject* create(ScriptSerializableProperty* parentProperty, MonoObject* object);
 
 	private:
-		static void internal_createInstance(MonoObject* instance, MonoReflectionType* type, MonoObject* object);
+		static void internal_createInstance(MonoObject* instance, MonoReflectionType* type);
 
 		static ScriptSerializableObject* createInternal(MonoObject* instance, const ManagedSerializableObjectInfoPtr& objInfo);
 

+ 2 - 0
SBansheeEngine/Include/BsScriptSerializableProperty.h

@@ -12,6 +12,8 @@ namespace BansheeEngine
 
 		static ScriptSerializableProperty* create(const ManagedSerializableTypeInfoPtr& typeInfo);
 
+		ManagedSerializableTypeInfoPtr getTypeInfo() const { return mTypeInfo; }
+
 		~ScriptSerializableProperty() {}
 
 	private:

+ 5 - 4
SBansheeEngine/Source/BsScriptSerializableObject.cpp

@@ -1,5 +1,6 @@
 #include "BsScriptSerializableObject.h"
 #include "BsScriptSerializableField.h"
+#include "BsScriptSerializableProperty.h"
 #include "BsScriptAssemblyManager.h"
 #include "BsScriptMeta.h"
 #include "BsMonoField.h"
@@ -24,12 +25,12 @@ namespace BansheeEngine
 		FieldsField = metaData.scriptClass->getField("_fields");
 	}
 
-	ScriptSerializableObject* ScriptSerializableObject::create(const ManagedSerializableTypeInfoPtr& typeInfo, MonoObject* object)
+	ScriptSerializableObject* ScriptSerializableObject::create(ScriptSerializableProperty* property, MonoObject* object)
 	{
-		MonoType* monoInternalElementType = mono_class_get_type(typeInfo->getMonoClass());
+		MonoType* monoInternalElementType = mono_class_get_type(property->getTypeInfo()->getMonoClass());
 		MonoReflectionType* internalElementType = mono_type_get_object(MonoManager::instance().getDomain(), monoInternalElementType);
 
-		void* params[2] = { internalElementType, object };
+		void* params[2] = { internalElementType, property->getManagedInstance() };
 		MonoObject* managedInstance = metaData.scriptClass->createInstance(params, 2);
 
 		// Managed constructor will call back to native which will create ScriptSerializableObject instance,
@@ -37,7 +38,7 @@ namespace BansheeEngine
 		return ScriptSerializableObject::toNative(managedInstance);
 	}
 
-	void ScriptSerializableObject::internal_createInstance(MonoObject* instance, MonoReflectionType* type, MonoObject* object)
+	void ScriptSerializableObject::internal_createInstance(MonoObject* instance, MonoReflectionType* type)
 	{
 		MonoType* internalType = mono_reflection_type_get_type(type);
 		::MonoClass* monoClass = mono_type_get_class(internalType);

+ 1 - 1
SBansheeEngine/Source/BsScriptSerializableProperty.cpp

@@ -48,7 +48,7 @@ namespace BansheeEngine
 
 	MonoObject* ScriptSerializableProperty::internal_createObject(ScriptSerializableProperty* nativeInstance, MonoObject* object)
 	{
-		ScriptSerializableObject* newObject = ScriptSerializableObject::create(nativeInstance->mTypeInfo, object);
+		ScriptSerializableObject* newObject = ScriptSerializableObject::create(nativeInstance, object);
 
 		return newObject->getManagedInstance();
 	}

+ 3 - 4
TODO.txt

@@ -56,7 +56,7 @@ Polish
 
 TODO:
  - Thoroughly test inspector
- - Modifying structs doesn't persist changes
+ - Writing on a child struct field unfocused input because the inspector gets rebuilt - delay rebuild until user unfocuses from the input box?
 
 Ribek use:
  - Camera, Renderable, Material, Texture inspector
@@ -107,14 +107,13 @@ Other polish:
  - Ortographic camera views (+ gizmo in scene view corner that shows camera orientation)
  - Drag to select in scene view
  - Update GUISlider so it works with the new style (and to have min/max limits, plus step size)
- - Replace "minimize" button in tabbed title bar with maximize and make sure it works
+ - Replace "minimize" button in tabbed title bar with maximize and make sure it works (in both docked and floating mode)
  - When I expand inspector elements and them come back to that object it should remember the previous state
    - Add a chaching mechanism to inspector (likely based on instance ID & property names)
    - This has to work not only when I come back to the object, but whenever inspector rebuilds (e.g. after removing element from array)
    - Consider saving this information with the serialized object
  - Make sure to persist EditorSettings
  - Import option inspectors for Texture, Mesh, Font
- - DOck manager maximize doesn't work'
 
 Stage 2 polish:
  - Inject an icon into an .exe (Win32 specific)
@@ -130,13 +129,13 @@ Stage 2 polish:
 
 Finalizing:
  - Add copyright notices in all files & change license to GPL
+ - UseCustomInspector isn't implemented
  - I could record undo/redo per-property using the new diff system
  - When building game make sure to go over texture resources and ensure they are saved in the valid format
    as we don't want to do format conversion at runtime (Not cruical, but it should be done eventually)
    - This should something similar to Unity where when changing the platform all resources get reimported
  - When building level for release make sure to clear all prefab diffs (possibly store them elsewhere in the first place)
    - And all prefab instances should have updateFromPrefab called on them.
- - Save the default editor layout somewhere and make sure its used on initial startup when no layout exists
  - Undo/Redo when breaking or reverting a scene object (and in general test & finalize undo/redo system)
  - Move all the code files into subfolders so their hierarchy is similar to VS filters
  - Get rid of PoolAlloc and other unused allocators (plus fix bs_new and others which have weird overloads)