diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index f279bec1..18c2b9e3 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -17,6 +17,7 @@ of DigiPen Institute of Technology is prohibited. #include // std::fstream #include // std::filesystem::canonical, std::filesystem::remove #include // std::shared_ptr +#include // std::this_thread::sleep_for // Project Headers #include "Tools/SHLogger.h" #include "Tools/SHStringUtils.h" @@ -25,7 +26,6 @@ of DigiPen Institute of Technology is prohibited. #include "Events/SHEventReceiver.h" #include "Events/SHEventManager.hpp" #include "Physics/SHPhysicsSystem.h" - #include "Assets/SHAssetMacros.h" namespace SHADE @@ -177,10 +177,10 @@ namespace SHADE } // Prepare directory (delete useless files) - deleteFolder(CSPROJ_DIR + "\\net5.0"); - deleteFolder(CSPROJ_DIR + "\\ref"); - deleteFolder(CSPROJ_DIR + "\\obj"); - deleteFolder(CSPROJ_DIR + "\\bin"); + deleteFolder(CSPROJ_DIR + "/net5.0"); + deleteFolder(CSPROJ_DIR + "/ref"); + deleteFolder(CSPROJ_DIR + "/obj"); + deleteFolder(CSPROJ_DIR + "/bin"); // Attempt to build the assembly std::ostringstream oss; @@ -214,7 +214,10 @@ namespace SHADE // Clean up built files deleteFolder("./tmp"); - deleteFolder(CSPROJ_DIR + "\\obj"); + deleteFolder(CSPROJ_DIR + "/bin"); + using namespace std::chrono_literals; + std::this_thread::sleep_for(50ms); // Not sure why this works but it prevents the folders from respawning + deleteFolder(CSPROJ_DIR + "/obj"); // Read the build log and output to the console dumpBuildLog(BUILD_LOG_PATH); diff --git a/SHADE_Managed/src/Components/Component.hxx b/SHADE_Managed/src/Components/Component.hxx index e52ab3a7..a1d83eaf 100644 --- a/SHADE_Managed/src/Components/Component.hxx +++ b/SHADE_Managed/src/Components/Component.hxx @@ -110,7 +110,7 @@ namespace SHADE /// Component to check. static operator bool(BaseComponent^ c); - protected: + internal: /*-----------------------------------------------------------------------------*/ /* Constructors */ /*-----------------------------------------------------------------------------*/ @@ -193,7 +193,6 @@ namespace SHADE /// NativeComponent* GetNativeComponent(); - protected: /*-----------------------------------------------------------------------------*/ /* Constructors */ /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx index 68dddf34..7b2e0982 100644 --- a/SHADE_Managed/src/Editor/Editor.cxx +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -79,7 +79,10 @@ namespace SHADE if (SHEditorUI::Selectable(Convert::ToNative(type->Name))) { // Add the script - ScriptStore::AddScriptViaName(entity, type->Name); + Script^ script; + ScriptStore::AddScriptViaNameWithRef(entity, type->Name, script); + registerUndoScriptAddAction(entity, script); + break; } } @@ -120,7 +123,7 @@ namespace SHADE SHEditorUI::Indent(); { // Right Click Menu - renderScriptContextMenu(entity, script); + renderScriptContextMenu(entity, script, index); // Go through all fields and output them auto fields = ReflectionUtilities::GetInstanceFields(script); @@ -143,7 +146,7 @@ namespace SHADE } else { - renderScriptContextMenu(entity, script); + renderScriptContextMenu(entity, script, index); } SHEditorUI::PopID(); } @@ -336,7 +339,7 @@ namespace SHADE return false; } - void Editor::renderScriptContextMenu(Entity entity, Script^ script) + void Editor::renderScriptContextMenu(Entity entity, Script^ script, int scriptIndex) { // Right Click Menu if (SHEditorUI::BeginPopupContextItem("scriptContextMenu")) @@ -345,6 +348,7 @@ namespace SHADE { // Mark script for removal ScriptStore::RemoveScript(entity, script); + registerUndoScriptRemoveAction(entity, script, scriptIndex); } SHEditorUI::EndPopup(); } @@ -392,6 +396,28 @@ namespace SHADE SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast(std::make_shared())); } + void Editor::registerUndoScriptAddAction(EntityID id, Script^ script) + { + if (script == nullptr) + return; + + actionStack.Add(gcnew ScriptAddCommand(id, script)); + + // Inform the C++ Undo-Redo stack + SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast(std::make_shared())); + } + + void Editor::registerUndoScriptRemoveAction(EntityID id, Script^ script, int originalIndex) + { + if (script == nullptr) + return; + + actionStack.Add(gcnew ScriptRemoveCommand(id, script, originalIndex)); + + // Inform the C++ Undo-Redo stack + SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast(std::make_shared())); + } + generic Attribute Editor::hasAttribute(System::Reflection::FieldInfo^ field) { diff --git a/SHADE_Managed/src/Editor/Editor.hxx b/SHADE_Managed/src/Editor/Editor.hxx index 64c445e5..79625274 100644 --- a/SHADE_Managed/src/Editor/Editor.hxx +++ b/SHADE_Managed/src/Editor/Editor.hxx @@ -69,7 +69,7 @@ namespace SHADE static UndoRedoStack actionStack; /*-----------------------------------------------------------------------------*/ - /* Helper Functions */ + /* Helper Functions - Inspector Rendering */ /*-----------------------------------------------------------------------------*/ /// /// Renders a single specified Script's inspector. @@ -170,25 +170,25 @@ namespace SHADE /// True if the field is modified. template static bool renderFieldEditorInternal(const std::string& fieldName, interior_ptr managedValPtr, EditorFieldFunc fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib); - /// /// Renders a context menu when right clicked for the scripts /// /// The Entity to render the Scripts of. /// The Script to render the inspector for. - static void renderScriptContextMenu(Entity entity, Script^ script); - /// - /// Adds changes to a variable as an undo-able/redo-able action on the Undo-Redo - /// stack. - /// - /// The object that changes are applied to. - /// The field that was changed. - /// New data to set. - /// Data that was overriden. + /// Index at which the Script is stored. + static void renderScriptContextMenu(Entity entity, Script^ script, int scriptIndex); + /*-----------------------------------------------------------------------------*/ + /* Helper Functions - Undo */ + /*-----------------------------------------------------------------------------*/ static void registerUndoAction(System::Object^ object, System::Reflection::FieldInfo^ field, System::Object^ newData, System::Object^ oldData); static void registerUndoListChangeAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ newData, System::Object^ oldData); static void registerUndoListAddAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ data); static void registerUndoListRemoveAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ data); + static void registerUndoScriptAddAction(EntityID id, Script^ script); + static void registerUndoScriptRemoveAction(EntityID id, Script^ script, int originalIndex); + /*-----------------------------------------------------------------------------*/ + /* Helper Functions - Others */ + /*-----------------------------------------------------------------------------*/ /// /// Checks if a specific field has the specified attribute /// diff --git a/SHADE_Managed/src/Editor/UndoRedoStack.cxx b/SHADE_Managed/src/Editor/UndoRedoStack.cxx index 789d285d..3d1f04e9 100644 --- a/SHADE_Managed/src/Editor/UndoRedoStack.cxx +++ b/SHADE_Managed/src/Editor/UndoRedoStack.cxx @@ -21,6 +21,7 @@ of DigiPen Institute of Technology is prohibited. // Project Headers #include "Utility/Debug.hxx" #include "Utility/Convert.hxx" +#include "Scripts/ScriptStore.hxx" namespace SHADE { @@ -34,7 +35,8 @@ namespace SHADE bool UndoRedoStack::RedoActionPresent::get() { - return latestActionIndex >= 0 && latestActionIndex < commandStack->Count - 1; + const int REDO_ACTION_INDEX = latestActionIndex + 1; + return REDO_ACTION_INDEX >= 0 && REDO_ACTION_INDEX < commandStack->Count; } /*---------------------------------------------------------------------------------*/ @@ -69,8 +71,9 @@ namespace SHADE { if (!RedoActionPresent) return; - - ICommand^ cmd = commandStack[latestActionIndex]; + + const int REDO_ACTION_INDEX = latestActionIndex + 1; + ICommand^ cmd = commandStack[REDO_ACTION_INDEX]; cmd->Execute(); ++latestActionIndex; } @@ -180,7 +183,7 @@ namespace SHADE } /*---------------------------------------------------------------------------------*/ - /* ListElementAddCommand - ICommand Functions */ + /* ListElementAddCommand - Constructor */ /*---------------------------------------------------------------------------------*/ ListElementAddCommand::ListElementAddCommand(System::Collections::IList^ list, int addIndex, System::Object^ data) : list { list } @@ -220,7 +223,7 @@ namespace SHADE } /*---------------------------------------------------------------------------------*/ - /* ListElementRemoveCommand - ICommand Functions */ + /* ListElementRemoveCommand - Constructor */ /*---------------------------------------------------------------------------------*/ ListElementRemoveCommand::ListElementRemoveCommand(System::Collections::IList^ list, int removeIndex, System::Object^ data) : list { list } @@ -258,4 +261,59 @@ namespace SHADE // Not allowed return false; } + + /*---------------------------------------------------------------------------------*/ + /* ScriptAddCommand - Constructor */ + /*---------------------------------------------------------------------------------*/ + ScriptAddCommand::ScriptAddCommand(EntityID id, Script^ script) + : entity { id } + , addedScript { script } + {} + + /*---------------------------------------------------------------------------------*/ + /* ScriptAddCommand - ICommand Functions */ + /*---------------------------------------------------------------------------------*/ + bool ScriptAddCommand::Execute() + { + return ScriptStore::AddScript(entity, addedScript) != nullptr; + } + + bool ScriptAddCommand::Unexceute() + { + return ScriptStore::RemoveScript(entity, addedScript); + } + + bool ScriptAddCommand::Merge(ICommand^) + { + // Not allowed + return false; + } + + /*---------------------------------------------------------------------------------*/ + /* ScriptRemoveCommand - Constructor */ + /*---------------------------------------------------------------------------------*/ + ScriptRemoveCommand::ScriptRemoveCommand(EntityID id, Script^ script, int index) + : entity { id } + , removedScript { script } + , originalIndex { index } + {} + + /*---------------------------------------------------------------------------------*/ + /* ScriptRemoveCommand - ICommand Functions */ + /*---------------------------------------------------------------------------------*/ + bool ScriptRemoveCommand::Execute() + { + return ScriptStore::RemoveScript(entity, removedScript); + } + + bool ScriptRemoveCommand::Unexceute() + { + return ScriptStore::AddScript(entity, removedScript, originalIndex) != nullptr; + } + + bool ScriptRemoveCommand::Merge(ICommand^) + { + // Not allowed + return false; + } } diff --git a/SHADE_Managed/src/Editor/UndoRedoStack.hxx b/SHADE_Managed/src/Editor/UndoRedoStack.hxx index dea458bc..c377e2b7 100644 --- a/SHADE_Managed/src/Editor/UndoRedoStack.hxx +++ b/SHADE_Managed/src/Editor/UndoRedoStack.hxx @@ -12,6 +12,7 @@ Reproduction or disclosure of this file or its contents without the prior writte of DigiPen Institute of Technology is prohibited. *//*************************************************************************************/ #pragma once +#include "Scripts/Script.hxx" namespace SHADE { @@ -102,6 +103,35 @@ namespace SHADE System::Object^ data; }; + private ref class ScriptAddCommand sealed : public ICommand + { + public: + ScriptAddCommand(EntityID id, Script^ script); + + bool Execute() override; + bool Unexceute() override; + bool Merge(ICommand^ command) override; + + private: + EntityID entity; + Script^ addedScript; + }; + + private ref class ScriptRemoveCommand sealed : public ICommand + { + public: + ScriptRemoveCommand(EntityID id, Script^ script, int index); + + bool Execute() override; + bool Unexceute() override; + bool Merge(ICommand^ command) override; + + private: + EntityID entity; + Script^ removedScript; + int originalIndex; + }; + /// /// Class that is able to store a stack of actions that can be done and redone. /// diff --git a/SHADE_Managed/src/Engine/GenericHandle.hxx b/SHADE_Managed/src/Engine/GenericHandle.hxx index 3f8e395f..3d77f54d 100644 --- a/SHADE_Managed/src/Engine/GenericHandle.hxx +++ b/SHADE_Managed/src/Engine/GenericHandle.hxx @@ -21,7 +21,7 @@ namespace SHADE /// /// Managed version of the generic Handle. /// - public value struct GenericHandle + private value struct GenericHandle { public: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Scripts/ScriptStore.cxx b/SHADE_Managed/src/Scripts/ScriptStore.cxx index d11e70c3..b42f7508 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.cxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.cxx @@ -38,6 +38,20 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ generic T ScriptStore::AddScript(Entity entity) + { + // Create the script and add it in + array^ params = gcnew array{GameObject(entity)}; + Script^ script = safe_cast(System::Activator::CreateInstance(T::typeid, params)); + + return safe_cast(AddScript(entity, script)); + } + + Script^ ScriptStore::AddScript(Entity entity, Script^ script) + { + return AddScript(entity, script, System::Int32::MaxValue); + } + + Script^ ScriptStore::AddScript(Entity entity, Script^ script, int index) { // Check if entity exists if (!EntityUtils::IsValid(entity)) @@ -57,15 +71,13 @@ namespace SHADE entityScriptList = scripts[entity]; } - // Create the script and add it in - array^ params = gcnew array{GameObject(entity)}; - Script^ script = safe_cast(System::Activator::CreateInstance(T::typeid, params)); - entityScriptList->Add(script); + // Add the script in + entityScriptList->Insert(System::Math::Clamp(index, 0, entityScriptList->Count), script); awakeList.Add(script); startList.Add(script); script->OnAttached(); - return safe_cast(script); + return script; } bool ScriptStore::AddScriptViaName(Entity entity, System::String^ scriptName) @@ -364,7 +376,10 @@ namespace SHADE } } startList.Clear(); - startList.AddRange(%inactiveStartList); + for each (Script ^ script in startList) + { + startList.Add(script); + } inactiveStartList.Clear(); SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") @@ -373,9 +388,8 @@ namespace SHADE { SAFE_NATIVE_CALL_BEGIN // Clear the queue - while (disposalQueue.Count > 0) - { - Script^ script = disposalQueue.Dequeue(); + for each (Script^ script in disposalQueue) + {; if (Application::IsPlaying) { script->OnDestroy(); @@ -388,6 +402,7 @@ namespace SHADE scripts.Remove(entity); } } + disposalQueue.Clear(); SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") } void ScriptStore::Exit() @@ -677,9 +692,9 @@ namespace SHADE void ScriptStore::removeScript(Script^ script) { // Prepare for disposal - disposalQueue.Enqueue(script); + disposalQueue.Add(script); - // Also remove it fromm awake and start queues if they were created but not initialised + // Also remove it from awake and start queues if they were created but not initialised awakeList.Remove(script); startList.Remove(script); script->OnDetached(); @@ -749,7 +764,8 @@ namespace SHADE void ScriptStore::getGenericMethods() { - addScriptMethod = ScriptStore::typeid->GetMethod("AddScript"); + array^ paramTypes = gcnew array{ Entity::typeid }; + addScriptMethod = ScriptStore::typeid->GetMethod("AddScript", paramTypes); if (addScriptMethod == nullptr) { Debug::LogError("[ScriptStore] Failed to get MethodInfo of \"AddScript()\". Adding of scripts from native code will fail."); diff --git a/SHADE_Managed/src/Scripts/ScriptStore.hxx b/SHADE_Managed/src/Scripts/ScriptStore.hxx index 23440f3d..62e3003a 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.hxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.hxx @@ -25,7 +25,7 @@ namespace SHADE /// Responsible for managing all scripts attached to Entities as well as executing /// all lifecycle functions of scripts. /// - public ref class ScriptStore abstract sealed + private ref class ScriptStore abstract sealed { public: /*-----------------------------------------------------------------------------*/ @@ -46,6 +46,27 @@ namespace SHADE generic where T : ref class, Script static T AddScript(Entity entity); /// + /// Adds a specified pre-constructed Script to a specified Entity. + /// + /// The entity to add a script to. + /// The pre-constructed Script to add. + /// Reference to the script added. + /// + /// If the specified Entity is invalid. + /// + static Script^ AddScript(Entity entity, Script^ script); + /// + /// Adds a specified pre-constructed Script to a specified Entity. + /// + /// The entity to add a script to. + /// The pre-constructed Script to add. + /// Location in the script list to add. + /// Reference to the script added. + /// + /// If the specified Entity is invalid. + /// + static Script^ AddScript(Entity entity, Script^ script, int index); + /// /// Adds a Script to a specified Entity. ///
/// This function is meant for consumption from native code. If you are writing @@ -281,16 +302,16 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ using ScriptList = System::Collections::Generic::List; using ScriptDictionary = System::Collections::Generic::Dictionary; - using ScriptQueue = System::Collections::Generic::Queue; + using ScriptSet = System::Collections::Generic::HashSet; /*-----------------------------------------------------------------------------*/ /* Static Data Members */ /*-----------------------------------------------------------------------------*/ static ScriptDictionary scripts; - static ScriptList awakeList; - static ScriptList startList; - static ScriptList inactiveStartList; - static ScriptQueue disposalQueue; + static ScriptSet awakeList; + static ScriptSet startList; + static ScriptSet inactiveStartList; + static ScriptSet disposalQueue; static System::Collections::Generic::IEnumerable^ scriptTypeList; static System::Reflection::MethodInfo^ addScriptMethod; diff --git a/SHADE_Managed/src/Serialisation/SerialisationUtilities.h++ b/SHADE_Managed/src/Serialisation/SerialisationUtilities.h++ index c1728fe6..3e756ce4 100644 --- a/SHADE_Managed/src/Serialisation/SerialisationUtilities.h++ +++ b/SHADE_Managed/src/Serialisation/SerialisationUtilities.h++ @@ -28,7 +28,6 @@ namespace SHADE template bool SerialisationUtilities::fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Node& fieldNode) { - Debug::Log(FieldType::typeid->Name); return varInsertYamlInternal(fieldInfo->GetValue(object), fieldNode); } template @@ -123,16 +122,6 @@ namespace SHADE return true; } } - else if constexpr (std::is_same_v) - { - if (ReflectionUtilities::FieldIsList(fieldInfo)) - { - System::Collections::IList^ iList = safe_cast(object); - object = gcnew - if (node.IsSequence() ) - - } - } else { if (object->GetType() == FieldType::typeid)