Преглед на файлове

Fixed a serialization issue that was causing different objects having identical IDs
Fixed resource dependency search issue where it wasn't able to properly recurse into children

Marko Pintera преди 11 години
родител
ревизия
54faddd74a

+ 9 - 5
BansheeCore/Source/BsUtility.cpp

@@ -38,7 +38,7 @@ namespace BansheeEngine
 					if (reflectableField->isArray())
 					{
 						UINT32 numElements = reflectableField->getArraySize(&obj);
-						for (UINT32 j = 0; i < numElements; j++)
+						for (UINT32 j = 0; j < numElements; j++)
 						{
 							HResource resource = (HResource&)reflectableField->getArrayValue(&obj, j);
 							if (resource != nullptr)
@@ -65,7 +65,7 @@ namespace BansheeEngine
 					if (reflectableField->isArray())
 					{
 						UINT32 numElements = reflectableField->getArraySize(&obj);
-						for (UINT32 j = 0; i < numElements; j++)
+						for (UINT32 j = 0; j < numElements; j++)
 						{
 							IReflectable& childObj = reflectableField->getArrayValue(&obj, j);
 							findResourceDependenciesInternal(childObj, true, dependencies);
@@ -85,16 +85,20 @@ namespace BansheeEngine
 				if (reflectablePtrField->isArray())
 				{
 					UINT32 numElements = reflectablePtrField->getArraySize(&obj);
-					for (UINT32 j = 0; i < numElements; j++)
+					for (UINT32 j = 0; j < numElements; j++)
 					{
 						SPtr<IReflectable> childObj = reflectablePtrField->getArrayValue(&obj, j);
-						findResourceDependenciesInternal(*childObj, true, dependencies);
+
+						if (childObj != nullptr)
+							findResourceDependenciesInternal(*childObj, true, dependencies);
 					}
 				}
 				else
 				{
 					SPtr<IReflectable> childObj = reflectablePtrField->getValue(&obj);
-					findResourceDependenciesInternal(*childObj, true, dependencies);
+
+					if (childObj != nullptr)
+						findResourceDependenciesInternal(*childObj, true, dependencies);
 				}
 			}
 		}

+ 9 - 0
BansheeUtility/Source/BsBinarySerializer.cpp

@@ -51,6 +51,7 @@ namespace BansheeEngine
 		*bytesWritten = 0;
 		mTotalBytesWritten = 0;
 		UINT8* bufferStart = buffer;
+		Vector<std::shared_ptr<IReflectable>> encodedObjects;
 
 		UINT32 objectId = findOrCreatePersistentId(object);
 		
@@ -87,6 +88,13 @@ namespace BansheeEngine
 				}
 
 				foundObjectToProcess = true;
+
+				// Ensure we keep a reference to the object so it isn't released.
+				// The system assigns unique IDs to IReflectable objects based on pointer 
+				// addresses but if objects get released then same address could be assigned twice.
+				// Note: To get around this I could assign unique IDs to IReflectable objects
+				encodedObjects.push_back(curObject);
+
 				break; // Need to start over as mObjectsToSerialize was possibly modified
 			}
 
@@ -103,6 +111,7 @@ namespace BansheeEngine
 
 		*bytesWritten = mTotalBytesWritten;
 
+		encodedObjects.clear();
 		mObjectsToEncode.clear();
 		mObjectAddrToId.clear();
 	}

+ 2 - 0
SBansheeEngine/Include/BsManagedSerializableField.h

