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

Added run in editor manager & attribute so user can pick which components run during play mode and which run always

BearishSun 10 лет назад
Родитель
Сommit
4dd0fa76ed

+ 3 - 7
MBansheeEditor/Scene/SceneCamera.cs

@@ -1,16 +1,12 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using BansheeEngine;
+using BansheeEngine;
 
 namespace BansheeEditor
 {
     /// <summary>
     /// Handles camera movement in the scene view.
     /// </summary>
-    public class SceneCamera : Component
+    [RunInEditor]
+    internal sealed class SceneCamera : Component
     {
         public const string MoveForwardBinding = "SceneForward";
 	    public const string MoveLeftBinding = "SceneLeft";

+ 2 - 1
MBansheeEngine/Camera.cs

@@ -11,7 +11,8 @@ namespace BansheeEngine
     /// in space, set options like aspect ratio and field or view and it outputs view and projection matrices required for 
     /// rendering.
     /// </summary>
-    public class Camera : Component
+    [RunInEditor]
+    public sealed class Camera : Component
     {
         private NativeCamera native;
 

+ 2 - 1
MBansheeEngine/Light.cs

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

+ 1 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -122,6 +122,7 @@
     <Compile Include="RenderTexture2D.cs" />
     <Compile Include="Resource.cs" />
     <Compile Include="Resources.cs" />
+    <Compile Include="RunInEditor.cs" />
     <Compile Include="Scene.cs" />
     <Compile Include="SceneObject.cs" />
     <Compile Include="ScriptCode.cs" />

+ 2 - 1
MBansheeEngine/ProfilerOverlay.cs

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

+ 2 - 1
MBansheeEngine/Renderable.cs

@@ -6,7 +6,8 @@ namespace BansheeEngine
     /// Renderable represents any visible object in the scene. It has a mesh, bounds and a set of materials. Renderer will 
     /// render any Renderable objects visible by a camera.
     /// </summary>
-    public class Renderable : Component
+    [RunInEditor]
+    public sealed class Renderable : Component
     {
         private NativeRenderable _native;
 

+ 14 - 0
MBansheeEngine/RunInEditor.cs

@@ -0,0 +1,14 @@
+using System;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Attribute that allows Component's code to be executed while game is not running in the editor. Normally the
+    /// initialize/update/destroy methods will not be running while the game is paused or not running, but this overrides
+    /// that behaviour.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Class)]
+    public sealed class RunInEditor : Attribute
+    {
+    }
+}

+ 2 - 2
SBansheeEditor/Source/BsScriptEditorUtility.cpp

@@ -64,9 +64,9 @@ namespace BansheeEngine
 
 		UINT32 numEntries = (UINT32)dependencies.size();
 		ScriptArray output = ScriptArray::create<ScriptResource>(numEntries);
-		for (int i = 0; i < numEntries; i++)
+		for (UINT32 i = 0; i < numEntries; i++)
 		{
-			ScriptResource* dependency;
+			ScriptResourceBase* dependency;
 			ScriptResourceManager::instance().getScriptResource(dependencies[i].resource, &dependency, true);
 
 			output.set(i, dependency->getManagedInstance());

+ 1 - 0
SBansheeEngine/Include/BsManagedComponent.h

@@ -98,6 +98,7 @@ namespace BansheeEngine
 		String mNamespace;
 		String mTypeName;
 		String mFullTypeName;
+		bool mRunInEditor;
 		bool mRequiresReset;
 
 		bool mMissingType;

+ 63 - 0
SBansheeEngine/Include/BsPlayInEditorManager.h

@@ -0,0 +1,63 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsModule.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	States the game in editor can be in.
+	 */
+	enum class PlayInEditorState
+	{
+		Stopped,
+		Playing,
+		Paused
+	};
+
+	/**
+	 * @brief	Handles functionality specific to running the game in editor.
+	 *
+	 * @note	Play-in-editor functionality is only available for managed code, but can be easily extended to 
+	 *			native code if needed (this would involve moving play in editor code into BansheeEngine library).
+	 */
+	class BS_SCR_BE_EXPORT PlayInEditorManager : public Module<PlayInEditorManager>
+	{
+	public:
+		PlayInEditorManager();
+
+		/**
+		 * @brief	Returns the current play state of the game.
+		 */
+		PlayInEditorState getState() const { return mState; }
+
+		/**
+		 * @brief	Updates the play state of the game, making the game stop or start running.
+		 */
+		void setState(PlayInEditorState state);
+
+		/**
+		 * @brief	Gets the number of seconds that have elapsed since the game was started. This time does not
+		 *			include time passed while the game is paused.
+		 */
+		float getPausableTime() const { return mPausableTime; }
+
+		/**
+		 * @brief	Runs the game for a single frame and then pauses it.
+		 */
+		void frameStep();
+
+		/**
+		 * @brief	Called once per frame.
+		 *
+		 * @note	Internal method.
+		 */
+		void update();
+
+	private:
+		PlayInEditorState mState;
+		bool mFrameStepActive;
+
+		float mPausableTime;
+	};
+}

+ 2 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -271,6 +271,7 @@
     <ClInclude Include="Include\BsManagedSerializableList.h" />
     <ClInclude Include="Include\BsManagedSerializableListRTTI.h" />
     <ClInclude Include="Include\BsManagedSerializableObject.h" />
+    <ClInclude Include="Include\BsPlayInEditorManager.h" />
     <ClInclude Include="Include\BsScriptAssemblyManager.h" />
     <ClInclude Include="Include\BsScriptAsyncOp.h" />
     <ClInclude Include="Include\BsScriptBoneWeight.h" />
@@ -368,6 +369,7 @@
     <ClCompile Include="Source\BsManagedResourceManager.cpp" />
     <ClCompile Include="Source\BsManagedResourceMetaData.cpp" />
     <ClCompile Include="Source\BsManagedSerializableDiff.cpp" />
+    <ClCompile Include="Source\BsPlayInEditorManager.cpp" />
     <ClCompile Include="Source\BsScriptAssemblyManager.cpp" />
     <ClCompile Include="Source\BsScriptAsyncOp.cpp" />
     <ClCompile Include="Source\BsScriptBoneWeight.cpp" />

+ 6 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -357,6 +357,9 @@
     <ClInclude Include="Include\BsScriptGUIContentImages.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsPlayInEditorManager.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -653,5 +656,8 @@
     <ClCompile Include="Source\BsScriptGUIContentImages.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsPlayInEditorManager.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 3 - 0
SBansheeEngine/Source/BsEngineScriptLibrary.cpp

@@ -13,6 +13,7 @@
 #include "BsApplication.h"
 #include "BsFileSystem.h"
 #include "BsScriptDebug.h"
+#include "BsPlayInEditorManager.h"
 
 namespace BansheeEngine
 {
@@ -28,6 +29,7 @@ namespace BansheeEngine
 		MonoManager::startUp();
 		MonoAssembly& bansheeEngineAssembly = MonoManager::instance().loadAssembly(engineAssemblyPath.toString(), ENGINE_ASSEMBLY);
 
+		PlayInEditorManager::startUp();
 		ScriptDebug::startUp();
 		GameResourceManager::startUp();
 		ScriptObjectManager::startUp();
@@ -98,5 +100,6 @@ namespace BansheeEngine
 		ScriptObjectManager::shutDown();
 		GameResourceManager::shutDown();
 		ScriptDebug::shutDown();
+		PlayInEditorManager::shutDown();
 	}
 }

+ 48 - 15
SBansheeEngine/Source/BsManagedComponent.cpp

@@ -8,6 +8,8 @@
 #include "BsManagedSerializableObject.h"
 #include "BsScriptGameObjectManager.h"
 #include "BsScriptAssemblyManager.h"
+#include "BsMonoAssembly.h"
+#include "BsPlayInEditorManager.h"
 #include "BsDebug.h"
 
 namespace BansheeEngine
@@ -15,13 +17,14 @@ namespace BansheeEngine
 	ManagedComponent::ManagedComponent()
 		:mManagedInstance(nullptr), mUpdateThunk(nullptr), mOnDestroyThunk(nullptr), mOnInitializedThunk(nullptr), 
 		mOnResetThunk(nullptr), mMissingType(false), mRequiresReset(true), mOnEnabledThunk(nullptr), mOnDisabledThunk(nullptr),
-		mCalculateBoundsMethod(nullptr)
+		mCalculateBoundsMethod(nullptr), mRunInEditor(false)
 	{ }
 
 	ManagedComponent::ManagedComponent(const HSceneObject& parent, MonoReflectionType* runtimeType)
 		: Component(parent), mManagedInstance(nullptr), mRuntimeType(runtimeType), mUpdateThunk(nullptr), 
-		mOnDestroyThunk(nullptr), mOnInitializedThunk(nullptr), mOnResetThunk(nullptr), mMissingType(false),
-		mRequiresReset(true), mOnEnabledThunk(nullptr), mOnDisabledThunk(nullptr), mCalculateBoundsMethod(nullptr)
+		mOnDestroyThunk(nullptr), mOnInitializedThunk(nullptr), mOnResetThunk(nullptr), mMissingType(false), 
+		mRequiresReset(true), mOnEnabledThunk(nullptr), mOnDisabledThunk(nullptr), mCalculateBoundsMethod(nullptr),
+		mRunInEditor(false)
 	{
 		MonoType* monoType = mono_reflection_type_get_type(mRuntimeType);
 		::MonoClass* monoClass = mono_type_get_class(monoType);
@@ -168,7 +171,19 @@ namespace BansheeEngine
 				mOnEnabledThunk = (OnInitializedThunkDef)onEnableMethod->getThunk();
 
 			mCalculateBoundsMethod = managedClass->getMethod("CalculateBounds", 2);
+
+			MonoAssembly* bansheeEngineAssembly = MonoManager::instance().getAssembly(ENGINE_ASSEMBLY);
+			if (bansheeEngineAssembly == nullptr)
+				BS_EXCEPT(InvalidStateException, String(ENGINE_ASSEMBLY) + " assembly is not loaded.");
+
+			MonoClass* runInEditorAttrib = bansheeEngineAssembly->getClass("BansheeEngine", "RunInEditor");
+			if (runInEditorAttrib == nullptr)
+				BS_EXCEPT(InvalidStateException, "Cannot find RunInEditor managed class.");
+
+			mRunInEditor = managedClass->getAttribute(runInEditorAttrib) != nullptr;
 		}
+		else
+			mRunInEditor = false;
 	}
 
 	bool ManagedComponent::typeEquals(const Component& other)
@@ -209,6 +224,9 @@ namespace BansheeEngine
 
 	void ManagedComponent::update()
 	{
+		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing && !mRunInEditor)
+			return;
+
 		assert(mManagedInstance != nullptr);
 
 		if (mUpdateThunk != nullptr)
@@ -223,11 +241,14 @@ namespace BansheeEngine
 	{
 		assert(mManagedInstance != nullptr);
 
-		if (mRequiresReset && mOnResetThunk != nullptr)
+		if (PlayInEditorManager::instance().getState() == PlayInEditorState::Playing || mRunInEditor)
 		{
-			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
-			// for some extra speed.
-			MonoUtil::invokeThunk(mOnResetThunk, mManagedInstance);
+			if (mRequiresReset && mOnResetThunk != nullptr)
+			{
+				// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
+				// for some extra speed.
+				MonoUtil::invokeThunk(mOnResetThunk, mManagedInstance);
+			}
 		}
 
 		mRequiresReset = false;
@@ -280,11 +301,14 @@ namespace BansheeEngine
 			mSerializedObjectData = nullptr;
 		}
 
-		if (mOnInitializedThunk != nullptr)
+		if (PlayInEditorManager::instance().getState() == PlayInEditorState::Playing || mRunInEditor)
 		{
-			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
-			// for some extra speed.
-			MonoUtil::invokeThunk(mOnInitializedThunk, mManagedInstance);
+			if (mOnInitializedThunk != nullptr)
+			{
+				// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
+				// for some extra speed.
+				MonoUtil::invokeThunk(mOnInitializedThunk, mManagedInstance);
+			}
 		}
 
 		triggerOnReset();
@@ -294,11 +318,14 @@ namespace BansheeEngine
 	{
 		assert(mManagedInstance != nullptr);
 
-		if (mOnDestroyThunk != nullptr)
+		if (PlayInEditorManager::instance().getState() == PlayInEditorState::Playing || mRunInEditor)
 		{
-			// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
-			// for some extra speed.
-			MonoUtil::invokeThunk(mOnDestroyThunk, mManagedInstance);
+			if (mOnDestroyThunk != nullptr)
+			{
+				// Note: Not calling virtual methods. Can be easily done if needed but for now doing this
+				// for some extra speed.
+				MonoUtil::invokeThunk(mOnDestroyThunk, mManagedInstance);
+			}
 		}
 
 		mManagedInstance = nullptr;
@@ -307,6 +334,9 @@ namespace BansheeEngine
 
 	void ManagedComponent::onEnabled()
 	{
+		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing && !mRunInEditor)
+			return;
+
 		assert(mManagedInstance != nullptr);
 
 		if (mOnEnabledThunk != nullptr)
@@ -319,6 +349,9 @@ namespace BansheeEngine
 
 	void ManagedComponent::onDisabled()
 	{
+		if (PlayInEditorManager::instance().getState() != PlayInEditorState::Playing && !mRunInEditor)
+			return;
+
 		assert(mManagedInstance != nullptr);
 
 		if (mOnDisabledThunk != nullptr)

+ 24 - 0
SBansheeEngine/Source/BsPlayInEditorManager.cpp

@@ -0,0 +1,24 @@
+#include "BsPlayInEditorManager.h"
+
+namespace BansheeEngine
+{
+	PlayInEditorManager::PlayInEditorManager()
+		:mState(PlayInEditorState::Stopped), mFrameStepActive(false)
+	{ }
+
+	void PlayInEditorManager::setState(PlayInEditorState state)
+	{
+		// TODO
+		//  - make sure to reset the clock when starting/stopping
+	}
+
+	void PlayInEditorManager::frameStep()
+	{
+		// TODO
+	}
+
+	void PlayInEditorManager::update()
+	{
+		// TODO
+	}
+}

+ 2 - 0
SBansheeEngine/Source/BsScriptEnginePlugin.cpp

@@ -2,6 +2,7 @@
 #include "BsScriptObjectManager.h"
 #include "BsEngineScriptLibrary.h"
 #include "BsScriptManager.h"
+#include "BsPlayInEditorManager.h"
 
 namespace BansheeEngine
 {
@@ -21,6 +22,7 @@ namespace BansheeEngine
 
 	extern "C" BS_SCR_BE_EXPORT void updatePlugin()
 	{
+		PlayInEditorManager::instance().update();
 		ScriptObjectManager::instance().update();
 	}
 }

+ 1 - 0
TODO.txt

@@ -36,6 +36,7 @@ Optional:
  - Cursors should be replaced with better ones, or at least hot-spots fixed
  - Drag and dropping a prefab onto the scene (or hierarchy) should work the same as with meshes
  - Add tooltips to toolbar items and other buttons with icons
+ - Either disable light tool icons before release or make them functional (With gizmos)
 
 Seriously optional:
  - Drag to select in scene view