Просмотр исходного кода

Refactoring C# components so they're just wrappers for C++ ones, to avoid duplicate code

BearishSun 8 лет назад
Родитель
Сommit
3eecbecfa0
51 измененных файлов с 975 добавлено и 269 удалено
  1. 6 3
      Source/BansheeCore/Include/BsComponent.h
  2. 6 0
      Source/BansheeCore/Include/BsSceneObject.h
  3. 29 0
      Source/BansheeCore/Source/BsSceneObject.cpp
  4. 1 1
      Source/BansheeUtility/Include/BsRTTIType.h
  5. 3 3
      Source/BansheeVulkanRenderAPI/Source/BsVulkanCommandBuffer.cpp
  6. 1 1
      Source/MBansheeEditor/General/EditorPersistentData.cs
  7. 2 2
      Source/MBansheeEditor/Tests/UnitTestTypes.cs
  8. 2 2
      Source/MBansheeEditor/Utility/SerializedObject.cs
  9. 1 1
      Source/MBansheeEditor/Windows/Inspector/InspectorPersistentData.cs
  10. 1 1
      Source/MBansheeEditor/Windows/Scene/SceneCamera.cs
  11. 1 1
      Source/MBansheeEngine/Animation/Animation.cs
  12. 1 1
      Source/MBansheeEngine/Animation/Bone.cs
  13. 1 1
      Source/MBansheeEngine/Audio/AudioListener.cs
  14. 1 1
      Source/MBansheeEngine/Audio/AudioSource.cs
  15. 1 1
      Source/MBansheeEngine/GUI/GUIWidget.cs
  16. 1 1
      Source/MBansheeEngine/Interop/ScriptObject.cs
  17. 1 0
      Source/MBansheeEngine/MBansheeEngine.csproj
  18. 1 1
      Source/MBansheeEngine/Physics/CharacterController.cs
  19. 1 1
      Source/MBansheeEngine/Physics/Collider.cs
  20. 1 1
      Source/MBansheeEngine/Physics/Joint.cs
  21. 1 1
      Source/MBansheeEngine/Physics/Rigidbody.cs
  22. 1 1
      Source/MBansheeEngine/Rendering/Camera.cs
  23. 1 1
      Source/MBansheeEngine/Rendering/Light.cs
  24. 1 1
      Source/MBansheeEngine/Rendering/Renderable.cs
  25. 39 26
      Source/MBansheeEngine/Scene/Component.cs
  26. 1 1
      Source/MBansheeEngine/Scene/MissingComponent.cs
  27. 1 1
      Source/MBansheeEngine/Utility/ProfilerOverlay.cs
  28. 1 1
      Source/SBansheeEditor/Include/BsScriptSerializedObject.h
  29. 4 3
      Source/SBansheeEditor/Source/BsScriptSerializedObject.cpp
  30. 3 0
      Source/SBansheeEngine/CMakeSources.cmake
  31. 82 0
      Source/SBansheeEngine/Include/BsBuiltinComponentLookup.h
  32. 3 3
      Source/SBansheeEngine/Include/BsManagedComponentRTTI.h
  33. 4 1
      Source/SBansheeEngine/Include/BsManagedSerializableObjectInfo.h
  34. 1 0
      Source/SBansheeEngine/Include/BsManagedSerializableObjectInfoRTTI.h
  35. 23 0
      Source/SBansheeEngine/Include/BsScriptAssemblyManager.h
  36. 88 32
      Source/SBansheeEngine/Include/BsScriptComponent.h
  37. 12 0
      Source/SBansheeEngine/Include/BsScriptEnginePrerequisites.h
  38. 2 2
      Source/SBansheeEngine/Include/BsScriptGameObject.h
  39. 21 9
      Source/SBansheeEngine/Include/BsScriptGameObjectManager.h
  40. 59 0
      Source/SBansheeEngine/Include/BsScriptManagedComponent.h
  41. 3 3
      Source/SBansheeEngine/Include/BsScriptManagedResource.h
  42. 26 1
      Source/SBansheeEngine/Include/BsScriptRenderable.h
  43. 2 2
      Source/SBansheeEngine/Include/BsScriptResource.h
  44. 3 2
      Source/SBansheeEngine/Source/BsManagedComponent.cpp
  45. 38 5
      Source/SBansheeEngine/Source/BsManagedSerializableField.cpp
  46. 6 2
      Source/SBansheeEngine/Source/BsManagedSerializableObjectInfo.cpp
  47. 76 7
      Source/SBansheeEngine/Source/BsScriptAssemblyManager.cpp
  48. 89 118
      Source/SBansheeEngine/Source/BsScriptComponent.cpp
  49. 67 22
      Source/SBansheeEngine/Source/BsScriptGameObjectManager.cpp
  50. 120 0
      Source/SBansheeEngine/Source/BsScriptManagedComponent.cpp
  51. 135 1
      Source/SBansheeEngine/Source/BsScriptRenderable.cpp

+ 6 - 3
Source/BansheeCore/Include/BsComponent.h

@@ -68,6 +68,12 @@ namespace bs
 		 */
 		virtual void _instantiate() {}
 
+		/** Sets new flags that determine when is onTransformChanged called. */
+		void _setNotifyFlags(TransformChangedFlags flags) { mNotifyFlags = flags; }
+
+		/** Gets the currently assigned notify flags. See _setNotifyFlags(). */
+		TransformChangedFlags _getNotifyFlags() const { return mNotifyFlags; }
+
 		/** @} */
 	protected:
 		friend class SceneObject;
@@ -91,9 +97,6 @@ namespace bs
 		/** Called when the component's parent scene object has changed. */
 		virtual void onTransformChanged(TransformChangedFlags flags) { }
 
-		/** Sets new flags that determine when is onTransformChanged called. */
-		void setNotifyFlags(TransformChangedFlags flags) { mNotifyFlags = flags; }
-
 		/** Checks whether the component wants to received the specified transform changed message. */
 		bool supportsNotify(TransformChangedFlags flags) const { return (mNotifyFlags & flags) != 0; }
 

+ 6 - 0
Source/BansheeCore/Include/BsSceneObject.h

@@ -528,6 +528,12 @@ namespace bs
 			return newComponent;
 		}
 
+		/** 
+		 * Constructs a new component of the specified type id and adds it to the internal component list. Component must
+		 * have a parameterless constructor.
+		 */
+		HComponent addComponent(UINT32 typeId);
+
 		/**
 		 * Searches for a component with the specific type and returns the first one it finds. Will also return components
 		 * derived from the type.

+ 29 - 0
Source/BansheeCore/Source/BsSceneObject.cpp

@@ -772,6 +772,35 @@ namespace bs
 		}
 	}
 
+	HComponent SceneObject::addComponent(UINT32 typeId)
+	{
+		SPtr<IReflectable> newObj = rtti_create(typeId);
+
+		if(!rtti_is_subclass<Component>(newObj.get()))
+		{
+			LOGERR("Specified type is not a valid Component.");
+			return HComponent();
+		}
+
+		SPtr<Component> componentPtr = std::static_pointer_cast<Component>(newObj);
+		HComponent newComponent = GameObjectManager::instance().registerObject(componentPtr);
+
+		newComponent->mParent = mThisHandle;
+		newComponent->mThisHandle = newComponent;
+		mComponents.push_back(newComponent);
+
+		if (isInstantiated())
+		{
+			newComponent->_instantiate();
+			newComponent->onInitialized();
+
+			if (getActive())
+				newComponent->onEnabled();
+		}
+
+		return newComponent;
+	}
+
 	void SceneObject::addComponentInternal(const SPtr<Component> component)
 	{
 		GameObjectHandle<Component> newComponent = GameObjectManager::instance().getObject(component->getInstanceId());

+ 1 - 1
Source/BansheeUtility/Include/BsRTTIType.h

@@ -1225,7 +1225,7 @@ namespace bs
 	}
 
 	/** Creates a new object just from its type ID. */
-	SPtr<IReflectable> rtti_create(UINT32 rttiId);
+	BS_UTILITY_EXPORT SPtr<IReflectable> rtti_create(UINT32 rttiId);
 
 	/** Checks is the current object a subclass of some type. */
 	template<class T>

+ 3 - 3
Source/BansheeVulkanRenderAPI/Source/BsVulkanCommandBuffer.cpp

