Browse Source

Feature: Non-component, non-resource script exported types can now have automatic inspectors

BearishSun 7 years ago
parent
commit
aa29c5ff37

+ 3 - 3
Source/Scripting/MBansheeEngine/Serialization/ShowInInspector.cs

@@ -11,10 +11,10 @@ namespace BansheeEngine
     /// <summary>
     /// Attribute that forces a field or a property to be visible in the inspector window in editor. Normally public fields
     /// are show in the inspector by default, and you can use this attribute to show private/protected/internal fields, or
-    /// to show properties (never shown by default) as well. Member must be in a serializable object otherwise this
-    /// attribute has no effect, and the type of the field/property must be a serializable type.
+    /// to show properties (never shown by default) as well. Type of the field/property must be a serializable type or
+    /// a type marked with this attribute itself.
     /// </summary>
-    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct)]
     public sealed class ShowInInspector : Attribute
     {
     }

+ 1 - 0
Source/Scripting/SBansheeEngine/RTTI/BsManagedSerializableObjectInfoRTTI.h

@@ -352,6 +352,7 @@ namespace bs
 			BS_RTTI_MEMBER_PLAIN(mTypeNamespace, 1)
 			BS_RTTI_MEMBER_PLAIN(mValueType, 2)
 			BS_RTTI_MEMBER_PLAIN(mTypeId, 4)
+			BS_RTTI_MEMBER_PLAIN(mFlags, 5)
 		BS_END_RTTI_MEMBERS
 
 	public:

+ 3 - 0
Source/Scripting/SBansheeEngine/Serialization/BsManagedSerializableObject.cpp

@@ -80,6 +80,9 @@ namespace bs
 		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(type->mTypeNamespace, type->mTypeName, currentObjInfo))
 			return nullptr;
 
+		if(!currentObjInfo->mTypeInfo->mFlags.isSet(ScriptTypeFlag::Serializable))
+			return nullptr;
+
 		const bool construct = currentObjInfo->mMonoClass->getMethod(".ctor", 0) != nullptr;
 		return currentObjInfo->mMonoClass->createInstance(construct);
 	}

+ 13 - 2
Source/Scripting/SBansheeEngine/Serialization/BsManagedSerializableObjectInfo.h

@@ -53,17 +53,27 @@ namespace bs
 		Range        = 1 << 2,
 		Step         = 1 << 3,
 		Animable     = 1 << 4,
-		LayerMask   = 1 << 5
+		LayerMask    = 1 << 5
 	};
 
 	typedef Flags<ScriptFieldFlag> ScriptFieldFlags;
 	BS_FLAGS_OPERATORS(ScriptFieldFlag);
 