@@ -27,6 +27,8 @@ namespace BansheeEngine
 	class BS_SCR_BE_EXPORT ManagedSerializableFieldData : public IReflectable
 	{
 	public:
+		virtual ~ManagedSerializableFieldData() { }
+
 		static ManagedSerializableFieldDataPtr create(const ManagedSerializableTypeInfoPtr& typeInfo, MonoObject* value);
 		virtual void* getValue(const ManagedSerializableTypeInfoPtr& typeInfo) = 0;
 		virtual MonoObject* getValueBoxed(const ManagedSerializableTypeInfoPtr& typeInfo) = 0;

+ 1 - 3
SBansheeEngine/Source/BsManagedSerializableArray.cpp

@@ -111,7 +111,7 @@ namespace BansheeEngine
 		{
 			MonoObject* boxedObj = nullptr;
 
-			if(arrayValue != nullptr)
+			if (arrayValue != nullptr)
 				boxedObj = mono_value_box(MonoManager::instance().getDomain(), mElementMonoClass, arrayValue);
 
 			return ManagedSerializableFieldData::create(mArrayTypeInfo->mElementType, boxedObj);
@@ -127,8 +127,6 @@ namespace BansheeEngine
 		UINT32 numElems = (UINT32)mono_array_length(array);
 		assert(arrayIdx < numElems);
 	
-		UINT32 dbgSIze = mono_array_element_size(mono_object_get_class(mManagedInstance));
-
 		void* elemAddr = mono_array_addr_with_size(array, mElemSize, arrayIdx);
 		memcpy(elemAddr, val, mElemSize);
 	}

+ 35 - 13
TODO.txt

@@ -7,19 +7,6 @@ ManagedSerializeArray::deserializeManagedInstance were reported as ManagedSerial
 It's inconsistent to reproduce but started happening after I have modified managed object serialization to be on-demand. It's possibly
 related to lambdas not capturing types as I expect them to. It always happens in the same place.
 
-Properly implement getPropertyCopy and updateProperties that are called from RenderWindowManager.
-
-Resource refresh:
- - Keep track of every single active ScriptObject
-   - Before refresh serialize any managed component and managed resource
-   - After refresh create new instances and restore mCachedPtr fields
-   - After refresh restore managed component and managed resource serialized data
-   - Pay special attention to C# types that store custom data which might not be serialized. I'll need to handle that manually or change where that data is stored.
-   - Pay special attention to script objects that store references to MonoObject*, or MonoClass* (and similar) types (if they're not refreshed in initRuntimeData)
- - Check non-ScriptObject classes to ensure they properly refresh any references to: MonoClass, MonoField, MonoProperty, MonoMethod, MonoAssembly, function thunk
- - I should probably avoid calling constructor on restore since it may be doing some initialization. See how Unity does it.
-   - Unity does call the constructor
-
 I can get mono errors by checking g_print calls in goutput.c
  - Calling thunks incorrectly can cause those weird errors with no real callstack
 
@@ -41,6 +28,41 @@ Add ProjectWindow and HierarchyWindow to C#
  - Make TreeViews a C# element?
 Set up a default layout and save it
 
+-----------------
+Resource refresh:
+ - Add ScriptObject::beginRefresh, ScriptObject::endRefresh
+   - Each ScriptObject can internally store data needed for refresh (e.g. serialized instance and similar)
+   - beginRefresh needs to at least clear mCachedPtr (and ensure when managed objects get destroyed that ScriptObjects stay as is)
+   - endRefresh needs to at least restore mCachedPtr
+   - Depending on ScriptObject other functionality might be needed
+ - After refresh check if type still exists, and if it doesn't delete the ScriptObject (or throw an assert if that wasn't supposed to happen)
+ - Add MonoManager::refreshDomain. This releases current domain (and all assemblies in it), and allocates a new one
+ - Add CoreApplication::refreshManagedAssemblies
+    - Calls ScriptObject::beginRefresh, MonoManager::refreshDomain and ScriptObject::endRefresh
+    - Will also need to call RuntimeScriptManager and some other types that rely on Mono types
+
+When restoring manage instance don't call the constructor. Currently some constructors call native methods that set up ScriptObjects, which is not what I want to do.
+ - Unity does call the constructor so if it turns out to be necesary go on a case by case basis and change their constructors so they do not call into native code. (Or if they have to, to check if the object isn't already initialized)
+
+Find all references to: MonoObject, MonoClass, MonoField, MonoProperty, MonoMethod, MonoAssembly, function thunks and ensure those are properly released and re-constructed during refresh.
+ - Make a list and figure out possible issues. Then modify them before starting the refactor.
+
+Find all C# versions of ScriptObject and see if they store any data. If they do that data might need to be serialized and deserialized during refresh.
+ - Make a list and figure out possible issues.
+
+Types that I need to ensure stay valid after refresh:
+ - Any Component, Resource and GUI object
+ - EditorWindow
+
+Types I can probably ignore:
+ - SerializableProperty and related types
+   - They can't be serialized by anything. So technically after refresh we're forced to create new ones anyway.
+ - HandleSlider
+   - Also can't be serialized.
+
+I need to ensure to call all start-up methods after refresh.
+ - e.g. Component onInitialize and whatever is called for EditorWindow or inspectors
+
 -----------------
 
 Need a way to drag and drop items from Scene tree view to Scene view