@@ -183,7 +183,7 @@ namespace bs { namespace ct
 			for (auto& entry : mResources)
 			{
 				ResourceUseHandle& useHandle = entry.second;
-				assert(useHandle.used);
+				assert(!useHandle.used);
 
 				entry.first->notifyUnbound();
 			}
@@ -194,7 +194,7 @@ namespace bs { namespace ct
 				ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
 
 				ResourceUseHandle& useHandle = imageInfo.useHandle;
-				assert(useHandle.used);
+				assert(!useHandle.used);
 
 				entry.first->notifyUnbound();
 			}
@@ -202,7 +202,7 @@ namespace bs { namespace ct
 			for (auto& entry : mBuffers)
 			{
 				ResourceUseHandle& useHandle = entry.second.useHandle;
-				assert(useHandle.used);
+				assert(!useHandle.used);
 
 				entry.first->notifyUnbound();
 			}

+ 1 - 1
Source/MBansheeEditor/General/EditorPersistentData.cs

@@ -12,7 +12,7 @@ namespace BansheeEditor
     /// <summary>
     /// Contains editor data that should persist assembly refresh.
     /// </summary>
-    internal class EditorPersistentData : Component
+    internal class EditorPersistentData : ManagedComponent
     {
         [SerializeField]
         internal Dictionary<string, bool> dirtyResources = new Dictionary<string, bool>();

+ 2 - 2
Source/MBansheeEditor/Tests/UnitTestTypes.cs

@@ -12,7 +12,7 @@ namespace BansheeEditor
     /// <summary>
     /// Helper component used for unit tests.
     /// </summary>
-    internal class UT1_Component1 : Component
+    internal class UT1_Component1 : ManagedComponent
     {
         public int a;
         public string b;
@@ -40,7 +40,7 @@ namespace BansheeEditor
     /// <summary>
     /// Helper component used for unit tests.
     /// </summary>
-    internal class UT1_Component2 : Component
+    internal class UT1_Component2 : ManagedComponent
     {
         public int a2;
     }

+ 2 - 2
Source/MBansheeEditor/Utility/SerializedObject.cs

@@ -12,7 +12,7 @@ namespace BansheeEditor
 
     /// <summary>
     /// Container and functionality to creating a serialized version of an object. The object must be of valid serializable
-    /// type (<see cref="Component"/>, <see cref="ManagedResource"/> or a class/struct marked with 
+    /// type (<see cref="ManagedComponent"/>, <see cref="ManagedResource"/> or a class/struct marked with 
     /// <see cref="SerializeObject"/> attribute).
     /// </summary>
     public class SerializedObject : ScriptObject
@@ -28,7 +28,7 @@ namespace BansheeEditor
         /// </summary>
         /// <param name="obj">Component to serialize.</param>
         /// <returns>Object containing serialized data.</returns>
-        public static SerializedObject Create(Component obj)
+        public static SerializedObject Create(ManagedComponent obj)
         {
             if (obj == null)
                 return null;

+ 1 - 1
Source/MBansheeEditor/Windows/Inspector/InspectorPersistentData.cs

@@ -12,7 +12,7 @@ namespace BansheeEditor
     /// <summary>
     /// Contains Inspector specific data that should persist assembly refresh.
     /// </summary>
-    internal class InspectorPersistentData : Component
+    internal class InspectorPersistentData : ManagedComponent
     {
         [SerializeField]
         private Dictionary<ulong, SerializableProperties> componentProperties =

+ 1 - 1
Source/MBansheeEditor/Windows/Scene/SceneCamera.cs

@@ -12,7 +12,7 @@ namespace BansheeEditor
     /// Handles camera movement in the scene view.
     /// </summary>
     [RunInEditor]
-    internal sealed class SceneCamera : Component
+    internal sealed class SceneCamera : ManagedComponent
     {
         #region Constants
         public const string MoveForwardBinding = "SceneForward";

+ 1 - 1
Source/MBansheeEngine/Animation/Animation.cs

@@ -17,7 +17,7 @@ namespace BansheeEngine
     /// thread for updating attached scene objects and bones (if skeleton is attached), or the data is made available for
     /// manual queries in the case of generic animation.
     /// </summary>
-    public class Animation : Component
+    public class Animation : ManagedComponent
     {
         private NativeAnimation _native;
 

+ 1 - 1
Source/MBansheeEngine/Animation/Bone.cs

@@ -12,7 +12,7 @@ namespace BansheeEngine
     /// Component that maps animation for specific bone also be applied to the <see cref="SceneObject"/> this component
     /// is attached to. The component will attach to the first found parent <see cref="Animation"/> component.
     /// </summary>
-    public class Bone : Component
+    public class Bone : ManagedComponent
     {
         [SerializeField]
         private string name;

+ 1 - 1
Source/MBansheeEngine/Audio/AudioListener.cs

@@ -10,7 +10,7 @@ namespace BansheeEngine
     /// Represents a listener that hears audio sources. For spatial audio the volume and pitch of played audio is determined
     /// by the distance, orientation and velocity differences between the source and the listener.
     /// </summary>
-    public abstract class AudioListener : Component
+    public abstract class AudioListener : ManagedComponent
     {
         internal NativeAudioListener native;
 

+ 1 - 1
Source/MBansheeEngine/Audio/AudioSource.cs

@@ -32,7 +32,7 @@ namespace BansheeEngine
     /// Whether or not an audio source is spatial is controlled by the assigned AudioClip.The volume and the pitch of a
     /// spatial audio source is controlled by its position and the AudioListener's position/direction/velocity.
     /// </summary>
-    public abstract class AudioSource : Component
+    public abstract class AudioSource : ManagedComponent
     {
         internal NativeAudioSource native;
 

+ 1 - 1
Source/MBansheeEngine/GUI/GUIWidget.cs

@@ -10,7 +10,7 @@ namespace BansheeEngine
     /// Container of GUI elements that can be positioned in the scene, and can output the rendered GUI to a user defined
     /// camera.
     /// </summary>
-    public class GUIWidget : Component
+    public class GUIWidget : ManagedComponent
     {
         private NativeGUIWidget nativeGUIWidget;
 

+ 1 - 1
Source/MBansheeEngine/Interop/ScriptObject.cs

@@ -38,7 +38,7 @@ namespace BansheeEngine
         /// <summary>
         /// Returns a pointer to the native script interop object.
         /// </summary>
-        /// <returns>Pointer to the native script interop object</returns>
+        /// <returns>Pointer to the native script interop object.</returns>
         internal IntPtr GetCachedPtr()
         {
             return mCachedPtr;

+ 1 - 0
Source/MBansheeEngine/MBansheeEngine.csproj

@@ -60,6 +60,7 @@
     <Compile Include="GUI\GUICanvas.cs" />
     <Compile Include="GUI\GUIScrollBar.cs" />
     <Compile Include="Rendering\PostProcessSettings.cs" />
+    <Compile Include="Rendering\Renderable2.cs" />
     <Compile Include="Serialization\ShowInInspector.cs" />
     <Compile Include="Serialization\Step.cs" />
     <Compile Include="Utility\AsyncOp.cs" />

+ 1 - 1
Source/MBansheeEngine/Physics/CharacterController.cs

@@ -14,7 +14,7 @@ namespace BansheeEngine
     /// of the standard physics model to handle various issues with manually moving kinematic objects.Uses a capsule to
     /// represent the character's bounds. 
     /// </summary>
-    public sealed class CharacterController : Component
+    public sealed class CharacterController : ManagedComponent
     {
         internal NativeCharacterController native;
 

+ 1 - 1
Source/MBansheeEngine/Physics/Collider.cs

@@ -15,7 +15,7 @@ namespace BansheeEngine
     ///  - Dynamic: Dynamic geometry that is a part of a Rigidbody.A set of colliders defines the shape of the parent 
     ///             rigidbody.
     /// </summary>
-    public abstract class Collider : Component
+    public abstract class Collider : ManagedComponent
     {
         internal NativeCollider native;
         protected Rigidbody parent;

+ 1 - 1
Source/MBansheeEngine/Physics/Joint.cs

@@ -13,7 +13,7 @@ namespace BansheeEngine
     /// Base class for all Joint types. Joints constrain how two rigidbodies move relative to one another (for example a
     /// door hinge). One of the bodies in the joint must always be movable (that is non-kinematic).
     /// </summary>
-    public abstract class Joint : Component
+    public abstract class Joint : ManagedComponent
     {
         internal NativeJoint native;
 

+ 1 - 1
Source/MBansheeEngine/Physics/Rigidbody.cs

@@ -18,7 +18,7 @@ namespace BansheeEngine
     /// rigidbody to be valid. Colliders that are on the same scene object as the rigidbody, or on child scene objects
     /// are automatically considered as part of the rigidbody.
     /// </summary>
-    public sealed class Rigidbody : Component
+    public sealed class Rigidbody : ManagedComponent
     {
         internal NativeRigidbody native;
         private List<Collider> children = new List<Collider>();

+ 1 - 1
Source/MBansheeEngine/Rendering/Camera.cs

@@ -14,7 +14,7 @@ namespace BansheeEngine
     /// rendering.
     /// </summary>
     [RunInEditor]
-    public sealed class Camera : Component
+    public sealed class Camera : ManagedComponent
     {
         private NativeCamera native;
 

+ 1 - 1
Source/MBansheeEngine/Rendering/Light.cs

@@ -10,7 +10,7 @@ namespace BansheeEngine
     /// Component that illuminates a portion of the scene covered by the light.
     /// </summary>
     [RunInEditor]
-    public sealed class Light : Component
+    public sealed class Light : ManagedComponent
     {
         private NativeLight _nativeLight;
 

+ 1 - 1
Source/MBansheeEngine/Rendering/Renderable.cs

@@ -13,7 +13,7 @@ namespace BansheeEngine
     /// render any Renderable objects visible by a camera.
     /// </summary>
     [RunInEditor]
-    public sealed class Renderable : Component
+    public sealed class Renderable : ManagedComponent
     {
         private NativeRenderable _native;
         private Animation animation;

+ 39 - 26
Source/MBansheeEngine/Scene/Component.cs

@@ -12,30 +12,11 @@ namespace BansheeEngine
     /// <summary>
     /// Base class for all components. Components represent primary logic elements in the scene. They are attached to 
     /// scene objects.
-    ///
-    /// Implementations of <see cref="Component"/> can implement a set of callbacks that will be called by the runtime
-    /// at specified occassions:
-    /// void OnInitialize() - Called once when the component is instantiated. Only called when the game is playing.
-    /// void OnUpdate() - Called every frame while the game is running and the component is enabled.
-    /// void OnEnable() - Called whenever a component is enabled, or instantiated as enabled in which case it is called 
-    ///                   after OnInitialize. Only called when the game is playing.
-    /// void OnDisable() - Called whenever a component is disabled. This includes destruction where it is called before 
-    ///                    OnDestroy. Only called when the game is playing.
-    /// void OnDestroy() - Called before the component is destroyed. Destruction is usually delayed until the end of the 
-    ///                    current frame unless specified otherwise in a call to Destroy. 
-    /// void OnReset() - Called when script assemblies have been refreshed or when the component is initialized. During
-    ///                  initialization it is called after OnInitialize but before OnEnable. Only relevant in editor.
-    /// void OnTransformChanged(TransformChangedFlags) - Called when the transform of the owning scene object changes.
-    ///                                                  When and if this gets triggered depends on 
-    ///                                                  <see cref="NotifyFlags"/>.
-    ///
-    /// You can also make these callbacks trigger when the game is stopped/paused by using the <see cref="RunInEditor"/>
-    /// attribute on the component.
     /// </summary>
     public class Component : GameObject
     {
         // Internal use only
-        protected Component()
+        internal Component()
         { }
 
         /// <summary>
@@ -86,10 +67,8 @@ namespace BansheeEngine
         /// Calls a parameterless method with the specified name, on the component. 
         /// </summary>
         /// <param name="name">Name of the method to call.</param>
-        protected internal void Invoke(string name)
-        {
-            Internal_Invoke(mCachedPtr, name);
-        }
+        protected internal virtual void Invoke(string name)
+        { }
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         internal static extern Component Internal_AddComponent(SceneObject parent, Type type);
@@ -116,10 +95,44 @@ namespace BansheeEngine
         internal static extern void Internal_SetNotifyFlags(IntPtr nativeInstance, TransformChangedFlags flags);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void Internal_Invoke(IntPtr nativeInstance, string name);
+        private static extern void Internal_Destroy(IntPtr nativeInstance, bool immediate);
+    }
+
+    /// <summary>
+    /// Base class for custom component implementations.
+    ///
+    /// Implementations of <see cref="ManagedComponent"/> can implement a set of callbacks that will be called by the
+    /// runtime at specified occassions:
+    /// void OnInitialize() - Called once when the component is instantiated. Only called when the game is playing.
+    /// void OnUpdate() - Called every frame while the game is running and the component is enabled.
+    /// void OnEnable() - Called whenever a component is enabled, or instantiated as enabled in which case it is called 
+    ///                   after OnInitialize. Only called when the game is playing.
+    /// void OnDisable() - Called whenever a component is disabled. This includes destruction where it is called before 
+    ///                    OnDestroy. Only called when the game is playing.
+    /// void OnDestroy() - Called before the component is destroyed. Destruction is usually delayed until the end of the 
+    ///                    current frame unless specified otherwise in a call to Destroy. 
+    /// void OnReset() - Called when script assemblies have been refreshed or when the component is initialized. During
+    ///                  initialization it is called after OnInitialize but before OnEnable. Only relevant in editor.
+    /// void OnTransformChanged(TransformChangedFlags) - Called when the transform of the owning scene object changes.
+    ///                                                  When and if this gets triggered depends on 
+    ///                                                  <see cref="Component.NotifyFlags"/>.
+    ///
+    /// You can also make these callbacks trigger when the game is stopped/paused by using the <see cref="RunInEditor"/>
+    /// attribute on the component.
+    /// </summary>
+    public class ManagedComponent : Component
+    {
+        protected ManagedComponent()
+        { }
+
+        /// <inheritdoc/>
+        protected internal override void Invoke(string name)
+        {
+            Internal_Invoke(mCachedPtr, name);
+        }
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_Destroy(IntPtr nativeInstance, bool immediate);
+        internal static extern void Internal_Invoke(IntPtr nativeInstance, string name);
     }
 
     /** @} */

+ 1 - 1
Source/MBansheeEngine/Scene/MissingComponent.cs

@@ -10,7 +10,7 @@ namespace BansheeEngine
     /// <summary>
     /// Component type that is used in place of deserialized component types that no longer exist.
     /// </summary>
-    internal sealed class MissingComponent : Component
+    internal sealed class MissingComponent : ManagedComponent
     {
     }
 

+ 1 - 1
Source/MBansheeEngine/Utility/ProfilerOverlay.cs

@@ -19,7 +19,7 @@ namespace BansheeEngine
     /// Component that displays a profiler overlay on the main game window.
     /// </summary>
     [RunInEditor]
-    public sealed class ProfilerOverlay : Component
+    public sealed class ProfilerOverlay : ManagedComponent
     {
         private ProfilerOverlayInternal impl;
 

+ 1 - 1
Source/SBansheeEditor/Include/BsScriptSerializedObject.h

@@ -28,7 +28,7 @@ namespace bs
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
-		static MonoObject* internal_CreateComponent(ScriptComponent* componentPtr);
+		static MonoObject* internal_CreateComponent(ScriptManagedComponent* componentPtr);
 		static MonoObject* internal_CreateResource(ScriptManagedResource* resourcePtr);
 		static MonoObject* internal_CreateGeneric(MonoObject* obj);
 		static MonoObject* internal_Deserialize(ScriptSerializedObject* thisPtr);

+ 4 - 3
Source/SBansheeEditor/Source/BsScriptSerializedObject.cpp

@@ -3,12 +3,13 @@
 #include "BsScriptSerializedObject.h"
 #include "BsScriptMeta.h"
 #include "BsMonoClass.h"
-#include "BsScriptComponent.h"
+#include "BsScriptManagedComponent.h"
 #include "BsScriptManagedResource.h"
 #include "BsManagedComponent.h"
 #include "BsManagedResource.h"
 #include "BsManagedSerializableObject.h"
 #include "BsScriptAssemblyManager.h"
+#include "BsRTTIType.h"
 
 namespace bs
 {
@@ -26,9 +27,9 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_Deserialize", &ScriptSerializedObject::internal_Deserialize);
 	}
 
-	MonoObject* ScriptSerializedObject::internal_CreateComponent(ScriptComponent* componentPtr)
+	MonoObject* ScriptSerializedObject::internal_CreateComponent(ScriptManagedComponent* componentPtr)
 	{
-		HManagedComponent component = componentPtr->getHandle();
+		HManagedComponent component = static_object_cast<ManagedComponent>(componentPtr->getHandle());
 		if (component.isDestroyed())
 			return nullptr;
 

+ 3 - 0
Source/SBansheeEngine/CMakeSources.cmake

@@ -147,6 +147,7 @@ set(BS_SBANSHEEENGINE_INC_WRAPPERS
 	"Include/BsScriptAnimationCurves.h"
 	"Include/BsScriptSkeleton.h"
 	"Include/BsScriptMorphShapes.h"
+	"Include/BsScriptManagedComponent.h"
 )
 
 set(BS_SBANSHEEENGINE_INC_WRAPPERS_GUI
@@ -284,6 +285,7 @@ set(BS_SBANSHEEENGINE_SRC_WRAPPERS
 	"Source/BsScriptAnimationCurves.cpp"
 	"Source/BsScriptSkeleton.cpp"
 	"Source/BsScriptMorphShapes.cpp"
+	"Source/BsScriptManagedComponent.cpp"
 )
 
 set(BS_SBANSHEEENGINE_INC_SERIALIZATION
@@ -296,6 +298,7 @@ set(BS_SBANSHEEENGINE_INC_SERIALIZATION
 	"Include/BsScriptAssemblyManager.h"
 	"Include/BsManagedSerializableDiff.h"
 	"Include/BsManagedDiff.h"
+	"Include/BsBuiltinComponentLookup.h"
 )
 
 set(BS_SBANSHEEENGINE_SRC_NOFILTER

+ 82 - 0
Source/SBansheeEngine/Include/BsBuiltinComponentLookup.h

@@ -0,0 +1,82 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptMeta.h"
+#include "BsMonoClass.h"
+
+#include "BsScriptRenderable.h"
+
+namespace bs
+{
+	/** Begins the definition for the builtin component lookup table. */
+#define LOOKUP_BEGIN																										\
+	class BuiltinComponents																									\
+	{																														\
+	public:																													\
+		template<int TID>																									\
+		class TLookup { };																									\
+																															\
+	private:																												\
+		struct META_FirstEntry {};																							\
+		static void META_GetPrevEntries(Vector<BuiltinComponentInfo>& entries, META_FirstEntry id) { }						\
+																															\
+		typedef META_FirstEntry 
+
+	/** Registers a new entry in the component lookup table. */
+#define ADD_ENTRY(TID, Type)																								\
+		META_Entry_##Type;																									\
+																															\
+	public:																													\
+		template<>																											\
+		class TLookup<TID>																									\
+		{																													\
+			typedef Type ScriptType;																						\
+		};																													\
+																															\
+		static ScriptComponentBase* create##Type(const HComponent& component)												\
+		{																													\
+			MonoObject* managedInstance = Type::getMetaData()->scriptClass->createInstance();								\
+			Type* scriptComponent = new (bs_alloc<Type>()) Type(managedInstance, component);								\
+																															\
+			return scriptComponent;																							\
+		}																													\
+																															\
+		struct META_NextEntry_##Type {};																					\
+		static void META_GetPrevEntries(Vector<BuiltinComponentInfo>& entries, META_NextEntry_##Type id)					\
+		{																													\
+			META_GetPrevEntries(entries, META_Entry_##Type());																\
+																															\
+			BuiltinComponentInfo entry;																						\
+			entry.metaData = Type::getMetaData();																			\
+			entry.typeId = TID;																								\
+			entry.monoClass = nullptr;																						\
+			entry.createCallback = &create##Type;																			\
+																															\
+			entries.push_back(entry);																						\
+		}																													\
+																															\
+		typedef META_NextEntry_##Type
+
+	/** End the definition for the builtin component lookup table. */
+#define LOOKUP_END																											\
+		META_LastEntry;																										\
+																															\
+	public:																													\
+		static Vector<BuiltinComponentInfo> getEntries()																	\
+		{																													\
+			Vector<BuiltinComponentInfo> entries;																			\
+			META_GetPrevEntries(entries, META_LastEntry());																	\
+			return entries;																									\
+		}																													\
+	};
+
+	LOOKUP_BEGIN
+		ADD_ENTRY(TID_Renderable, ScriptRenderable2)
+	LOOKUP_END
+
+#undef LOOKUP_BEGIN
+#undef ADD_ENTRY
+#undef LOOKUP_END
+}

+ 3 - 3
Source/SBansheeEngine/Include/BsManagedComponentRTTI.h

@@ -87,18 +87,18 @@ namespace bs
 			mc->mRTTIData = nullptr;
 		}
 
-		virtual const String& getRTTIName() override
+		const String& getRTTIName() override
 		{
 			static String name = "ManagedComponent";
 			return name;
 		}
 
-		virtual UINT32 getRTTIId() override
+		UINT32 getRTTIId() override
 		{
 			return TID_ManagedComponent;
 		}
 
-		virtual SPtr<IReflectable> newRTTIObject() override
+		SPtr<IReflectable> newRTTIObject() override
 		{
 			return GameObjectRTTI::createGameObject<ManagedComponent>();
 		}

+ 4 - 1
Source/SBansheeEngine/Include/BsManagedSerializableObjectInfo.h

@@ -49,13 +49,15 @@ namespace bs
 		StringTable,
 		GUISkin,
 		SceneObject,
-		Component,
+		BuiltinComponent,
 		PhysicsMaterial,
 		PhysicsMesh,
 		AudioClip,
 		AnimationClip,
 		ManagedComponent,
 		Resource,
+		BuiltinComponentBase,
+		ManagedComponentBase,
 		Count // Keep at end
 	};
 
@@ -140,6 +142,7 @@ namespace bs
 		::MonoClass* getMonoClass() const override;
 
 		ScriptReferenceType mType;
+		UINT32 mRTIITypeId;
 		String mTypeNamespace;
 		String mTypeName;
 

+ 1 - 0
Source/SBansheeEngine/Include/BsManagedSerializableObjectInfoRTTI.h

@@ -289,6 +289,7 @@ namespace bs
 			BS_RTTI_MEMBER_PLAIN(mType, 0)
 			BS_RTTI_MEMBER_PLAIN(mTypeName, 1)
 			BS_RTTI_MEMBER_PLAIN(mTypeNamespace, 2)
+			BS_RTTI_MEMBER_PLAIN(mRTIITypeId, 3)
 		BS_END_RTTI_MEMBERS
 
 	public:

+ 23 - 0
Source/SBansheeEngine/Include/BsScriptAssemblyManager.h

@@ -8,6 +8,8 @@
 
 namespace bs
 {
+	struct BuiltinComponentInfo;
+
 	/** @addtogroup SBansheeEngine
 	 *  @{
 	 */
@@ -45,6 +47,18 @@ namespace bs
 		/**	Generates or retrieves a type info object for the specified managed class, if the class is serializable. */
 		SPtr<ManagedSerializableTypeInfo> getTypeInfo(MonoClass* monoClass);
 
+		/** 
+		 * Maps a mono type to information about a wrapped built-in component. Returns null if type doesn't correspond to
+		 * a builtin component. 
+		 */
+		BuiltinComponentInfo* getBuiltinComponentInfo(::MonoReflectionType* type);
+
+		/** 
+		 * Maps a type id to information about a wrapped built-in component. Returns null if type id doesn't correspond to
+		 * a builtin component. 
+		 */
+		BuiltinComponentInfo* getBuiltinComponentInfo(UINT32 rttiTypeId);
+
 		/**
 		 * Checks if the managed serializable object info for the specified type exists.
 		 *
@@ -72,6 +86,9 @@ namespace bs
 		/**	Gets the managed class for BansheeEngine.Component type. */
 		MonoClass* getComponentClass() const { return mComponentClass; }
 
+		/**	Gets the managed class for BansheeEngine.ManagedComponent type. */
+		MonoClass* getManagedComponentClass() const { return mManagedComponentClass; }
+
 		/**	Gets the managed class for BansheeEngine.MissingComponent type. */
 		MonoClass* getMissingComponentClass() const { return mMissingComponentClass; }
 
@@ -93,7 +110,12 @@ namespace bs
 		 */
 		void initializeBaseTypes();
 
+		/** Initializes information required for mapping builtin components to managed components. */
+		void initializeBuiltinComponentInfos();
+
 		UnorderedMap<String, SPtr<ManagedSerializableAssemblyInfo>> mAssemblyInfos;
+		UnorderedMap<::MonoReflectionType*, BuiltinComponentInfo> mBuiltinComponentInfos;
+		UnorderedMap<UINT32, BuiltinComponentInfo> mBuiltinComponentInfosByTID;
 		bool mBaseTypesInitialized;
 
 		MonoClass* mSystemArrayClass;
@@ -102,6 +124,7 @@ namespace bs
 		MonoClass* mSystemTypeClass;
 
 		MonoClass* mComponentClass;
+		MonoClass* mManagedComponentClass;
 		MonoClass* mSceneObjectClass;
 		MonoClass* mMissingComponentClass;
 

+ 88 - 32
Source/SBansheeEngine/Include/BsScriptComponent.h

@@ -5,7 +5,7 @@
 #include "BsScriptEnginePrerequisites.h"
 #include "BsScriptGameObject.h"
 #include "BsScriptObject.h"
-#include "BsFont.h"
+#include "BsMonoUtil.h"
 
 namespace bs
 {
@@ -13,45 +13,102 @@ namespace bs
 	 *  @{
 	 */
 
-	/**	Interop class between C++ & CLR for ManagedComponent. */
-	class BS_SCR_BE_EXPORT ScriptComponent : public ScriptObject<ScriptComponent, ScriptGameObjectBase>
+	/**	Base class for all Component interop classes. */
+	class BS_SCR_BE_EXPORT ScriptComponentBase : public ScriptGameObjectBase
 	{
 	public:
-		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "Component")
+		ScriptComponentBase(MonoObject* instance);
+		virtual ~ScriptComponentBase() { }
+
+		/** Returns the component wrapped by this object. */
+		HComponent getComponent() const { return static_object_cast<Component>(getNativeHandle()); }
 
-		/** @copydoc ScriptGameObjectBase::getNativeHandle */
-		HGameObject getNativeHandle() const override { return mManagedComponent; }
+	protected:
+		friend class ScriptGameObjectManager;
 
-		/** @copydoc ScriptGameObjectBase::setNativeHandle */
-		void setNativeHandle(const HGameObject& gameObject) override;
+		/** Destroys the interop object, unless refresh is in progress in which case it is just prepared for re-creation. */
+		void destroy();
 
-		/** Returns the managed component this object wraps. */
-		HManagedComponent getHandle() const { return mManagedComponent; }
+		/**	Triggered by the script game object manager when the handle this object is referencing is destroyed. */
+		virtual void _notifyDestroyed() { }
 
-	private:
+		/** Checks if the provided game object is destroyed and logs a warning if it is. */
+		static bool checkIfDestroyed(const GameObjectHandleBase& handle);
+	};
+
+	/**	Base class for a specific builtin component's interop object. */
+	template<class ScriptClass, class CompType>
+	class BS_SCR_BE_EXPORT TScriptComponent : public ScriptObject <ScriptClass, ScriptComponentBase>
+	{
+	public:
+		/**	Returns a generic handle to the internal wrapped component. */
+		HGameObject getNativeHandle() const override { return mComponent; }
+
+		/**	Sets the internal component this object wraps. */
+		void setNativeHandle(const HGameObject& gameObject) override { mComponent = static_object_cast<CompType>(gameObject); }
+
+		/**	Returns a handle to the internal wrapped component. */
+		const GameObjectHandle<CompType>& getHandle() const { return mComponent; }
+
+	protected:
 		friend class ScriptGameObjectManager;
 
-		ScriptComponent(MonoObject* instance);
-		
-		/** @copydoc ScriptObjectBase::beginRefresh */
-		ScriptObjectBackup beginRefresh() override;
+		TScriptComponent(MonoObject* instance, const GameObjectHandle<CompType>& component)
+			:ScriptObject<ScriptClass, ScriptComponentBase>(instance), mComponent(component)
+		{
+			mManagedHandle = MonoUtil::newGCHandle(instance);
 
-		/** @copydoc ScriptObjectBase::endRefresh */
-		void endRefresh(const ScriptObjectBackup& backupData) override;
+			BS_DEBUG_ONLY(mHandleValid = true);
+		}
 
-		/** @copydoc ScriptObjectBase::_createManagedInstance */
-		MonoObject* _createManagedInstance(bool construct) override;
+		virtual ~TScriptComponent() {}
 
-		/** @copydoc ScriptObjectBase::_onManagedInstanceDeleted */
-		void _onManagedInstanceDeleted() override;
+		/**
+		 * Called after assembly reload starts to give the object a chance to restore the data backed up by the previous
+		 * beginRefresh() call.
+		 */
+		virtual void endRefresh(const ScriptObjectBackup& backupData) override
+		{
+			BS_ASSERT(!mHandleValid);
+			mManagedHandle = MonoUtil::newGCHandle(this->mManagedInstance);
 
-		/** Checks if the provided game object is destroyed and logs a warning if it is. */
-		static bool checkIfDestroyed(const GameObjectHandleBase& handle);
+			ScriptObject<ScriptClass, ScriptComponentBase>::endRefresh(backupData);
+		}
+
+		/**
+		 * Triggered by the script game object manager when the native component handle this object point to has been
+		 * destroyed.
+		 */
+		void _notifyDestroyed() override
+		{
+			MonoUtil::freeGCHandle(mManagedHandle);
+			BS_DEBUG_ONLY(mHandleValid = false);
+		}
+
+		/**	Called when the managed instance gets finalized by the CLR. */
+		void _onManagedInstanceDeleted() override
+		{
+			MonoUtil::freeGCHandle(mManagedHandle);
+			BS_DEBUG_ONLY(mHandleValid = false);
+
+			this->destroy();
+		}
+
+		GameObjectHandle<CompType> mComponent;
+		uint32_t mManagedHandle;
+		BS_DEBUG_ONLY(bool mHandleValid);
+	};
+
+	/**	Interop class between C++ & CLR for Component. */
+	class BS_SCR_BE_EXPORT ScriptComponent : public ScriptObject<ScriptComponent, ScriptComponentBase>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "Component")
 
-		HManagedComponent mManagedComponent;
-		String mNamespace;
-		String mType;
-		bool mTypeMissing;
+	private:
+		friend class ScriptGameObjectManager;
+
+		ScriptComponent(MonoObject* instance);
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
@@ -61,11 +118,10 @@ namespace bs
 		static MonoArray* internal_getComponents(MonoObject* parentSceneObject);
 		static MonoArray* internal_getComponentsPerType(MonoObject* parentSceneObject, MonoReflectionType* type);
 		static void internal_removeComponent(MonoObject* parentSceneObject, MonoReflectionType* type);
-		static MonoObject* internal_getSceneObject(ScriptComponent* nativeInstance);
-		static TransformChangedFlags internal_getNotifyFlags(ScriptComponent* nativeInstance);
-		static void internal_setNotifyFlags(ScriptComponent* nativeInstance, TransformChangedFlags flags);
-		static void internal_invoke(ScriptComponent* nativeInstance, MonoString* name);
-		static void internal_destroy(ScriptComponent* nativeInstance, bool immediate);
+		static MonoObject* internal_getSceneObject(ScriptComponentBase* nativeInstance);
+		static TransformChangedFlags internal_getNotifyFlags(ScriptComponentBase* nativeInstance);
+		static void internal_setNotifyFlags(ScriptComponentBase* nativeInstance, TransformChangedFlags flags);
+		static void internal_destroy(ScriptComponentBase* nativeInstance, bool immediate);
 	};
 
 	/** @} */

+ 12 - 0
Source/SBansheeEngine/Include/BsScriptEnginePrerequisites.h

@@ -68,7 +68,9 @@ namespace bs
 	class ScriptGUIScrollAreaLayout;
 	class ScriptGameObjectBase;
 	class ScriptSceneObject;
+	class ScriptComponentBase;
 	class ScriptComponent;
+	class ScriptManagedComponent;
 	class ScriptManagedResource;
 	class ScriptRenderTarget;
 	class ScriptRenderTexture2D;
@@ -107,6 +109,7 @@ namespace bs
 	class ScriptRigidbody;
 	class ScriptColliderBase;
 	class ScriptAudioClip;
+	struct ScriptMeta;
 
 	typedef GameObjectHandle<ManagedComponent> HManagedComponent;
 	typedef ResourceHandle<ManagedResource> HManagedResource;
@@ -166,4 +169,13 @@ namespace bs
 		TID_SerializableFieldInfo = 50051,
 		TID_SerializablePropertyInfo = 50052
 	};
+
+	/** Information about a builtin component wrapped as a script object. */
+	struct BuiltinComponentInfo
+	{
+		const ScriptMeta* metaData;
+		UINT32 typeId;
+		MonoClass* monoClass;
+		std::function<ScriptComponentBase*(const HComponent&)> createCallback;
+	};
 }

+ 2 - 2
Source/SBansheeEngine/Include/BsScriptGameObject.h

@@ -25,10 +25,10 @@ namespace bs
 		virtual void setNativeHandle(const HGameObject& gameObject) = 0;
 
 		/** @copydoc ScriptObjectBase::beginRefresh */
-		virtual ScriptObjectBackup beginRefresh() override;
+		ScriptObjectBackup beginRefresh() override;
 
 		/** @copydoc ScriptObjectBase::endRefresh */
-		virtual void endRefresh(const ScriptObjectBackup& backupData) override;
+		void endRefresh(const ScriptObjectBackup& backupData) override;
 	protected:
 		bool mRefreshInProgress;
 	};

+ 21 - 9
Source/SBansheeEngine/Include/BsScriptGameObjectManager.h

@@ -7,6 +7,8 @@
 
 namespace bs
 {
+	class ScriptRenderable;
+
 	/** @addtogroup SBansheeEngine
 	 *  @{
 	 */
@@ -47,22 +49,32 @@ namespace bs
 		ScriptSceneObject* createScriptSceneObject(MonoObject* existingInstance, const HSceneObject& sceneObject);
 
 		/**
-		 * Connects an existing managed ManagedComponent instance with the native ManagedComponent by creating the interop
-		 * object. Throws an exception if the interop object already exists.
+		 * Connects an existing instance of a ManagedComponent instance with the native ManagedComponent class by creating
+		 * the interop object. Throws an exception if the interop object already exists.
+		 */
+		ScriptManagedComponent* createManagedScriptComponent(MonoObject* existingInstance, const HManagedComponent& component);
+
+		/**
+		 * Creates a new interop object that connects a built-in native component with a managed version of that component.
+		 */
+		ScriptComponentBase* createBuiltinScriptComponent(const HComponent& component);
+
+		/**
+		 * Attempts to find the interop object for the specified built-in component. If one cannot be found a new
+		 * script interop object is created.
 		 */
-		ScriptComponent* createScriptComponent(MonoObject* existingInstance, 
-			const GameObjectHandle<ManagedComponent>& component);
+		ScriptComponentBase* getBuiltinScriptComponent(const HComponent& component);
 
 		/**
 		 * Attempts to find the interop object for the specified managed component. If one cannot be found null is returned.
 		 */
-		ScriptComponent* getScriptComponent(const GameObjectHandle<ManagedComponent>& component) const;
+		ScriptManagedComponent* getManagedScriptComponent(const HManagedComponent& component) const;
 
 		/**
-		 * Attempts to find the interop object for a managed component with the specified instance ID. If one cannot be
+		 * Attempts to find the interop object for a component with the specified instance ID. If one cannot be
 		 * found null is returned.
 		 */
-		ScriptComponent* getScriptComponent(UINT64 instanceId) const;
+		ScriptComponentBase* getScriptComponent(UINT64 instanceId) const;
 
 		/** Attempts to find the interop object for the specified SceneObject. If one cannot be found null is returned. */
 		ScriptSceneObject* getScriptSceneObject(const HSceneObject& sceneObject) const;
@@ -83,7 +95,7 @@ namespace bs
 		void destroyScriptSceneObject(ScriptSceneObject* sceneObject);
 
 		/**	Destroys and unregisters the specified ManagedComponent interop object. */
-		void destroyScriptComponent(ScriptComponent* component);
+		void destroyScriptComponent(ScriptComponentBase* component);
 
 		/** 
 		 * Sends OnInitialize/OnEnable events to all components that run only while the game is playing (ones without 
@@ -102,7 +114,7 @@ namespace bs
 		/**	Triggered when the any game object is destroyed. */
 		void onGameObjectDestroyed(const HGameObject& go);
 
-		UnorderedMap<UINT64, ScriptComponent*> mScriptComponents;
+		UnorderedMap<UINT64, ScriptComponentBase*> mScriptComponents;
 		UnorderedMap<UINT64, ScriptSceneObject*> mScriptSceneObjects;
 
 		HEvent mOnAssemblyReloadDoneConn;

+ 59 - 0
Source/SBansheeEngine/Include/BsScriptManagedComponent.h

@@ -0,0 +1,59 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptComponent.h"
+#include "BsScriptObject.h"
+
+namespace bs
+{
+	/** @addtogroup ScriptInteropEngine
+	 *  @{
+	 */
+
+	/**	Interop class between C++ & CLR for ManagedComponent. */
+	class BS_SCR_BE_EXPORT ScriptManagedComponent : public ScriptObject<ScriptManagedComponent, ScriptComponentBase>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "ManagedComponent")
+
+		/**	Returns a generic handle to the internal wrapped component. */
+		HGameObject getNativeHandle() const override { return mComponent; }
+
+		/**	Sets the internal component this object wraps. */
+		void setNativeHandle(const HGameObject& gameObject) override { mComponent = static_object_cast<ManagedComponent>(gameObject); }
+
+		/**	Returns a handle to the internal wrapped component. */
+		const HManagedComponent& getHandle() const { return mComponent; }
+
+	private:
+		friend class ScriptGameObjectManager;
+
+		ScriptManagedComponent(MonoObject* instance);
+		
+		/** @copydoc ScriptObjectBase::beginRefresh */
+		ScriptObjectBackup beginRefresh() override;
+
+		/** @copydoc ScriptObjectBase::endRefresh */
+		void endRefresh(const ScriptObjectBackup& backupData) override;
+
+		/** @copydoc ScriptObjectBase::_createManagedInstance */
+		MonoObject* _createManagedInstance(bool construct) override;
+
+		/** @copydoc ScriptObjectBase::_onManagedInstanceDeleted */
+		void _onManagedInstanceDeleted() override;
+
+		HManagedComponent mComponent;
+		String mNamespace;
+		String mType;
+		bool mTypeMissing;
+
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static void internal_invoke(ScriptManagedComponent* nativeInstance, MonoString* name);
+	};
+
+	/** @} */
+}

+ 3 - 3
Source/SBansheeEngine/Include/BsScriptManagedResource.h

@@ -35,13 +35,13 @@ namespace bs
 		friend class ScriptResourceManager;
 
 		/** @copydoc ScriptObjectBase::beginRefresh */
-		virtual ScriptObjectBackup beginRefresh() override;
+		ScriptObjectBackup beginRefresh() override;
 
 		/** @copydoc ScriptObjectBase::endRefresh */
-		virtual void endRefresh(const ScriptObjectBackup& backupData) override;
+		void endRefresh(const ScriptObjectBackup& backupData) override;
 
 		/** @copydoc ScriptObjectBase::_createManagedInstance */
-		virtual MonoObject* _createManagedInstance(bool construct) override;
+		MonoObject* _createManagedInstance(bool construct) override;
 
 		/** @copydoc ScriptObjectBase::_onManagedInstanceDeleted */
 		void _onManagedInstanceDeleted() override;

+ 26 - 1
Source/SBansheeEngine/Include/BsScriptRenderable.h

@@ -3,7 +3,7 @@
 #pragma once
 
 #include "BsScriptEnginePrerequisites.h"
-#include "BsScriptObject.h"
+#include "BsScriptComponent.h"
 
 namespace bs
 {
@@ -54,5 +54,30 @@ namespace bs
 		static void internal_OnDestroy(ScriptRenderable* thisPtr);
 	};
 
+	/**	Interop class between C++ & CLR for Renderable. */
+	class BS_SCR_BE_EXPORT ScriptRenderable2 : public TScriptComponent <ScriptRenderable2, Renderable>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "Renderable2")
+
+		ScriptRenderable2(MonoObject* managedInstance, const HComponent& component);
+
+	private:
+		~ScriptRenderable2();
+
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static MonoObject* internal_GetMesh(ScriptRenderable2* thisPtr);
+		static void internal_SetMesh(ScriptRenderable2* thisPtr, ScriptMesh* mesh);
+		static void internal_GetBounds(ScriptRenderable2* thisPtr, AABox* box, Sphere* sphere);
+		static UINT64 internal_GetLayers(ScriptRenderable2* thisPtr);
+		static void internal_SetLayers(ScriptRenderable2* thisPtr, UINT64 layers);
+		static MonoObject* internal_GetMaterial(ScriptRenderable2* thisPtr, int index);
+		static void internal_SetMaterial(ScriptRenderable2* thisPtr, ScriptMaterial* material, int index);
+		static MonoArray* internal_GetMaterials(ScriptRenderable2* thisPtr);
+		static void internal_SetMaterials(ScriptRenderable2* thisPtr, MonoArray* materials);
+	};
+
 	/** @} */
 }

+ 2 - 2
Source/SBansheeEngine/Include/BsScriptResource.h

@@ -30,10 +30,10 @@ namespace bs
 		virtual void setResource(const HResource& resource) = 0;
 
 		/** @copydoc ScriptObjectBase::beginRefresh */
-		virtual ScriptObjectBackup beginRefresh() override;
+		ScriptObjectBackup beginRefresh() override;
 
 		/** @copydoc ScriptObjectBase::endRefresh */
-		virtual void endRefresh(const ScriptObjectBackup& backupData) override;
+		void endRefresh(const ScriptObjectBackup& backupData) override;
 
 	protected:
 		friend class ScriptResourceManager;

+ 3 - 2
Source/SBansheeEngine/Source/BsManagedComponent.cpp

@@ -10,6 +10,7 @@
 #include "BsManagedSerializableObject.h"
 #include "BsScriptGameObjectManager.h"
 #include "BsScriptAssemblyManager.h"
+#include "BsScriptManagedComponent.h"
 #include "BsMonoAssembly.h"
 #include "BsPlayInEditorManager.h"
 
@@ -209,7 +210,7 @@ namespace bs
 
 			// Search for methods on base class if there is one
 			MonoClass* baseClass = mManagedClass->getBaseClass();
-			if (baseClass != ScriptComponent::getMetaData()->scriptClass)
+			if (baseClass != ScriptManagedComponent::getMetaData()->scriptClass)
 				mManagedClass = baseClass;
 			else
 				break;
@@ -358,7 +359,7 @@ namespace bs
 		}
 
 		assert(componentHandle != nullptr);
-		ScriptGameObjectManager::instance().createScriptComponent(mManagedInstance, componentHandle);
+		ScriptGameObjectManager::instance().createManagedScriptComponent(mManagedInstance, componentHandle);
 	}
 
 	void ManagedComponent::onInitialized()

+ 38 - 5
Source/SBansheeEngine/Source/BsManagedSerializableField.cpp

@@ -28,10 +28,12 @@
 #include "BsScriptAnimationClip.h"
 #include "BsScriptSceneObject.h"
 #include "BsScriptComponent.h"
+#include "BsScriptManagedComponent.h"
 #include "BsManagedSerializableObject.h"
 #include "BsManagedSerializableArray.h"
 #include "BsManagedSerializableList.h"
 #include "BsManagedSerializableDictionary.h"
+#include "BsScriptAssemblyManager.h"
 
 namespace bs
 {
@@ -185,7 +187,7 @@ namespace bs
 				{ &getScriptResource<AudioClip, ScriptAudioClip>, &setScriptResource<ScriptAudioClip> };
 
 			lookup[(int)ScriptReferenceType::AnimationClip] =
-			{ &getScriptResource<AnimationClip, ScriptAnimationClip>, &setScriptResource<ScriptAnimationClip> };
+				{ &getScriptResource<AnimationClip, ScriptAnimationClip>, &setScriptResource<ScriptAnimationClip> };
 
 			lookup[(int)ScriptReferenceType::ManagedResource] =
 				{ &getScriptResource<ManagedResource, ScriptManagedResource>, &setScriptResource<ScriptManagedResource> };
@@ -336,19 +338,36 @@ namespace bs
 
 				return fieldData;
 			}
+			case ScriptReferenceType::ManagedComponentBase:
 			case ScriptReferenceType::ManagedComponent:
-			case ScriptReferenceType::Component:
 			{
 				auto fieldData = bs_shared_ptr_new<ManagedSerializableFieldDataGameObjectRef>();
 
 				if (value != nullptr)
 				{
-					ScriptComponent* scriptComponent = ScriptComponent::toNative(value);
+					ScriptManagedComponent* scriptComponent = ScriptManagedComponent::toNative(value);
 					fieldData->value = static_object_cast<Component>(scriptComponent->getNativeHandle());
 				}
 
 				return fieldData;
 			}
+			case ScriptReferenceType::BuiltinComponentBase:
+			case ScriptReferenceType::BuiltinComponent:
+			{
+				BuiltinComponentInfo* info = ScriptAssemblyManager::instance().getBuiltinComponentInfo(refTypeInfo->mRTIITypeId);
+				if (info == nullptr)
+					return nullptr;
+
+				auto fieldData = bs_shared_ptr_new<ManagedSerializableFieldDataGameObjectRef>();
+
+				if (value != nullptr)
+				{
+					ScriptComponentBase* scriptComponent = ScriptComponent::toNative(value);
+					fieldData->value = scriptComponent->getComponent();
+				}
+
+				return fieldData;
+			}
 			default:
 				// Must be a resource
 				return getResourceFieldLookup()[(int)refTypeInfo->mType].setter(value);
@@ -610,11 +629,25 @@ namespace bs
 				else
 					return nullptr;
 			}
-			else if(refTypeInfo->mType == ScriptReferenceType::Component || refTypeInfo->mType == ScriptReferenceType::ManagedComponent)
+			else if(refTypeInfo->mType == ScriptReferenceType::ManagedComponentBase || 
+					refTypeInfo->mType == ScriptReferenceType::ManagedComponent)
+			{
+				if (value)
+				{
+					ScriptManagedComponent* scriptComponent = ScriptGameObjectManager::instance().getManagedScriptComponent(value);
+					assert(scriptComponent != nullptr);
+
+					return scriptComponent->getManagedInstance();
+				}
+				else
+					return nullptr;
+			}
+			else if (refTypeInfo->mType == ScriptReferenceType::BuiltinComponentBase || 
+					 refTypeInfo->mType == ScriptReferenceType::BuiltinComponent)
 			{
 				if (value)
 				{
-					ScriptComponent* scriptComponent = ScriptGameObjectManager::instance().getScriptComponent(value);
+					ScriptComponentBase* scriptComponent = ScriptGameObjectManager::instance().getBuiltinScriptComponent(value);
 					assert(scriptComponent != nullptr);
 
 					return scriptComponent->getManagedInstance();

+ 6 - 2
Source/SBansheeEngine/Source/BsManagedSerializableObjectInfo.cpp

@@ -393,7 +393,9 @@ namespace bs
 		case ScriptReferenceType::AudioClip:
 		case ScriptReferenceType::AnimationClip:
 		case ScriptReferenceType::SceneObject:
-		case ScriptReferenceType::Component:
+		case ScriptReferenceType::BuiltinComponentBase:
+		case ScriptReferenceType::ManagedComponentBase:
+		case ScriptReferenceType::BuiltinComponent:
 			return true;
 		default:
 			break;
@@ -446,8 +448,10 @@ namespace bs
 			return ScriptAnimationClip::getMetaData()->scriptClass->_getInternalClass();
 		case ScriptReferenceType::SceneObject:
 			return ScriptAssemblyManager::instance().getSceneObjectClass()->_getInternalClass();
-		case ScriptReferenceType::Component:
+		case ScriptReferenceType::BuiltinComponentBase:
 			return ScriptAssemblyManager::instance().getComponentClass()->_getInternalClass();
+		case ScriptReferenceType::ManagedComponentBase:
+			return ScriptAssemblyManager::instance().getManagedComponentClass()->_getInternalClass();
 		default:
 			break;
 		}

+ 76 - 7
Source/SBansheeEngine/Source/BsScriptAssemblyManager.cpp

@@ -9,6 +9,7 @@
 #include "BsMonoMethod.h"
 #include "BsMonoProperty.h"
 #include "BsScriptManagedResource.h"
+#include "BsScriptComponent.h"
 #include "BsScriptTexture2D.h"
 #include "BsScriptTexture3D.h"
 #include "BsScriptTextureCube.h"
@@ -27,15 +28,17 @@
 #include "BsScriptAudioClip.h"
 #include "BsScriptPrefab.h"
 #include "BsScriptAnimationClip.h"
+#include "BsBuiltinComponentLookup.h"
 
 namespace bs
 {
 	ScriptAssemblyManager::ScriptAssemblyManager()
 		: mBaseTypesInitialized(false), mSystemArrayClass(nullptr), mSystemGenericListClass(nullptr)
 		, mSystemGenericDictionaryClass(nullptr), mSystemTypeClass(nullptr), mComponentClass(nullptr)
-		, mSceneObjectClass(nullptr), mMissingComponentClass(nullptr), mSerializeObjectAttribute(nullptr)
-		, mDontSerializeFieldAttribute(nullptr), mSerializeFieldAttribute(nullptr), mHideInInspectorAttribute(nullptr)
-		, mShowInInspectorAttribute(nullptr), mRangeAttribute(nullptr), mStepAttribute(nullptr)
+		, mManagedComponentClass(nullptr), mSceneObjectClass(nullptr), mMissingComponentClass(nullptr)
+		, mSerializeObjectAttribute(nullptr), mDontSerializeFieldAttribute(nullptr), mSerializeFieldAttribute(nullptr)
+		, mHideInInspectorAttribute(nullptr), mShowInInspectorAttribute(nullptr), mRangeAttribute(nullptr)
+		, mStepAttribute(nullptr)
 	{
 
 	}
@@ -59,6 +62,8 @@ namespace bs
 		if(!mBaseTypesInitialized)
 			initializeBaseTypes();
 
+		initializeBuiltinComponentInfos();
+
 		// Process all classes and fields
 		UINT32 mUniqueTypeId = 1;
 
@@ -77,8 +82,9 @@ namespace bs
 		const Vector<MonoClass*>& allClasses = curAssembly->getAllClasses();
 		for(auto& curClass : allClasses)
 		{
-			if ((curClass->isSubClassOf(mComponentClass) || curClass->isSubClassOf(managedResourceClass) ||
-				curClass->hasAttribute(mSerializeObjectAttribute)) && curClass != mComponentClass && curClass != managedResourceClass)
+			if ((curClass->isSubClassOf(mManagedComponentClass) || curClass->isSubClassOf(managedResourceClass) ||
+				curClass->hasAttribute(mSerializeObjectAttribute)) && curClass != mManagedComponentClass && 
+				curClass != managedResourceClass)
 			{
 				SPtr<ManagedSerializableTypeInfoObject> typeInfo = bs_shared_ptr_new<ManagedSerializableTypeInfoObject>();
 				typeInfo->mTypeNamespace = curClass->getNamespace();
@@ -372,13 +378,30 @@ namespace bs
 				SPtr<ManagedSerializableTypeInfoRef> typeInfo = bs_shared_ptr_new<ManagedSerializableTypeInfoRef>();
 				typeInfo->mTypeNamespace = monoClass->getNamespace();
 				typeInfo->mTypeName = monoClass->getTypeName();
+				typeInfo->mRTIITypeId = 0;
 
 				if (monoClass == mComponentClass)
-					typeInfo->mType = ScriptReferenceType::Component;
+					typeInfo->mType = ScriptReferenceType::BuiltinComponentBase;
+				else if (monoClass == mManagedComponentClass)
+					typeInfo->mType = ScriptReferenceType::ManagedComponentBase;
 				else if (monoClass->isSubClassOf(mSceneObjectClass))
 					typeInfo->mType = ScriptReferenceType::SceneObject;
-				else if (monoClass->isSubClassOf(mComponentClass))
+				else if (monoClass->isSubClassOf(mManagedComponentClass))
 					typeInfo->mType = ScriptReferenceType::ManagedComponent;
+				else if (monoClass->isSubClassOf(mComponentClass))
+				{
+					typeInfo->mType = ScriptReferenceType::BuiltinComponent;
+
+					::MonoReflectionType* type = MonoUtil::getType(monoClass->_getInternalClass());
+					BuiltinComponentInfo* builtinInfo = getBuiltinComponentInfo(type);
+					if(builtinInfo == nullptr)
+					{
+						assert(false && "Unable to find information about a built-in component. Did you update BuiltinComponents list?");
+						return nullptr;
+					}
+
+					typeInfo->mRTIITypeId = builtinInfo->typeId;
+				}
 
 				return typeInfo;
 			}
@@ -480,6 +503,7 @@ namespace bs
 		mDontSerializeFieldAttribute = nullptr;
 
 		mComponentClass = nullptr;
+		mManagedComponentClass = nullptr;
 		mSceneObjectClass = nullptr;
 		mMissingComponentClass = nullptr;
 
@@ -537,6 +561,10 @@ namespace bs
 		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.");
@@ -560,6 +588,47 @@ namespace bs
 		mBaseTypesInitialized = true;
 	}
 
+	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;
+		}
+	}
+
+	BuiltinComponentInfo* ScriptAssemblyManager::getBuiltinComponentInfo(::MonoReflectionType* type)
+	{
+		auto iterFind = mBuiltinComponentInfos.find(type);
+		if (iterFind == mBuiltinComponentInfos.end())
+			return nullptr;
+
+		return &(iterFind->second);
+	}
+
+	BuiltinComponentInfo* ScriptAssemblyManager::getBuiltinComponentInfo(UINT32 rttiTypeId)
+	{
+		auto iterFind = mBuiltinComponentInfosByTID.find(rttiTypeId);
+		if (iterFind == mBuiltinComponentInfosByTID.end())
+			return nullptr;
+
+		return &(iterFind->second);
+	}
+
 	bool ScriptAssemblyManager::getSerializableObjectInfo(const String& ns, const String& typeName, SPtr<ManagedSerializableObjectInfo>& outInfo)
 	{
 		String fullName = ns + "." + typeName;

+ 89 - 118
Source/SBansheeEngine/Source/BsScriptComponent.cpp

@@ -11,18 +11,45 @@
 #include "BsMonoManager.h"
 #include "BsMonoUtil.h"
 #include "BsScriptSceneObject.h"
+#include "BsScriptAssemblyManager.h"
 #include "BsManagedComponent.h"
 #include "BsSceneObject.h"
 #include "BsMonoUtil.h"
+#include "BsBuiltinComponentLookup.h"
 
 namespace bs
 {
+	ScriptComponentBase::ScriptComponentBase(MonoObject* instance)
+		:ScriptGameObjectBase(instance)
+	{ }
+
+	void ScriptComponentBase::destroy()
+	{
+		mManagedInstance = nullptr;
+
+		// It's possible that managed component is destroyed but a reference to it is still kept during assembly refresh. 
+		// Such components shouldn't be restored so we delete them.
+
+		HComponent component = getComponent();
+		if (!mRefreshInProgress || component.isDestroyed(true))
+			ScriptGameObjectManager::instance().destroyScriptComponent(this);
+	}
+
+	bool ScriptComponentBase::checkIfDestroyed(const GameObjectHandleBase& handle)
+	{
+		if (handle.isDestroyed())
+		{
+			LOGWRN("Trying to access a destroyed GameObject with instance ID: " + toString(handle.getInstanceId()));
+			return true;
+		}
+
+		return false;
+	}
+
 	ScriptComponent::ScriptComponent(MonoObject* instance)
-		:ScriptObject(instance), mTypeMissing(false)
+		:ScriptObject(instance)
 	{ 
 		assert(instance != nullptr);
-
-		MonoUtil::getClassName(instance, mNamespace, mType);
 	}
 
 	void ScriptComponent::initRuntimeData()
@@ -35,7 +62,6 @@ namespace bs
 		metaData.scriptClass->addInternalCall("Internal_GetSceneObject", &ScriptComponent::internal_getSceneObject);
 		metaData.scriptClass->addInternalCall("Internal_GetNotifyFlags", &ScriptComponent::internal_getNotifyFlags);
 		metaData.scriptClass->addInternalCall("Internal_SetNotifyFlags", &ScriptComponent::internal_setNotifyFlags);
-		metaData.scriptClass->addInternalCall("Internal_Invoke", &ScriptComponent::internal_invoke);
 		metaData.scriptClass->addInternalCall("Internal_Destroy", &ScriptComponent::internal_destroy);
 	}
 
@@ -47,8 +73,29 @@ namespace bs
 		if (checkIfDestroyed(so))
 			return nullptr;
 
-		GameObjectHandle<ManagedComponent> mc = so->addComponent<ManagedComponent>(type);
-		return mc->getManagedInstance();
+		ScriptAssemblyManager& sam = ScriptAssemblyManager::instance();
+
+		MonoClass* managedComponent = sam.getManagedComponentClass();
+		::MonoClass* requestedClass = MonoUtil::getClass(type);
+
+		bool isManagedComponent = MonoUtil::isSubClassOf(requestedClass, managedComponent->_getInternalClass());
+		if(isManagedComponent)
+		{
+			GameObjectHandle<ManagedComponent> mc = so->addComponent<ManagedComponent>(type);
+			return mc->getManagedInstance();
+		}
+		else
+		{
+			BuiltinComponentInfo* info = sam.getBuiltinComponentInfo(type);
+			if (info == nullptr)
+				return nullptr;
+
+			HComponent component = so->addComponent(info->typeId);
+			ScriptComponentBase* scriptComponent = 
+				ScriptGameObjectManager::instance().createBuiltinScriptComponent(component);
+
+			return scriptComponent->getManagedInstance();
+		}
 	}
 
 	MonoObject* ScriptComponent::internal_getComponent(MonoObject* parentSceneObject, MonoReflectionType* type)
@@ -76,6 +123,11 @@ namespace bs
 					return managedComponent->getManagedInstance();
 				}
 			}
+			else
+			{
+				ScriptComponentBase* scriptComponent = ScriptGameObjectManager::instance().getBuiltinScriptComponent(component);
+				return scriptComponent->getManagedInstance();
+			}
 		}
 
 		return nullptr;
@@ -104,6 +156,11 @@ namespace bs
 					if (MonoUtil::isSubClassOf(componentClass, baseClass))
 						managedComponents.push_back(managedComponent->getManagedInstance());
 				}
+				else
+				{
+					ScriptComponentBase* scriptComponent = ScriptGameObjectManager::instance().getBuiltinScriptComponent(component);
+					managedComponents.push_back(scriptComponent->getManagedInstance());
+				}
 			}
 		}
 
@@ -132,6 +189,11 @@ namespace bs
 
 					managedComponents.push_back(managedComponent->getManagedInstance());
 				}
+				else
+				{
+					ScriptComponentBase* scriptComponent = ScriptGameObjectManager::instance().getBuiltinScriptComponent(component);
+					managedComponents.push_back(scriptComponent->getManagedInstance());
+				}
 			}
 		}
 
@@ -155,7 +217,7 @@ namespace bs
 		const Vector<HComponent>& mComponents = so->getComponents();
 		for(auto& component : mComponents)
 		{
-			if(component->getTypeId() == TID_ManagedComponent)
+			if (component->getTypeId() == TID_ManagedComponent)
 			{
 				GameObjectHandle<ManagedComponent> managedComponent = static_object_cast<ManagedComponent>(component);
 
@@ -168,17 +230,20 @@ namespace bs
 					return;
 				}
 			}
+			else
+				component->destroy();
 		}
 
 		LOGWRN("Attempting to remove a component that doesn't exists on SceneObject \"" + so->getName() + "\"");
 	}
 
-	MonoObject* ScriptComponent::internal_getSceneObject(ScriptComponent* nativeInstance)
+	MonoObject* ScriptComponent::internal_getSceneObject(ScriptComponentBase* nativeInstance)
 	{
-		if (checkIfDestroyed(nativeInstance->mManagedComponent))
+		HComponent component = nativeInstance->getComponent();
+		if (checkIfDestroyed(component))
 			return nullptr;
 
-		HSceneObject sceneObject = nativeInstance->mManagedComponent->sceneObject();
+		HSceneObject sceneObject = component->sceneObject();
 
 		ScriptSceneObject* scriptSO = ScriptGameObjectManager::instance().getOrCreateScriptSceneObject(sceneObject);
 
@@ -186,123 +251,29 @@ namespace bs
 		return scriptSO->getManagedInstance();
 	}
 
-	TransformChangedFlags ScriptComponent::internal_getNotifyFlags(ScriptComponent* nativeInstance)
-	{
-		if (!checkIfDestroyed(nativeInstance->mManagedComponent))
-			return nativeInstance->mManagedComponent->mNotifyFlags;
-
-		return TCF_None;
-	}
-
-	void ScriptComponent::internal_setNotifyFlags(ScriptComponent* nativeInstance, TransformChangedFlags flags)
-	{
-		if (!checkIfDestroyed(nativeInstance->mManagedComponent))
-			nativeInstance->mManagedComponent->mNotifyFlags = flags;
-	}
-
-	void ScriptComponent::internal_invoke(ScriptComponent* nativeInstance, MonoString* name)
-	{
-		HManagedComponent comp = nativeInstance->mManagedComponent;
-		if (checkIfDestroyed(nativeInstance->mManagedComponent))
-			return;
-
-		MonoObject* compObj = comp->getManagedInstance();
-		MonoClass* compClass = comp->getClass();
-
-		bool found = false;
-		String methodName = MonoUtil::monoToString(name);
-		while (compClass != nullptr)
-		{
-			MonoMethod* method = compClass->getMethod(methodName);
-			if (method != nullptr)
-			{
-				method->invoke(compObj, nullptr);
-				found = true;
-				break;
-			}
-
-			// Search for methods on base class if there is one
-			MonoClass* baseClass = compClass->getBaseClass();
-			if (baseClass != metaData.scriptClass)
-				compClass = baseClass;
-			else
-				break;
-		}
-
-		if (!found)
-		{
-			LOGWRN("Method invoke failed. Cannot find method \"" + methodName + "\" on component of type \"" + 
-				compClass->getTypeName() + "\".");
-		}
-	}
-
-	void ScriptComponent::internal_destroy(ScriptComponent* nativeInstance, bool immediate)
-	{
-		if (!checkIfDestroyed(nativeInstance->mManagedComponent))
-			nativeInstance->mManagedComponent->destroy(immediate);
-	}
-
-	bool ScriptComponent::checkIfDestroyed(const GameObjectHandleBase& handle)
-	{
-		if (handle.isDestroyed())
-		{
-			LOGWRN("Trying to access a destroyed GameObject with instance ID: " + toString(handle.getInstanceId()));
-			return true;
-		}
-
-		return false;
-	}
-
-	MonoObject* ScriptComponent::_createManagedInstance(bool construct)
-	{
-		SPtr<ManagedSerializableObjectInfo> currentObjInfo = nullptr;
-
-		// See if this type even still exists
-		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mType, currentObjInfo))
-		{
-			mTypeMissing = true;
-			return ScriptAssemblyManager::instance().getMissingComponentClass()->createInstance(true);
-		}
-
-		mTypeMissing = false;
-		return currentObjInfo->mMonoClass->createInstance(construct);
-	}
-
-	ScriptObjectBackup ScriptComponent::beginRefresh()
+	TransformChangedFlags ScriptComponent::internal_getNotifyFlags(ScriptComponentBase* nativeInstance)
 	{
-		ScriptGameObjectBase::beginRefresh();
+		HComponent component = nativeInstance->getComponent();
 
-		ScriptObjectBackup backupData;
+		if (!checkIfDestroyed(component))
+			return component->_getNotifyFlags();
 
-		// It's possible that managed component is destroyed but a reference to it
-		// is still kept. Don't backup such components.
-		if (!mManagedComponent.isDestroyed(true))
-			backupData.data = mManagedComponent->backup(true);
-
-		return backupData;
+		return TCF_None;
 	}
 
-	void ScriptComponent::endRefresh(const ScriptObjectBackup& backupData)
+	void ScriptComponent::internal_setNotifyFlags(ScriptComponentBase* nativeInstance, TransformChangedFlags flags)
 	{
-		ComponentBackupData componentBackup = any_cast<ComponentBackupData>(backupData.data);
-		mManagedComponent->restore(mManagedInstance, componentBackup, mTypeMissing);
+		HComponent component = nativeInstance->getComponent();
 
-		ScriptGameObjectBase::endRefresh(backupData);
+		if (!checkIfDestroyed(component))
+			component->_setNotifyFlags(flags);
 	}
-
-	void ScriptComponent::_onManagedInstanceDeleted()
+	
+	void ScriptComponent::internal_destroy(ScriptComponentBase* nativeInstance, bool immediate)
 	{
-		mManagedInstance = nullptr;
+		HComponent component = nativeInstance->getComponent();
 
-		// It's possible that managed component is destroyed but a reference to it
-		// is still kept during assembly refresh. Such components shouldn't be restored
-		// so we delete them.
-		if (!mRefreshInProgress || mManagedComponent.isDestroyed(true))
-			ScriptGameObjectManager::instance().destroyScriptComponent(this);
-	}
-
-	void ScriptComponent::setNativeHandle(const HGameObject& gameObject)
-	{
-		mManagedComponent = static_object_cast<ManagedComponent>(gameObject);
+		if (!checkIfDestroyed(component))
+			component->destroy(immediate);
 	}
 }

+ 67 - 22
Source/SBansheeEngine/Source/BsScriptGameObjectManager.cpp

@@ -3,6 +3,7 @@
 #include "BsScriptGameObjectManager.h"
 #include "BsScriptGameObject.h"
 #include "BsScriptComponent.h"
+#include "BsScriptManagedComponent.h"
 #include "BsScriptSceneObject.h"
 #include "BsGameObjectManager.h"
 #include "BsGameObject.h"
@@ -14,6 +15,7 @@
 #include "BsMonoClass.h"
 #include "BsScriptAssemblyManager.h"
 #include "BsScriptObjectManager.h"
+#include "BsBuiltinComponentLookup.h"
 
 using namespace std::placeholders;
 
@@ -72,9 +74,10 @@ namespace bs
 		return nativeInstance;
 	}
 
