bool ScriptEditorWidget::createManagedInstance()
	{
		const char* assemblies[2] = { EDITOR_ASSEMBLY, SCRIPT_EDITOR_ASSEMBLY };
		UINT32 numAssemblies = sizeof(assemblies) / sizeof(assemblies[0]);

		for (UINT32 i = 0; i < numAssemblies; i++)
		{
			MonoAssembly* assembly = MonoManager::instance().getAssembly(assemblies[i]);

			if (assembly != nullptr)
			{
				MonoClass* editorWindowClass = assembly->getClass(mNamespace, mTypename);

				if (editorWindowClass != nullptr)
				{
					mManagedInstance = editorWindowClass->createInstance();

					MonoObject* guiPanel = ScriptGUIPanel::createFromExisting(mContent);
					mContentsPanel = ScriptGUILayout::toNative(guiPanel);
					ScriptEditorWindow::guiPanelField->setValue(mManagedInstance, guiPanel);

					reloadMonoTypes(editorWindowClass);
					return true;
				}
			}
		}

		return false;
	}
	void MenuItemManager::reloadAssemblyData()
	{
		clearMenuItems();

		// Reload MenuItem attribute from editor assembly
		MonoAssembly* editorAssembly = MonoManager::instance().getAssembly(EDITOR_ASSEMBLY);
		mMenuItemAttribute = editorAssembly->getClass(EDITOR_NS, "MenuItem");
		if (mMenuItemAttribute == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find MenuItem managed class.");

		mPathField = mMenuItemAttribute->getField("path");
		mShortcutField = mMenuItemAttribute->getField("shortcut");
		mPriorityField = mMenuItemAttribute->getField("priority");
		mSeparatorField = mMenuItemAttribute->getField("separator");

		MainEditorWindow* mainWindow = EditorWindowManager::instance().getMainWindow();

		Vector<String> scriptAssemblyNames = mScriptObjectManager.getScriptAssemblies();
		for (auto& assemblyName : scriptAssemblyNames)
		{
			MonoAssembly* assembly = MonoManager::instance().getAssembly(assemblyName);

			// Find new menu item methods
			const Vector<MonoClass*>& allClasses = assembly->getAllClasses();
			for (auto curClass : allClasses)
			{
				const Vector<MonoMethod*>& methods = curClass->getAllMethods();
				for (auto& curMethod : methods)
				{
					String path;
					ShortcutKey shortcutKey = ShortcutKey::NONE;
					INT32 priority = 0;
					bool separator = false;
					if (parseMenuItemMethod(curMethod, path, shortcutKey, priority, separator))
					{
						std::function<void()> callback = std::bind(&MenuItemManager::menuItemCallback, curMethod);

						if (separator)
						{
							Vector<String> pathElements = StringUtil::split(path, "/");
							String separatorPath;
							if (pathElements.size() > 1)
							{
								const String& lastElem = pathElements[pathElements.size() - 1];
								separatorPath = path;
								separatorPath.erase(path.size() - lastElem.size() - 1, lastElem.size() + 1);
							}

							GUIMenuItem* separatorItem = mainWindow->getMenuBar().addMenuItemSeparator(separatorPath, priority);
							mMenuItems.push_back(separatorItem);
						}

						GUIMenuItem* menuItem = mainWindow->getMenuBar().addMenuItem(path, callback, priority, shortcutKey);
						mMenuItems.push_back(menuItem);
					}
				}
			}
		}
	}
	MonoObject* ScriptDropDownWindow::internal_CreateInstance(MonoString* ns, MonoString* typeName, 
		ScriptEditorWindow* parentWindow, Vector2I* position)
	{
		String strTypeName = MonoUtil::monoToString(typeName);
		String strNamespace = MonoUtil::monoToString(ns);
		String fullName = strNamespace + "." + strTypeName;

		MonoClass* windowClass = MonoManager::instance().findClass(strNamespace, strTypeName);
		if (windowClass == nullptr)
			return nullptr;

		MonoAssembly* assembly = MonoManager::instance().getAssembly(EDITOR_ASSEMBLY);

		MonoClass* defaultSizeAttrib = assembly->getClass("BansheeEditor", "DefaultSize");
		if (defaultSizeAttrib == nullptr)
			BS_EXCEPT(InternalErrorException, "Cannot find DefaultSize managed class.");

		MonoField* defaultWidthField = defaultSizeAttrib->getField("width");
		MonoField* defaultHeightField = defaultSizeAttrib->getField("height");

		int width = 200;
		int height = 200;

		MonoObject* defaultSizeObj = windowClass->getAttribute(defaultSizeAttrib);
		if (defaultSizeObj != nullptr)
		{
			defaultWidthField->get(defaultSizeObj, &width);
			defaultHeightField->get(defaultSizeObj, &height);
		}

		MonoObject* instance = windowClass->createInstance(false);

		ManagedDropDownWindow* dropDownWindow = nullptr;
		if (parentWindow != nullptr && !parentWindow->isDestroyed())
		{
			EditorWidgetBase* editorWidget = parentWindow->getEditorWidget();
			EditorWidgetContainer* parentContainer = editorWidget->_getParent();
			if (parentContainer != nullptr)
			{
				SPtr<RenderWindow> parentRenderWindow = parentContainer->getParentWindow()->getRenderWindow();
				SPtr<Camera> parentCamera = parentContainer->getParentWidget().getCamera();

				position->x += editorWidget->getX();
				position->y += editorWidget->getY();

				dropDownWindow = DropDownWindowManager::instance().open<ManagedDropDownWindow>(
					parentRenderWindow, parentCamera, *position, instance, width, height);
			}
		}

		ScriptDropDownWindow* nativeInstance = new (bs_alloc<ScriptDropDownWindow>()) ScriptDropDownWindow(dropDownWindow);

		if (dropDownWindow != nullptr)
			dropDownWindow->initialize(nativeInstance);

		windowClass->construct(instance);
		return instance;
	}
	void ScriptEditorWindow::registerManagedEditorWindows()
	{
		MonoAssembly* assembly = MonoManager::instance().getAssembly(EDITOR_ASSEMBLY);

		if(assembly != nullptr)
		{
			MonoClass* defaultSizeAttrib = assembly->getClass("BansheeEditor", "DefaultSize");
			if (defaultSizeAttrib == nullptr)
				BS_EXCEPT(InternalErrorException, "Cannot find DefaultSize managed attribute.");

			MonoField* defaultWidthField = defaultSizeAttrib->getField("width");
			MonoField* defaultHeightField = defaultSizeAttrib->getField("height");

			MonoClass* undoRedoLocalAttrib = assembly->getClass("BansheeEditor", "UndoRedoLocal");
			if (undoRedoLocalAttrib == nullptr)
				BS_EXCEPT(InternalErrorException, "Cannot find UndoRedoLocal managed attribute.");

			MonoClass* editorWindowClass = assembly->getClass("BansheeEditor", "EditorWindow");

			const Vector<MonoClass*>& allClasses = assembly->getAllClasses();
			for(auto& curClass : allClasses)
			{
				if(curClass->isSubClassOf(editorWindowClass) && curClass != editorWindowClass)
				{
					UINT32 width = 400;
					UINT32 height = 400;

					MonoObject* defaultSize = curClass->getAttribute(defaultSizeAttrib);
					if (defaultSize != nullptr)
					{
						defaultWidthField->get(defaultSize, &width);
						defaultHeightField->get(defaultSize, &height);
					}

					bool hasLocalUndoRedo = curClass->getAttribute(undoRedoLocalAttrib) != nullptr;

					const String& className = curClass->getFullName();
					EditorWidgetManager::instance().registerWidget(className, 
						std::bind(&ScriptEditorWindow::openEditorWidgetCallback, curClass->getNamespace(), 
						curClass->getTypeName(), width, height, hasLocalUndoRedo, _1));
					AvailableWindowTypes.push_back(className);
				}
			}
		}
	}
	void ScriptPostProcessSettings::initRuntimeData()
	{
		metaData.scriptClass->addInternalCall("Internal_CreateDefault", &ScriptPostProcessSettings::internal_CreateDefault);

		// Validation
#if BS_DEBUG_MODE
		MonoAssembly* engineAssembly = MonoManager::instance().getAssembly(ENGINE_ASSEMBLY);

		MonoClass* autoExposureSettingsClass = engineAssembly->getClass("BansheeEngine", "AutoExposureSettings");
		MonoClass* tonemappingSettingsClass = engineAssembly->getClass("BansheeEngine", "TonemappingSettings");
		MonoClass* whieBalanceSettingsClass = engineAssembly->getClass("BansheeEngine", "WhiteBalanceSettings");
		MonoClass* colorGradingSettingsClass = engineAssembly->getClass("BansheeEngine", "ColorGradingSettings");

		assert(metaData.scriptClass->getInstanceSize() == sizeof(PostProcessSettings));
		assert(autoExposureSettingsClass->getInstanceSize() == sizeof(AutoExposureSettings));
		assert(tonemappingSettingsClass->getInstanceSize() == sizeof(TonemappingSettings));
		assert(whieBalanceSettingsClass->getInstanceSize() == sizeof(WhiteBalanceSettings));
		assert(colorGradingSettingsClass->getInstanceSize() == sizeof(ColorGradingSettings));
#endif
	}
	void MonoManager::initializeAssembly(MonoAssembly& assembly)
	{
		if (!assembly.mIsLoaded)
		{
			assembly.load(mScriptDomain);

			// Fully initialize all types that use this assembly
			Vector<ScriptMeta*>& mTypeMetas = getScriptMetaData()[assembly.mName];
			for (auto& meta : mTypeMetas)
			{
				meta->scriptClass = assembly.getClass(meta->ns, meta->name);
				if (meta->scriptClass == nullptr)
					BS_EXCEPT(InvalidParametersException, "Unable to find class of type: \"" + meta->ns + "::" + meta->name + "\"");

				if (meta->scriptClass->hasField("mCachedPtr"))
					meta->thisPtrField = meta->scriptClass->getField("mCachedPtr");
				else
					meta->thisPtrField = nullptr;

				meta->initCallback();
			}
		}

		if (!mIsCoreLoaded)
		{
			mIsCoreLoaded = true;

			MonoAssembly* corlib = nullptr;

			auto iterFind = mAssemblies.find("corlib");
			if (iterFind == mAssemblies.end())
			{
				corlib = new (bs_alloc<MonoAssembly>()) MonoAssembly(L"corlib", "corlib");
				mAssemblies["corlib"] = corlib;
			}
			else
				corlib = iterFind->second;

			corlib->loadFromImage(mono_get_corlib());
		}
	}
	void ScriptAssemblyManager::initializeBuiltinComponentInfos()
	{
		mBuiltinComponentInfos.clear();
		mBuiltinComponentInfosByTID.clear();

		Vector<BuiltinComponentInfo> allComponentsInfos = BuiltinComponents::getEntries();

		for(auto& entry : allComponentsInfos)
		{
			MonoAssembly* assembly = MonoManager::instance().getAssembly(entry.metaData->assembly);
			if (assembly == nullptr)
				continue;

			BuiltinComponentInfo info = entry;
			info.monoClass = assembly->getClass(entry.metaData->ns, entry.metaData->name);

			::MonoReflectionType* type = MonoUtil::getType(info.monoClass->_getInternalClass());

			mBuiltinComponentInfos[type] = info;
			mBuiltinComponentInfosByTID[info.typeId] = info;
		}
	}
示例#8
0
	void ScriptGizmoManager::reloadAssemblyData()
	{
		// Reload DrawGizmo attribute from editor assembly
		MonoAssembly* editorAssembly = MonoManager::instance().getAssembly(EDITOR_ASSEMBLY);
		mDrawGizmoAttribute = editorAssembly->getClass("BansheeEditor", "DrawGizmo");
		if (mDrawGizmoAttribute == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find DrawGizmo managed class.");

		mFlagsField = mDrawGizmoAttribute->getField("flags");

		Vector<String> scriptAssemblyNames = mScriptObjectManager.getScriptAssemblies();
		for (auto& assemblyName : scriptAssemblyNames)
		{
			MonoAssembly* assembly = MonoManager::instance().getAssembly(assemblyName);

			// Find new gizmo drawer methods
			const Vector<MonoClass*>& allClasses = assembly->getAllClasses();
			for (auto curClass : allClasses)
			{
				const Vector<MonoMethod*>& methods = curClass->getAllMethods();
				for (auto& curMethod : methods)
				{
					UINT32 drawGizmoFlags = 0;
					MonoClass* componentType = nullptr;
					if (isValidDrawGizmoMethod(curMethod, componentType, drawGizmoFlags))
					{
						String fullComponentName = componentType->getFullName();
						GizmoData& newGizmoData = mGizmoDrawers[fullComponentName];

						newGizmoData.componentType = componentType;
						newGizmoData.drawGizmosMethod = curMethod;
						newGizmoData.flags = drawGizmoFlags;
					}
				}
			}
		}
	}
	void ScriptInspectorUtility::reloadAssemblyData()
	{
		mInspectorTypes.clear();
		mInspectableFieldTypes.clear();

		// Reload MenuItem attribute from editor assembly
		MonoAssembly* editorAssembly = MonoManager::instance().getAssembly(EDITOR_ASSEMBLY);
		mCustomInspectorAtribute = editorAssembly->getClass("BansheeEditor", "CustomInspector");
		if (mCustomInspectorAtribute == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find CustomInspector managed class.");

		MonoClass* inspectorClass = editorAssembly->getClass("BansheeEditor", "Inspector");
		if (inspectorClass == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find Inspector managed class.");

		MonoClass* inspectableFieldClass = editorAssembly->getClass("BansheeEditor", "InspectableField");
		if (inspectableFieldClass == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find InspectableField managed class.");

		mTypeField = mCustomInspectorAtribute->getField("type");

		ScriptAssemblyManager& sam = ScriptAssemblyManager::instance();

		Vector<String> scriptAssemblyNames = sam.getScriptAssemblies();
		for (auto& assemblyName : scriptAssemblyNames)
		{
			MonoAssembly* assembly = MonoManager::instance().getAssembly(assemblyName);

			// Find new classes/structs with the custom inspector attribute
			const Vector<MonoClass*>& allClasses = assembly->getAllClasses();
			for (auto curClass : allClasses)
			{
				MonoObject* attrib = curClass->getAttribute(mCustomInspectorAtribute);
				if (attrib == nullptr)
					continue;

				// Check if the attribute references a valid class
				MonoReflectionType* referencedReflType = nullptr;
				mTypeField->getValue(attrib, &referencedReflType);

				::MonoClass* referencedMonoClass = MonoUtil::getClass(referencedReflType);

				MonoClass* referencedClass = MonoManager::instance().findClass(referencedMonoClass);
				if (referencedClass == nullptr)
					continue;

				if (curClass->isSubClassOf(inspectorClass))
				{
					bool isValidInspectorType = referencedClass->isSubClassOf(ScriptResource::getMetaData()->scriptClass) ||
						referencedClass->isSubClassOf(ScriptComponent::getMetaData()->scriptClass);

					if (!isValidInspectorType)
						continue;

					mInspectorTypes[referencedClass] = curClass;
				}
				else if (curClass->isSubClassOf(inspectableFieldClass))
				{
					mInspectorTypes[referencedClass] = curClass;
				}
			}
		}
	}
	void ScriptAssemblyManager::initializeBaseTypes()
	{
		// Get necessary classes for detecting needed class & field information
		MonoAssembly* corlib = MonoManager::instance().getAssembly("corlib");
		if(corlib == nullptr)
			BS_EXCEPT(InvalidStateException, "corlib assembly is not loaded.");

		MonoAssembly* bansheeEngineAssembly = MonoManager::instance().getAssembly(ENGINE_ASSEMBLY);
		if(bansheeEngineAssembly == nullptr)
			BS_EXCEPT(InvalidStateException, String(ENGINE_ASSEMBLY) +  " assembly is not loaded.");

		mSystemArrayClass = corlib->getClass("System", "Array");
		if(mSystemArrayClass == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find System.Array managed class.");

		mSystemGenericListClass = corlib->getClass("System.Collections.Generic", "List`1");
		if(mSystemGenericListClass == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find List<T> managed class.");

		mSystemGenericDictionaryClass = corlib->getClass("System.Collections.Generic", "Dictionary`2");
		if(mSystemGenericDictionaryClass == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find Dictionary<TKey, TValue> managed class.");

		mSystemTypeClass = corlib->getClass("System", "Type");
		if (mSystemTypeClass == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find Type managed class.");

		mSerializeObjectAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "SerializeObject");
		if(mSerializeObjectAttribute == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find SerializableObject managed class.");

		mDontSerializeFieldAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "DontSerializeField");
		if(mDontSerializeFieldAttribute == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find DontSerializeField managed class.");

		mRangeAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "Range");
		if (mRangeAttribute == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find Range managed class.");

		mStepAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "Step");
		if (mStepAttribute == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find Step managed class.");

		mComponentClass = bansheeEngineAssembly->getClass("BansheeEngine", "Component");
		if(mComponentClass == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find Component managed class.");

		mManagedComponentClass = bansheeEngineAssembly->getClass("BansheeEngine", "ManagedComponent");
		if (mManagedComponentClass == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find ManagedComponent managed class.");

		mMissingComponentClass = bansheeEngineAssembly->getClass("BansheeEngine", "MissingComponent");
		if (mMissingComponentClass == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find MissingComponent managed class.");

		mSceneObjectClass = bansheeEngineAssembly->getClass("BansheeEngine", "SceneObject");
		if(mSceneObjectClass == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find SceneObject managed class.");

		mSerializeFieldAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "SerializeField");
		if(mSerializeFieldAttribute == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find SerializeField managed class.");

		mHideInInspectorAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "HideInInspector");
		if(mHideInInspectorAttribute == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find HideInInspector managed class.");

		mShowInInspectorAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "ShowInInspector");
		if (mShowInInspectorAttribute == nullptr)
			BS_EXCEPT(InvalidStateException, "Cannot find ShowInInspector managed class.");

		mBaseTypesInitialized = true;
	}
	void ScriptAssemblyManager::loadAssemblyInfo(const String& assemblyName)
	{
		if(!mBaseTypesInitialized)
			initializeBaseTypes();

		initializeBuiltinComponentInfos();
		initializeBuiltinResourceInfos();

		// Process all classes and fields
		UINT32 mUniqueTypeId = 1;

		MonoAssembly* curAssembly = MonoManager::instance().getAssembly(assemblyName);
		if(curAssembly == nullptr)
			return;

		SPtr<ManagedSerializableAssemblyInfo> assemblyInfo = bs_shared_ptr_new<ManagedSerializableAssemblyInfo>();
		assemblyInfo->mName = assemblyName;

		mAssemblyInfos[assemblyName] = assemblyInfo;

		MonoClass* resourceClass = ScriptResource::getMetaData()->scriptClass;
		MonoClass* managedResourceClass = ScriptManagedResource::getMetaData()->scriptClass;

		// Populate class data
		const Vector<MonoClass*>& allClasses = curAssembly->getAllClasses();
		for(auto& curClass : allClasses)
		{
			if ((curClass->isSubClassOf(mComponentClass) || curClass->isSubClassOf(resourceClass) ||
				curClass->hasAttribute(mSerializeObjectAttribute)) && 
				curClass != mComponentClass && curClass != resourceClass &&
				curClass != mManagedComponentClass && curClass != managedResourceClass)
			{
				SPtr<ManagedSerializableTypeInfoObject> typeInfo = bs_shared_ptr_new<ManagedSerializableTypeInfoObject>();
				typeInfo->mTypeNamespace = curClass->getNamespace();
				typeInfo->mTypeName = curClass->getTypeName();
				typeInfo->mTypeId = mUniqueTypeId++;

				MonoPrimitiveType monoPrimitiveType = MonoUtil::getPrimitiveType(curClass->_getInternalClass());

				if(monoPrimitiveType == MonoPrimitiveType::ValueType)
					typeInfo->mValueType = true;
				else
					typeInfo->mValueType = false;

				SPtr<ManagedSerializableObjectInfo> objInfo = bs_shared_ptr_new<ManagedSerializableObjectInfo>();

				objInfo->mTypeInfo = typeInfo;
				objInfo->mMonoClass = curClass;

				assemblyInfo->mTypeNameToId[objInfo->getFullTypeName()] = typeInfo->mTypeId;
				assemblyInfo->mObjectInfos[typeInfo->mTypeId] = objInfo;
			}
		}

		// Populate field & property data
		for(auto& curClassInfo : assemblyInfo->mObjectInfos)
		{
			SPtr<ManagedSerializableObjectInfo> objInfo = curClassInfo.second;

			UINT32 mUniqueFieldId = 1;

			const Vector<MonoField*>& fields = objInfo->mMonoClass->getAllFields();
			for(auto& field : fields)
			{
				if(field->isStatic())
					continue;

				SPtr<ManagedSerializableTypeInfo> typeInfo = getTypeInfo(field->getType());
				if (typeInfo == nullptr)
					continue;

				SPtr<ManagedSerializableFieldInfo> fieldInfo = bs_shared_ptr_new<ManagedSerializableFieldInfo>();
				fieldInfo->mFieldId = mUniqueFieldId++;
				fieldInfo->mName = field->getName();
				fieldInfo->mMonoField = field;
				fieldInfo->mTypeInfo = typeInfo;
				fieldInfo->mParentTypeId = objInfo->mTypeInfo->mTypeId;
				
				MonoMemberVisibility visibility = field->getVisibility();
				if (visibility == MonoMemberVisibility::Public)
				{
					if (!field->hasAttribute(mDontSerializeFieldAttribute))
						fieldInfo->mFlags |= ScriptFieldFlag::Serializable;

					if (!field->hasAttribute(mHideInInspectorAttribute))
						fieldInfo->mFlags |= ScriptFieldFlag::Inspectable;

					fieldInfo->mFlags |= ScriptFieldFlag::Animable;
				}
				else
				{
					if (field->hasAttribute(mSerializeFieldAttribute))
						fieldInfo->mFlags |= ScriptFieldFlag::Serializable;

					if (field->hasAttribute(mShowInInspectorAttribute))
						fieldInfo->mFlags |= ScriptFieldFlag::Inspectable;
				}

				if (field->hasAttribute(mRangeAttribute))
					fieldInfo->mFlags |= ScriptFieldFlag::Range;

				if (field->hasAttribute(mStepAttribute))
					fieldInfo->mFlags |= ScriptFieldFlag::Step;

				objInfo->mFieldNameToId[fieldInfo->mName] = fieldInfo->mFieldId;
				objInfo->mFields[fieldInfo->mFieldId] = fieldInfo;
			}

			const Vector<MonoProperty*>& properties = objInfo->mMonoClass->getAllProperties();
			for (auto& property : properties)
			{
				SPtr<ManagedSerializableTypeInfo> typeInfo = getTypeInfo(property->getReturnType());
				if (typeInfo == nullptr)
					continue;

				SPtr<ManagedSerializablePropertyInfo> propertyInfo = bs_shared_ptr_new<ManagedSerializablePropertyInfo>();
				propertyInfo->mFieldId = mUniqueFieldId++;
				propertyInfo->mName = property->getName();
				propertyInfo->mMonoProperty = property;
				propertyInfo->mTypeInfo = typeInfo;
				propertyInfo->mParentTypeId = objInfo->mTypeInfo->mTypeId;

				if (!property->isIndexed())
				{
					MonoMemberVisibility visibility = property->getVisibility();
					if (visibility == MonoMemberVisibility::Public)
						propertyInfo->mFlags |= ScriptFieldFlag::Animable;

					if (property->hasAttribute(mSerializeFieldAttribute))
						propertyInfo->mFlags |= ScriptFieldFlag::Serializable;

					if (property->hasAttribute(mShowInInspectorAttribute))
						propertyInfo->mFlags |= ScriptFieldFlag::Inspectable;
				}

				if (property->hasAttribute(mRangeAttribute))
					propertyInfo->mFlags |= ScriptFieldFlag::Range;

				if (property->hasAttribute(mStepAttribute))
					propertyInfo->mFlags |= ScriptFieldFlag::Step;

				objInfo->mFieldNameToId[propertyInfo->mName] = propertyInfo->mFieldId;
				objInfo->mFields[propertyInfo->mFieldId] = propertyInfo;
			}
		}

		// Form parent/child connections
		for(auto& curClass : assemblyInfo->mObjectInfos)
		{
			MonoClass* base = curClass.second->mMonoClass->getBaseClass();
			while(base != nullptr)
			{
				SPtr<ManagedSerializableObjectInfo> baseObjInfo;
				if(getSerializableObjectInfo(base->getNamespace(), base->getTypeName(), baseObjInfo))
				{
					curClass.second->mBaseClass = baseObjInfo;
					baseObjInfo->mDerivedClasses.push_back(curClass.second);

					break;
				}

				base = base->getBaseClass();
			}
		}
	}