+	/** Flags that are used to further desribe a type of a managed serializable object. */
+	enum class ScriptTypeFlag
+	{
+		Serializable = 1 << 0,
+		Inspectable  = 1 << 1
+	};
+
+	typedef Flags<ScriptTypeFlag> ScriptTypeFlags;
+	BS_FLAGS_OPERATORS(ScriptTypeFlag);
+
 	/**	Contains information about a type of a managed serializable object. */
 	class BS_SCR_BE_EXPORT ManagedSerializableTypeInfo : public IReflectable
 	{
 	public:
-		virtual ~ManagedSerializableTypeInfo() {}
+		virtual ~ManagedSerializableTypeInfo() = default;
 
 		/**	Checks if the current type matches the provided type. */
 		virtual bool matches(const SPtr<ManagedSerializableTypeInfo>& typeInfo) const = 0;
@@ -180,6 +190,7 @@ namespace bs
 		String mTypeNamespace;
 		String mTypeName;
 		bool mValueType;
+		ScriptTypeFlags mFlags;
 		UINT32 mTypeId;
 
 		/************************************************************************/

+ 39 - 8
Source/Scripting/SBansheeEngine/Serialization/BsScriptAssemblyManager.cpp

@@ -113,8 +113,15 @@ namespace bs
 		const Vector<MonoClass*>& allClasses = curAssembly->getAllClasses();
 		for(auto& curClass : allClasses)
 		{
-			if ((curClass->isSubClassOf(mBuiltin.componentClass) || curClass->isSubClassOf(resourceClass) ||
-				curClass->hasAttribute(mBuiltin.serializeObjectAttribute)) && 
+			const bool isSerializable = 
+				curClass->isSubClassOf(mBuiltin.componentClass) || 
+				curClass->isSubClassOf(resourceClass) ||
+				curClass->hasAttribute(mBuiltin.serializeObjectAttribute);
+
+			const bool isInspectable =
+				curClass->hasAttribute(mBuiltin.showInInspectorAttribute);
+
+			if ((isSerializable || isInspectable) &&
 				curClass != mBuiltin.componentClass && curClass != resourceClass &&
 				curClass != mBuiltin.managedComponentClass && curClass != managedResourceClass)
 			{
@@ -123,6 +130,12 @@ namespace bs
 				typeInfo->mTypeName = curClass->getTypeName();
 				typeInfo->mTypeId = mUniqueTypeId++;
 
+				if(isSerializable)
+					typeInfo->mFlags |= ScriptTypeFlag::Serializable;
+
+				if(isSerializable || isInspectable)
+					typeInfo->mFlags |= ScriptTypeFlag::Inspectable;
+
 				MonoPrimitiveType monoPrimitiveType = MonoUtil::getPrimitiveType(curClass->_getInternalClass());
 
 				if(monoPrimitiveType == MonoPrimitiveType::ValueType)
@@ -157,6 +170,15 @@ namespace bs
 				if (typeInfo == nullptr)
 					continue;
 
+				bool typeIsSerializable = true;
+				bool typeIsInspectable = true;
+
+				if(const auto* objTypeInfo = rtti_cast<ManagedSerializableTypeInfoObject>(typeInfo.get()))
+				{
+					typeIsSerializable = objTypeInfo->mFlags.isSet(ScriptTypeFlag::Serializable);
+					typeIsInspectable = typeIsSerializable || objTypeInfo->mFlags.isSet(ScriptTypeFlag::Inspectable);
+				}
+
 				SPtr<ManagedSerializableFieldInfo> fieldInfo = bs_shared_ptr_new<ManagedSerializableFieldInfo>();
 				fieldInfo->mFieldId = mUniqueFieldId++;
 				fieldInfo->mName = field->getName();
@@ -167,20 +189,20 @@ namespace bs
 				MonoMemberVisibility visibility = field->getVisibility();
 				if (visibility == MonoMemberVisibility::Public)
 				{
-					if (!field->hasAttribute(mBuiltin.dontSerializeFieldAttribute))
+					if (typeIsSerializable && !field->hasAttribute(mBuiltin.dontSerializeFieldAttribute))
 						fieldInfo->mFlags |= ScriptFieldFlag::Serializable;
 
-					if (!field->hasAttribute(mBuiltin.hideInInspectorAttribute))
+					if (typeIsInspectable && !field->hasAttribute(mBuiltin.hideInInspectorAttribute))
 						fieldInfo->mFlags |= ScriptFieldFlag::Inspectable;
 
 					fieldInfo->mFlags |= ScriptFieldFlag::Animable;
 				}
 				else
 				{
-					if (field->hasAttribute(mBuiltin.serializeFieldAttribute))
+					if (typeIsSerializable && field->hasAttribute(mBuiltin.serializeFieldAttribute))
 						fieldInfo->mFlags |= ScriptFieldFlag::Serializable;
 
-					if (field->hasAttribute(mBuiltin.showInInspectorAttribute))
+					if (typeIsInspectable && field->hasAttribute(mBuiltin.showInInspectorAttribute))
 						fieldInfo->mFlags |= ScriptFieldFlag::Inspectable;
 				}
 
@@ -214,6 +236,15 @@ namespace bs
 				if (typeInfo == nullptr)
 					continue;
 
+				bool typeIsSerializable = true;
+				bool typeIsInspectable = true;
+
+				if(const auto* objTypeInfo = rtti_cast<ManagedSerializableTypeInfoObject>(typeInfo.get()))
+				{
+					typeIsSerializable = objTypeInfo->mFlags.isSet(ScriptTypeFlag::Serializable);
+					typeIsInspectable = typeIsSerializable || objTypeInfo->mFlags.isSet(ScriptTypeFlag::Inspectable);
+				}
+
 				SPtr<ManagedSerializablePropertyInfo> propertyInfo = bs_shared_ptr_new<ManagedSerializablePropertyInfo>();
 				propertyInfo->mFieldId = mUniqueFieldId++;
 				propertyInfo->mName = property->getName();
@@ -227,10 +258,10 @@ namespace bs
 					if (visibility == MonoMemberVisibility::Public)
 						propertyInfo->mFlags |= ScriptFieldFlag::Animable;
 
-					if (property->hasAttribute(mBuiltin.serializeFieldAttribute))
+					if (typeIsSerializable && property->hasAttribute(mBuiltin.serializeFieldAttribute))
 						propertyInfo->mFlags |= ScriptFieldFlag::Serializable;
 
-					if (property->hasAttribute(mBuiltin.showInInspectorAttribute))
+					if (typeIsInspectable && property->hasAttribute(mBuiltin.showInInspectorAttribute))
 						propertyInfo->mFlags |= ScriptFieldFlag::Inspectable;
 
 					if (property->hasAttribute(mBuiltin.rangeAttribute))