-	ScriptComponent* ScriptGameObjectManager::createScriptComponent(MonoObject* existingInstance, const GameObjectHandle<ManagedComponent>& component)
+	ScriptManagedComponent* ScriptGameObjectManager::createManagedScriptComponent(MonoObject* existingInstance,
+																				  const HManagedComponent& component)
 	{
-		ScriptComponent* nativeInstance = new (bs_alloc<ScriptComponent>()) ScriptComponent(existingInstance);
+		ScriptManagedComponent* nativeInstance = new (bs_alloc<ScriptManagedComponent>()) ScriptManagedComponent(existingInstance);
 		nativeInstance->setNativeHandle(component);
 
 		UINT64 instanceId = component->getInstanceId();
@@ -83,16 +86,42 @@ namespace bs
 		return nativeInstance;
 	}
 
-	ScriptComponent* ScriptGameObjectManager::getScriptComponent(const GameObjectHandle<ManagedComponent>& component) const
+	ScriptComponentBase* ScriptGameObjectManager::createBuiltinScriptComponent(const HComponent& component)
+	{
+		UINT32 rttiId = component->getRTTI()->getRTTIId();
+		BuiltinComponentInfo* info = ScriptAssemblyManager::instance().getBuiltinComponentInfo(rttiId);
+
+		if (info == nullptr)
+			return nullptr;
+
+		ScriptComponentBase* nativeInstance = info->createCallback(component);
+		nativeInstance->setNativeHandle(component);
+
+		UINT64 instanceId = component->getInstanceId();
+		mScriptComponents[instanceId] = nativeInstance;
+
+		return nativeInstance;
+	}
+
+	ScriptComponentBase* ScriptGameObjectManager::getBuiltinScriptComponent(const HComponent& component)
+	{
+		ScriptComponentBase* scriptComponent = getScriptComponent(component.getInstanceId());
+		if (scriptComponent != nullptr)
+			return scriptComponent;
+
+		return createBuiltinScriptComponent(component);
+	}
+
+	ScriptManagedComponent* ScriptGameObjectManager::getManagedScriptComponent(const HManagedComponent& component) const
 	{
 		auto findIter = mScriptComponents.find(component.getInstanceId());
 		if (findIter != mScriptComponents.end())
-			return findIter->second;
+			return static_cast<ScriptManagedComponent*>(findIter->second);
 
 		return nullptr;
 	}
 
-	ScriptComponent* ScriptGameObjectManager::getScriptComponent(UINT64 instanceId) const
+	ScriptComponentBase* ScriptGameObjectManager::getScriptComponent(UINT64 instanceId) const
 	{
 		auto findIter = mScriptComponents.find(instanceId);
 		if (findIter != mScriptComponents.end())
@@ -140,7 +169,7 @@ namespace bs
 		bs_delete(sceneObject);
 	}
 
-	void ScriptGameObjectManager::destroyScriptComponent(ScriptComponent* component)
+	void ScriptGameObjectManager::destroyScriptComponent(ScriptComponentBase* component)
 	{
 		UINT64 instanceId = component->getNativeHandle().getInstanceId();
 		mScriptComponents.erase(instanceId);
@@ -152,11 +181,15 @@ namespace bs
 	{
 		for (auto& scriptObjectEntry : mScriptComponents)
 		{
-			ScriptComponent* scriptComponent = scriptObjectEntry.second;
-			HManagedComponent component = scriptComponent->getNativeHandle();
-
-			if (!component.isDestroyed())
-				component->triggerOnReset();
+			ScriptComponentBase* scriptComponent = scriptObjectEntry.second;
+			HComponent component = scriptComponent->getComponent();
+
+			if (component->getRTTI()->getRTTIId() == TID_ManagedComponent)
+			{
+				HManagedComponent managedComponent = static_object_cast<ManagedComponent>(component);
+				if (!managedComponent.isDestroyed())
+					managedComponent->triggerOnReset();
+			}
 		}
 	}
 
@@ -164,16 +197,21 @@ namespace bs
 	{
 		for (auto& scriptObjectEntry : mScriptComponents)
 		{
-			ScriptComponent* scriptComponent = scriptObjectEntry.second;
-			HManagedComponent component = scriptComponent->getNativeHandle();
+			ScriptComponentBase* scriptComponent = scriptObjectEntry.second;
+			HComponent component = scriptComponent->getNativeHandle();
+
+			if (component->getRTTI()->getRTTIId() == TID_ManagedComponent)
+			{
+				HManagedComponent managedComponent = static_object_cast<ManagedComponent>(component);
 
-			if (component.isDestroyed() || component->runInEditor())
-				continue;
+				if (managedComponent.isDestroyed() || managedComponent->runInEditor())
+					continue;
 
-			component->triggerOnInitialize();
+				managedComponent->triggerOnInitialize();
 
-			if(component->SO()->getActive())
-				component->triggerOnEnable();
+				if (component->SO()->getActive())
+					managedComponent->triggerOnEnable();
+			}
 		}
 	}
 
@@ -182,10 +220,17 @@ namespace bs
 		UINT64 instanceId = go.getInstanceId();
 
 		ScriptSceneObject* so = getScriptSceneObject(instanceId);
-		if (so == nullptr)
-			return;
+		if (so != nullptr)
+		{
+			so->_notifyDestroyed();
+			mScriptSceneObjects.erase(instanceId);
+		}
 
-		so->_notifyDestroyed();
-		mScriptSceneObjects.erase(instanceId);
+		ScriptComponentBase* component = getScriptComponent(instanceId);
+		if(component != nullptr)
+		{
+			component->_notifyDestroyed();
+			mScriptComponents.erase(instanceId);
+		}
 	}
 }

+ 120 - 0
Source/SBansheeEngine/Source/BsScriptManagedComponent.cpp

@@ -0,0 +1,120 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsScriptManagedComponent.h"
+#include "BsScriptGameObjectManager.h"
+#include "BsScriptObjectManager.h"
+#include "BsScriptAssemblyManager.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoMethod.h"
+#include "BsMonoManager.h"
+#include "BsMonoUtil.h"
+#include "BsScriptSceneObject.h"
+#include "BsScriptAssemblyManager.h"
+#include "BsManagedComponent.h"
+#include "BsSceneObject.h"
+#include "BsMonoUtil.h"
+
+namespace bs
+{
+	ScriptManagedComponent::ScriptManagedComponent(MonoObject* instance)
+		:ScriptObject(instance), mTypeMissing(false)
+	{
+		assert(instance != nullptr);
+
+		MonoUtil::getClassName(instance, mNamespace, mType);
+	}
+
+	void ScriptManagedComponent::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_Invoke", &ScriptManagedComponent::internal_invoke);
+	}
+
+	void ScriptManagedComponent::internal_invoke(ScriptManagedComponent* nativeInstance, MonoString* name)
+	{
+		HManagedComponent comp = nativeInstance->mComponent;
+		if (checkIfDestroyed(nativeInstance->mComponent))
+			return;
+
+		MonoObject* compObj = comp->getManagedInstance();
+		MonoClass* compClass = comp->getClass();
+
+		bool found = false;
+		String methodName = MonoUtil::monoToString(name);
+		while (compClass != nullptr)
+		{
+			MonoMethod* method = compClass->getMethod(methodName);
+			if (method != nullptr)
+			{
+				method->invoke(compObj, nullptr);
+				found = true;
+				break;
+			}
+
+			// Search for methods on base class if there is one
+			MonoClass* baseClass = compClass->getBaseClass();
+			if (baseClass != metaData.scriptClass)
+				compClass = baseClass;
+			else
+				break;
+		}
+
+		if (!found)
+		{
+			LOGWRN("Method invoke failed. Cannot find method \"" + methodName + "\" on component of type \"" +
+				   compClass->getTypeName() + "\".");
+		}
+	}
+
+	MonoObject* ScriptManagedComponent::_createManagedInstance(bool construct)
+	{
+		SPtr<ManagedSerializableObjectInfo> currentObjInfo = nullptr;
+
+		// See if this type even still exists
+		if (!ScriptAssemblyManager::instance().getSerializableObjectInfo(mNamespace, mType, currentObjInfo))
+		{
+			mTypeMissing = true;
+			return ScriptAssemblyManager::instance().getMissingComponentClass()->createInstance(true);
+		}
+
+		mTypeMissing = false;
+		return currentObjInfo->mMonoClass->createInstance(construct);
+	}
+
+	ScriptObjectBackup ScriptManagedComponent::beginRefresh()
+	{
+		ScriptGameObjectBase::beginRefresh();
+
+		HManagedComponent managedComponent = static_object_cast<ManagedComponent>(mComponent);
+		ScriptObjectBackup backupData;
+
+		// It's possible that managed component is destroyed but a reference to it
+		// is still kept. Don't backup such components.
+		if (!managedComponent.isDestroyed(true))
+			backupData.data = managedComponent->backup(true);
+
+		return backupData;
+	}
+
+	void ScriptManagedComponent::endRefresh(const ScriptObjectBackup& backupData)
+	{
+		HManagedComponent managedComponent = static_object_cast<ManagedComponent>(mComponent);
+
+		ComponentBackupData componentBackup = any_cast<ComponentBackupData>(backupData.data);
+		managedComponent->restore(mManagedInstance, componentBackup, mTypeMissing);
+
+		ScriptGameObjectBase::endRefresh(backupData);
+	}
+
+	void ScriptManagedComponent::_onManagedInstanceDeleted()
+	{
+		mManagedInstance = nullptr;
+
+		// It's possible that managed component is destroyed but a reference to it
+		// is still kept during assembly refresh. Such components shouldn't be restored
+		// so we delete them.
+		if (!mRefreshInProgress || mComponent.isDestroyed(true))
+			ScriptGameObjectManager::instance().destroyScriptComponent(this);
+	}
+}

+ 135 - 1
Source/SBansheeEngine/Source/BsScriptRenderable.cpp

@@ -7,13 +7,14 @@
 #include "BsMonoManager.h"
 #include "BsMonoUtil.h"
 #include "BsApplication.h"
-#include "BsRenderable.h"
+#include "BsCRenderable.h"
 #include "BsScriptSceneObject.h"
 #include "BsSceneObject.h"
 #include "BsSceneManager.h"
 #include "BsScriptMesh.h"
 #include "BsScriptAnimation.h"
 #include "BsScriptMaterial.h"
+#include "BsScriptResourceManager.h"
 
 namespace bs
 {
@@ -169,4 +170,137 @@ namespace bs
 
 		ScriptObject::_onManagedInstanceDeleted();
 	}
+
+	ScriptRenderable2::ScriptRenderable2(MonoObject* managedInstance, const HComponent& component)
+		:TScriptComponent <ScriptRenderable2, Renderable>(managedInstance, component)
+	{ }
+
+	ScriptRenderable2::~ScriptRenderable2()
+	{ }
+
+	void ScriptRenderable2::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_GetMesh", &ScriptRenderable2::internal_GetMesh);
+		metaData.scriptClass->addInternalCall("Internal_SetMesh", &ScriptRenderable2::internal_SetMesh);
+		metaData.scriptClass->addInternalCall("Internal_GetBounds", &ScriptRenderable2::internal_GetBounds);
+		metaData.scriptClass->addInternalCall("Internal_GetLayers", &ScriptRenderable2::internal_GetLayers);
+		metaData.scriptClass->addInternalCall("Internal_SetLayers", &ScriptRenderable2::internal_SetLayers);
+		metaData.scriptClass->addInternalCall("Internal_GetMaterial", &ScriptRenderable2::internal_GetMaterial);
+		metaData.scriptClass->addInternalCall("Internal_SetMaterial", &ScriptRenderable2::internal_SetMaterial);
+		metaData.scriptClass->addInternalCall("Internal_GetMaterials", &ScriptRenderable2::internal_GetMaterials);
+		metaData.scriptClass->addInternalCall("Internal_SetMaterials", &ScriptRenderable2::internal_SetMaterials);
+	}
+
+	MonoObject* ScriptRenderable2::internal_GetMesh(ScriptRenderable2* thisPtr)
+	{
+		HMesh mesh = thisPtr->getHandle()->getMesh();
+
+		if (!mesh.isLoaded(false))
+			return nullptr;
+
+		ScriptMesh* scriptMesh;
+		ScriptResourceManager::instance().getScriptResource(mesh, &scriptMesh, true);
+
+		return scriptMesh->getManagedInstance();
+	}
+
+	void ScriptRenderable2::internal_SetMesh(ScriptRenderable2* thisPtr, ScriptMesh* mesh)
+	{
+		HMesh nativeMesh;
+		if (mesh != nullptr)
+			nativeMesh = mesh->getHandle();
+
+		thisPtr->getHandle()->setMesh(nativeMesh);
+	}
+
+	void ScriptRenderable2::internal_GetBounds(ScriptRenderable2* thisPtr, AABox* box, Sphere* sphere)
+	{
+		Bounds bounds = thisPtr->getHandle()->getBounds();
+
+		*box = bounds.getBox();
+		*sphere = bounds.getSphere();
+	}
+
+	UINT64 ScriptRenderable2::internal_GetLayers(ScriptRenderable2* thisPtr)
+	{
+		return thisPtr->getHandle()->getLayer();
+	}
+
+	void ScriptRenderable2::internal_SetLayers(ScriptRenderable2* thisPtr, UINT64 layers)
+	{
+		thisPtr->getHandle()->setLayer(layers);
+	}
+
+	MonoObject* ScriptRenderable2::internal_GetMaterial(ScriptRenderable2* thisPtr, int index)
+	{
+		HMaterial material = thisPtr->getHandle()->getMaterial(index);
+		if (!material.isLoaded())
+			return nullptr;
+
+		ScriptMaterial* scriptMaterial;
+		ScriptResourceManager::instance().getScriptResource(material, &scriptMaterial, true);
+
+		return scriptMaterial->getManagedInstance();
+	}
+
+	void ScriptRenderable2::internal_SetMaterial(ScriptRenderable2* thisPtr, ScriptMaterial* material, int index)
+	{
+		HMaterial nativeMaterial;
+		if (material != nullptr)
+			nativeMaterial = material->getHandle();
+
+		thisPtr->getHandle()->setMaterial(index, nativeMaterial);
+	}
+
+	MonoArray* ScriptRenderable2::internal_GetMaterials(ScriptRenderable2* thisPtr)
+	{
+		HRenderable renderable = thisPtr->getHandle();
+
+		HMesh mesh = renderable->getMesh();
+		if (!mesh.isLoaded())
+			return ScriptArray::create<ScriptMaterial>(0).getInternal();
+
+		UINT32 numMaterials = mesh->getProperties().getNumSubMeshes();
+		ScriptArray output = ScriptArray::create<ScriptMaterial>(numMaterials);
+
+		for(UINT32 i = 0; i < numMaterials; i++)
+		{
+			HMaterial material = renderable->getMaterial(i);
+			if (!material.isLoaded())
+				output.set(i, nullptr);
+			else
+			{
+				ScriptMaterial* scriptMaterial;
+				ScriptResourceManager::instance().getScriptResource(material, &scriptMaterial, true);
+
+				output.set(i, scriptMaterial->getManagedInstance());
+			}
+		}
+
+		return output.getInternal();
+	}
+
+	void ScriptRenderable2::internal_SetMaterials(ScriptRenderable2* thisPtr, MonoArray* materials)
+	{
+		if (materials != nullptr)
+		{
+			ScriptArray scriptMaterials(materials);
+
+			Vector<HMaterial> nativeMaterials(scriptMaterials.size());
+			for (UINT32 i = 0; i < scriptMaterials.size(); i++)
+			{
+				MonoObject* monoMaterial = scriptMaterials.get<MonoObject*>(i);
+				ScriptMaterial* scriptMaterial = ScriptMaterial::toNative(monoMaterial);
+
+				if (scriptMaterial != nullptr)
+					nativeMaterials[i] = scriptMaterial->getHandle();
+			}
+
+			thisPtr->getHandle()->setMaterials(nativeMaterials);
+		}
+		else
+		{
+			thisPtr->getHandle()->setMaterials({});
+		}
+	}
 }