From 5a6ff60fe1ccf09030c46fdadac1388ddd8ef94b Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Tue, 13 Sep 2022 00:18:33 +0800 Subject: [PATCH] Added ScriptStore --- SHADE.sln | 5 + SHADE_Managed/SHADE_Managed.vcxproj.filters | 6 + SHADE_Managed/src/Scripts/ScriptStore.cxx | 673 ++++++++++++++++++++ SHADE_Managed/src/Scripts/ScriptStore.hxx | 305 +++++++++ 4 files changed, 989 insertions(+) create mode 100644 SHADE_Managed/src/Scripts/ScriptStore.cxx create mode 100644 SHADE_Managed/src/Scripts/ScriptStore.hxx diff --git a/SHADE.sln b/SHADE.sln index 67bacd3b..fadd2bea 100644 --- a/SHADE.sln +++ b/SHADE.sln @@ -30,6 +30,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SHADE_Engine", "SHADE_Engin EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SHADE_Managed", "SHADE_Managed\SHADE_Managed.vcxproj", "{16DB1400-829B-9036-4BD6-D9B3B755D512}" + ProjectSection(ProjectDependencies) = postProject + {88F1A057-74BE-FB62-9DD7-E90A890331F1} = {88F1A057-74BE-FB62-9DD7-E90A890331F1} + {C0FF640D-2C14-8DBE-F595-301E616989EF} = {C0FF640D-2C14-8DBE-F595-301E616989EF} + {8EAD431C-7A4F-6EF2-630A-82464F4BF542} = {8EAD431C-7A4F-6EF2-630A-82464F4BF542} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/SHADE_Managed/SHADE_Managed.vcxproj.filters b/SHADE_Managed/SHADE_Managed.vcxproj.filters index c83321cd..ae83954d 100644 --- a/SHADE_Managed/SHADE_Managed.vcxproj.filters +++ b/SHADE_Managed/SHADE_Managed.vcxproj.filters @@ -34,6 +34,9 @@ Scripts + + Scripts + Utility @@ -64,6 +67,9 @@ Scripts + + Scripts + Utility diff --git a/SHADE_Managed/src/Scripts/ScriptStore.cxx b/SHADE_Managed/src/Scripts/ScriptStore.cxx new file mode 100644 index 00000000..86329f29 --- /dev/null +++ b/SHADE_Managed/src/Scripts/ScriptStore.cxx @@ -0,0 +1,673 @@ +/************************************************************************************//*! +\file ScriptStore.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definition of the functions for the ScriptStore managed + static class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "ScriptStore.hxx" +// Standard Libraries +#include +// Project Headers +#include "Utility/Debug.hxx" +#include "Utility/Convert.hxx" +#include "Tools/SHLogger.h" +#include "Script.hxx" +#include "Engine/Entity.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Scripts Manipulation Functions */ + /*---------------------------------------------------------------------------------*/ + generic + T ScriptStore::AddScript(Entity entity) + { + // Check if entity exists and is a valid GameObject + if (!EntityUtils::IsValid(entity) /*|| !GameObjectLibrary::Contains(entity)*/) + throw gcnew System::ArgumentException("Invalid Entity provided to add a Script to."); + + System::Collections::Generic::List ^ entityScriptList; + + // Check if storage for scripts of this entity exists + if (!scripts.ContainsKey(entity)) + { + // Create a new list for this set of scripts + entityScriptList = gcnew System::Collections::Generic::List(); + scripts.Add(entity, entityScriptList); + } + else + { + 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); + awakeList.Add(script); + startList.Add(script); + script->OnAttached(); + + return safe_cast(script); + } + + bool ScriptStore::AddScriptViaName(Entity entity, System::String^ scriptName) + { + SAFE_NATIVE_CALL_BEGIN + Script^ script; + return AddScriptViaNameWithRef(entity, scriptName, script); + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + return false; + } + + bool ScriptStore::AddScriptViaNameWithRef(Entity entity, System::String^ scriptName, Script^% createdScript) + { + // Check if we are set up to get scripts + if (addScriptMethod == nullptr) + { + Debug::LogError("[ScriptStore] Native AddScript() was not loaded. Unable to add scripts."); + return false; + } + + // Get the script if it exists + System::Type^ scriptType = getScriptType(scriptName); + if (scriptType == nullptr) + { + std::ostringstream oss; + oss << "[ScriptStore] No Script named " + << Convert::ToNative(scriptName) + << " found!"; + SHLOG_ERROR(oss.str()); + return false; + } + + // Otherwise, add the script + System::Reflection::MethodInfo^ method = addScriptMethod->MakeGenericMethod(scriptType); + try + { + array^ params = gcnew array{entity}; + createdScript = safe_cast(method->Invoke(nullptr, params)); + } + catch (System::Exception^ e) + { + std::ostringstream oss; + oss << "[ScriptStore] Failed to add Script named \"" << Convert::ToNative(scriptName) + << "\" to Entity #" << entity << "! (" << Convert::ToNative(e->GetType()->Name) << ")"; + SHLOG_ERROR(oss.str()); + return false; + } + return true; + } + + generic + T ScriptStore::GetScript(Entity entity) + { + // Check if entity exists and is a valid GameObject + if (!EntityUtils::IsValid(entity) /*|| !GameObjectLibrary::Contains(entity)*/) + { + throw gcnew System::ArgumentException("Invalid Entity provided to get a Script from."); + } + + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + { + return T(); + } + + // Search for and obtain + for each (Script^ script in scripts[entity]) + { + try + { + T actualScript = safe_cast(script); + return actualScript; + } + catch (System::InvalidCastException^) + { + continue; + } + } + + return T(); + } + + generic + T ScriptStore::GetScriptInChildren(Entity entity) + { + // Check if entity exists and is a valid GameObject + if (!EntityUtils::IsValid(entity) /*|| !GameObjectLibrary::Contains(entity)*/) + { + throw gcnew System::ArgumentException("Invalid Entity provided to get a Script from."); + } + + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + { + return T(); + } + + // Get Transform component and get the children list + throw gcnew System::NotImplementedException; + //Pls::Transform* tf = Pls::ECS::GetComponent(Convert::ToNative(entity)); + //if (tf == nullptr) + // return T(); + + //// Search direct children first + //for (const auto& child : tf->GetChildren()) + //{ + // T script = GetScript(Convert::ToCLI(child)); + // if (script != nullptr) + // return script; + //} + + //// Search their children + //for (const auto& child : tf->GetChildren()) + //{ + // T script = GetScriptInChildren(Convert::ToCLI(child)); + // if (script != nullptr) + // return script; + //} + + // None here + return T(); + } + + generic + System::Collections::Generic::IEnumerable^ ScriptStore::GetScripts(Entity entity) + { + // Check if entity exists and is a valid GameObject + if (!EntityUtils::IsValid(entity) /*|| !GameObjectLibrary::Contains(entity)*/) + { + throw gcnew System::ArgumentException("Invalid Entity provided to get a Script from."); + } + + // Create a list to store entries + System::Collections::Generic::List^ foundScripts = gcnew System::Collections::Generic::List(); + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + { + return foundScripts; + } + + // Search for and obtain + for each (Script^ script in scripts[entity]) + { + try + { + T actualScript = safe_cast(script); + foundScripts->Add(actualScript); + } + catch (System::InvalidCastException^) + { + continue; + } + } + + return foundScripts; + } + System::Collections::Generic::IEnumerable^ ScriptStore::GetAllScripts(Entity entity) + { + // Check if entity exists and is a valid GameObject + if (!EntityUtils::IsValid(entity) /*|| !GameObjectLibrary::Contains(entity)*/) + return nullptr; + + // Check if entity exists in the script storage + if (scripts.ContainsKey(entity)) + { + return scripts[entity]; + } + return nullptr; + } + generic + void ScriptStore::RemoveScript(Entity entity) + { + // Check if entity exists and is a valid GameObject + if (!EntityUtils::IsValid(entity) /*|| !GameObjectLibrary::Contains(entity)*/) + throw gcnew System::ArgumentException("Invalid Entity provided to remove a Script from."); + + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + { + Debug::LogError("[ScriptStore] Attempted to remove a Script that does not belong to the specified Entity!"); + return; + } + + // Search for and obtain + for each (Script^ script in scripts[entity]) + { + try + { + safe_cast(script); + removeScript(script); + } + catch (System::InvalidCastException^) + { + continue; + } + } + } + bool ScriptStore::RemoveScript(Entity entity, Script^ script) + { + // Check if entity exists and is a valid GameObject + if (!EntityUtils::IsValid(entity) /*|| !GameObjectLibrary::Contains(entity)*/) + { + Debug::LogError("[ScriptStore] Attempted to remove a Script from an invalid Entity!"); + return false; + } + + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + { + Debug::LogError("[ScriptStore] Attempted to remove a Script that does not belong to the specified Entity!"); + return false; + } + + // Check if the script exists to begin with + if (!scripts[entity]->Contains(script)) + { + Debug::LogError("[ScriptStore] Attempted to remove a Script that does not belong to the specified Entity!"); + return false; + } + + // Script found, queue it for deletion + removeScript(script); + return true; + } + void ScriptStore::RemoveAllScripts(Entity entity) + { + SAFE_NATIVE_CALL_BEGIN + // Check if entity exists and is a valid GameObject + if (!EntityUtils::IsValid(entity) /*|| !GameObjectLibrary::Contains(entity)*/) + { + Debug::LogError("[ScriptStore] Attempted to remove Scripts from an invalid Entity!"); + return; + } + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + return; + + // Search for and clear + System::Collections::Generic::List^ scriptList = scripts[entity]; + for each (Script^ script in scriptList) + { + removeScript(script); + } + scriptList->Clear(); + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + void ScriptStore::RemoveAllScriptsImmediately(Entity entity, bool callOnDestroy) + { + SAFE_NATIVE_CALL_BEGIN + // Check if entity exists and is a valid GameObject + if (!EntityUtils::IsValid(entity) /*|| !GameObjectLibrary::Contains(entity)*/) + { + Debug::LogError("[ScriptStore] Attempted to remove Scripts from an invalid Entity!"); + return; + } + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + return; + + // Clear all + System::Collections::Generic::List^ scriptList = scripts[entity]; + for each (Script ^ script in scriptList) + { + // Call OnDestroy only if indicated and also in play mode + if (callOnDestroy) + { + script->OnDestroy(); + } + script->OnDetached(); + + // Remove scripts from awakening if they were not woken up to begin with + awakeList.Remove(script); + startList.Remove(script); + } + scriptList->Clear(); + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + + /*---------------------------------------------------------------------------------*/ + /* Lifecycle Functions */ + /*---------------------------------------------------------------------------------*/ + void ScriptStore::Init() + { + // Create an enumerable list of script types + refreshScriptTypeList(); + // Get stored methods for interop variants of functions + getGenericMethods(); + } + void ScriptStore::FrameSetUp() + { + SAFE_NATIVE_CALL_BEGIN + // Clear the awake queue + for each (Script^ script in awakeList) + { + script->Awake(); + } + awakeList.Clear(); + + // Clear the start queue + for each (Script^ script in startList) + { + if (script->Owner.IsActiveInHierarchy) + { + script->Start(); + } + else + { + inactiveStartList.Add(script); + } + } + startList.Clear(); + startList.AddRange(%inactiveStartList); + inactiveStartList.Clear(); + + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + void ScriptStore::FrameCleanUp() + { + SAFE_NATIVE_CALL_BEGIN + // Clear the queue + while (disposalQueue.Count > 0) + { + Script^ script = disposalQueue.Dequeue(); + /*if (Application::IsPlaying) + { + script->OnDestroy(); + + }*/ + auto entity = script->Owner.GetEntity(); + auto scriptList = scripts[script->Owner.GetEntity()]; + scriptList->Remove(script); + if (scriptList->Count <= 0) + { + scripts.Remove(entity); + } + } + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + void ScriptStore::Exit() + { + SAFE_NATIVE_CALL_BEGIN + // Run the deinit all scripts if needed + //if (Application::IsPlaying) + { + Debug::Log("Running OnDestroy() for scripts."); + for each (System::Collections::Generic::KeyValuePair entity in scripts) + { + for each (Script^ script in entity.Value) + { + script->OnDestroy(); + } + } + } + + // Clear Script Storage + scripts.Clear(); + awakeList.Clear(); + startList.Clear(); + disposalQueue.Clear(); + scriptTypeList = nullptr; + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + + /*---------------------------------------------------------------------------------*/ + /* Script Information Functions */ + /*---------------------------------------------------------------------------------*/ + System::Collections::Generic::IEnumerable^ ScriptStore::GetAvailableScriptList() + { + return scriptTypeList; + } + + /*---------------------------------------------------------------------------------*/ + /* Script Execution Functions */ + /*---------------------------------------------------------------------------------*/ + void ScriptStore::ExecuteFixedUpdate() + { + SAFE_NATIVE_CALL_BEGIN + for each (System::Collections::Generic::KeyValuePair entity in scripts) + { + // Check active state + if (!isEntityActive(entity.Key)) + continue; + + // Update each script + for each (Script^ script in entity.Value) + { + script->FixedUpdate(); + } + } + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + void ScriptStore::ExecuteUpdate() + { + SAFE_NATIVE_CALL_BEGIN + for each (System::Collections::Generic::KeyValuePair entity in scripts) + { + // Check active state + if (!isEntityActive(entity.Key)) + continue; + + // Update each script + for each (Script^ script in entity.Value) + { + script->Update(); + } + } + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + void ScriptStore::ExecuteLateUpdate() + { + SAFE_NATIVE_CALL_BEGIN + for each (System::Collections::Generic::KeyValuePair entity in scripts) + { + // Check active state + if (!isEntityActive(entity.Key)) + continue; + + // Update each script + for each (Script^ script in entity.Value) + { + script->LateUpdate(); + } + } + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + } + bool ScriptStore::SerialiseScripts(Entity entity, System::Text::StringBuilder^ buffer, int bufferSize) + { + SAFE_NATIVE_CALL_BEGIN + // Create a buffer that we can work with temporarily + System::Text::StringBuilder^ jsonString = gcnew System::Text::StringBuilder(); + + // Check if entity exists and is a valid GameObject, otherwise nothing + if (!EntityUtils::IsValid(entity) /*|| !GameObjectLibrary::Contains(entity)*/) + return true; + + + // Check if entity exists in the script storage + if (!scripts.ContainsKey(entity)) + return true; + + // Serialise each script + System::Collections::Generic::List^ scriptList = scripts[entity]; + for (int i = 0; i < scriptList->Count; ++i) + { + throw gcnew System::NotFiniteNumberException; + //jsonString->Append(ReflectionUtilities::Serialise(scriptList[i])); + + // Only add separator if is not last script + if (i != scriptList->Count - 1) + { + jsonString->Append(",\r\n"); + } + } + + // Check if the size is too big + if (jsonString->Length > bufferSize) + return false; + + // Otherwise we copy it over + buffer->Clear(); + buffer->Append(jsonString->ToString()); + return true; + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + return false; + } + + bool ScriptStore::DeserialiseScript(Entity entity, System::String^ json) + { + SAFE_NATIVE_CALL_BEGIN + // Check if entity exists and is a valid GameObject, otherwise nothing + if (!EntityUtils::IsValid(entity)/* || !GameObjectLibrary::Contains(entity)*/) + return false; + + // Get the name of the script + const int FIRST_QUOTE = json->IndexOf('\"'); + const int FIRST_COLON = json->IndexOf(':'); + if (FIRST_QUOTE < 0 || FIRST_COLON < 0) // No script name, it's invalid + return false; + const int SCRIPT_NAME_START = FIRST_QUOTE + 1; + const int SCRIPT_NAME_END = FIRST_COLON - 1; + System::String^ typeName = json->Substring(SCRIPT_NAME_START, SCRIPT_NAME_END - SCRIPT_NAME_START); + + // Create the script + Script^ script; + if (AddScriptViaNameWithRef(entity, typeName, script)) + { + // Copy the data in + throw gcnew System::NotImplementedException; + //ReflectionUtilities::Deserialise(json, script); + return true; + } + + SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore") + return false; + } + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + void ScriptStore::removeScript(Script^ script) + { + // Prepare for disposal + disposalQueue.Enqueue(script); + + // Also remove it fromm awake and start queues if they were created but not initialised + awakeList.Remove(script); + startList.Remove(script); + script->OnDetached(); + } + + namespace + { + /* Select Many */ + ref struct Pair + { + System::Reflection::Assembly^ assembly; + System::Type^ type; + }; + + System::Collections::Generic::IEnumerable^ selectorFunc(System::Reflection::Assembly^ assembly) + { + return assembly->GetExportedTypes(); + } + Pair^ resultSelectorFunc(System::Reflection::Assembly^ assembly, System::Type^ type) + { + Pair^ p = gcnew Pair(); + p->assembly = assembly; + p->type = type; + return p; + } + + /* Where */ + bool predicateFunc(Pair^ pair) + { + return pair->type->IsSubclassOf(PlushieScript::typeid) && !pair->type->IsAbstract; + } + + /* Select */ + System::Type^ selectorFunc(Pair^ pair) + { + return pair->type; + } + } + + void ScriptStore::refreshScriptTypeList() + { + using namespace System; + using namespace System::Reflection; + using namespace System::Linq; + using namespace System::Collections::Generic; + + /* Select Many: Types in Loaded Assemblies */ + IEnumerable^ assemblies = AppDomain::CurrentDomain->GetAssemblies(); + Func^>^ collectionSelector = gcnew Func^>(selectorFunc); + Func^ resultSelector = gcnew Func(resultSelectorFunc); + IEnumerable^ selectManyResult = Enumerable::SelectMany(assemblies, collectionSelector, resultSelector); + + /* Where: Are concrete PlushieScripts */ + Func^ predicate = gcnew Func(predicateFunc); + IEnumerable^ whereResult = Enumerable::Where(selectManyResult, predicate); + + /* Select: Select them all */ + Func^ selector = gcnew Func(selectorFunc); + scriptTypeList = Enumerable::Select(whereResult, selector); + + // Log + std::ostringstream oss; + oss << "[ScriptStore] Successfully retrieved references to " << Enumerable::Count(scriptTypeList) + << " Script(s) from currently loaded assemblies."; + SHLOG_INFO(oss.str()); + } + + void ScriptStore::getGenericMethods() + { + addScriptMethod = ScriptStore::typeid->GetMethod("AddScript"); + if (addScriptMethod == nullptr) + { + SHLOG_ERROR("[ScriptStore] Failed to get MethodInfo of \"AddScript()\". Adding of scripts from native code will fail."); + } + } + + System::Type^ ScriptStore::getScriptType(System::String^ scriptName) + { + // Remove any whitespaces just in case + scriptName = scriptName->Trim(); + + // Look for the correct script + for each (System::Type^ type in scriptTypeList) + { + if (type->FullName == scriptName || type->Name == scriptName) + { + return type; + } + } + + return nullptr; + } + + bool ScriptStore::isEntityActive(Entity entity) + { + // Check active state + return Convert::ToNative(entity).isActive; + } +} // namespace SHADE diff --git a/SHADE_Managed/src/Scripts/ScriptStore.hxx b/SHADE_Managed/src/Scripts/ScriptStore.hxx new file mode 100644 index 00000000..91c98ce9 --- /dev/null +++ b/SHADE_Managed/src/Scripts/ScriptStore.hxx @@ -0,0 +1,305 @@ +/************************************************************************************//*! +\file ScriptStore.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definitions of the GameObject managed class which define an + abstraction for working with Entities in managed code. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Project Includes +#include "Engine/Entity.hxx" +#include "Script.hxx" + +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 + { + public: + /*-----------------------------------------------------------------------------*/ + /* Scripts Manipulation Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Adds a Script to a specified Entity. + /// + /// + /// Type of script to add. + /// This needs to be a default constructable PlushieScript. + /// + /// The entity to add a script to. + /// Reference to the script added. + /// + /// If the specified Entity is invalid. + /// + generic where T : ref class, Script + static T AddScript(Entity entity); + /// + /// Adds a Script to a specified Entity. + ///
+ /// This function is meant for consumption from native code. If you are writing + /// in C# or C++/CLI, use AddScript<T>() instead as it is faster. + ///
+ /// The entity to add a script to. + /// The entity to add a script to. + /// + /// True if successfully added. False otherwise with the error logged to the + /// console. + /// + static bool AddScriptViaName(Entity entity, System::String^ scriptName); + /// + /// Adds a Script to a specified Entity. + ///
+ /// This function is meant for consumption from native code or for serialisation + /// purposes. If you are writing in C# or C++/CLI and not doing serialisation, + /// use AddScript<T>() instead as it is faster. + ///
+ /// The entity to add a script to. + /// The entity to add a script to. + /// + /// Out parameter handle to the Script that was created. + /// + /// + /// True if successfully added. False otherwise with the error logged to the + /// console. + /// + static bool AddScriptViaNameWithRef(Entity entity, System::String^ scriptName, [Out] Script^% createdScript); + /// + /// Retrieves the first Script from the specified Entity that matches the + /// specified type. + /// + /// + /// Type of script to get. + /// This needs to be a default constructable Script. + /// + /// + /// The entity which the script to retrieve is attached. + /// + /// + /// Reference to the script. This can be null if no script of the specified + /// type is attached. + /// + /// + /// If the specified Entity is invalid. + /// + generic where T : ref class, Script + static T GetScript(Entity entity); + /// + /// Retrieves the first Script from the specified Entity's children that matches + /// the specified type. + /// + /// + /// Type of script to get. + /// This needs to be a default constructable Script. + /// + /// + /// The entity which the script to retrieve is attached. + /// + /// + /// Reference to the script. This can be null if no script of the specified + /// type is attached. + /// + /// + /// If the specified Entity is invalid. + /// + generic where T : ref class, Script + static T GetScriptInChildren(Entity entity); + /// + /// Retrieves a immutable list of scripts from the specified Entity that + /// matches the specified type. + ///
+ /// Note that this function allocates. It should be used sparingly. + ///
+ /// + /// Type of scripts to get. + /// This needs to be a default constructable Script. + /// + /// + /// The entity which the scripts to retrieve are attached. + /// + /// + /// Immutable list of references to scripts of the specified type. + /// + generic where T : ref class, Script + static System::Collections::Generic::IEnumerable ^ GetScripts(Entity entity); + /// + /// Retrieves an immutable list of all scripts attached to a specified Entity. + /// + /// + /// The entity which the scripts to retrieve are attached. + /// + /// + /// Immutable list of references to scripts attached to the specified Entity. + /// This can also be null if there are no scripts at all or an invalid Entity + /// was specified. + /// + static System::Collections::Generic::IEnumerable^ GetAllScripts(Entity entity); + /// + /// Removes all Scripts of the specified type from the specified Entity. + /// + /// + /// Type of script to remove. + /// This needs to be a default constructable Script. + /// + /// The entity to remove the script from. + /// + /// If the specified Entity is invalid. + /// + generic where T : ref class, Script + static void RemoveScript(Entity entity); + /// + /// Removes a specific script from the + /// + /// The entity to remove the script from. + /// The script to remove. + /// True if successfully removed. False otherwise. + static bool RemoveScript(Entity entity, Script^ script); + /// + /// Removes all Scripts attached to the specified Entity. Does not do anything + /// if the specified Entity is invalid or does not have any Scripts + /// attached. + /// + /// The entity to remove the scripts from. + static void RemoveAllScripts(Entity entity); + /// + /// Removes all Scripts attached to the specified Entity. Unlike + /// RemoveAllScripts(), this removes all the scripts immediately. + /// Does not do anything if the specified Entity is invalid or does not have any + /// Scripts attached. + /// + /// The entity to remove the scripts from. + /// + /// Whether or not to call OnDestroy on the scripts.This is ignored if not in + /// play mode. + /// + static void RemoveAllScriptsImmediately(Entity entity, bool callOnDestroy); + + internal: + /*-----------------------------------------------------------------------------*/ + /* Lifecycle Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Initializes the ScriptStore to allocate and pre-populate reflection data. + /// + static void Init(); + /// + /// Sets up scripts that were marked for initialization. This calls the Awake() + /// and Start() for Scripts that have yet to have done so. + /// + static void FrameSetUp(); + /// + /// Cleans up scripts that were marked for deletion. This calls the OnDestroy() + /// for these Scripts. + /// + static void FrameCleanUp(); + /// + /// Cleans up data stored in the ScriptStore to free up memory for garbage + /// collection. + /// + static void Exit(); + + /*-----------------------------------------------------------------------------*/ + /* Script Information Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Retrieves a immutable list of available scripts that can be added. + /// + /// Immutable list of available scripts that can be added. + static System::Collections::Generic::IEnumerable^ GetAvailableScriptList(); + + /*-----------------------------------------------------------------------------*/ + /* Script Execution Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Executes FixedUpdate() for all scripts. + /// + static void ExecuteFixedUpdate(); + /// + /// Executes Update() for all scripts. + /// + static void ExecuteUpdate(); + /// + /// Executes LateUpdate() for all scripts. + /// + static void ExecuteLateUpdate(); + /// + /// Executes OnTrigger functions for all scripts. + /// + static void ExecuteOnTrigger(); + + /*-----------------------------------------------------------------------------*/ + /* Serialisation Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Generates a JSON string that represents the set of Scripts attached + /// to the specified Entity. + ///

+ /// This function should only be called from native unmanaged code. + ///
+ /// The Entity to Serialise. + /// + /// StringBuilder handle that maps to a native char array that will contain the + /// serialised string. + /// + /// + /// The size of the char array. + /// + /// + /// True if serialisation is successful. False if the buffer is too small for + /// the serialised output. + /// + static bool SerialiseScripts(Entity entity, System::Text::StringBuilder^ buffer, int bufferSize); + /// + /// Processes a JSON string that represents a single Script and attaches + /// it onto the specified Entity. + ///

+ /// This function should only be called from native unmanaged code. + ///
+ /// + /// The Entity to attach the deserialised Scripts to. + /// + /// + /// JSON string that describes the Script to serialise. + /// + /// + static bool DeserialiseScript(Entity entity, System::String^ json); + + private: + /*-----------------------------------------------------------------------------*/ + /* Type Definition */ + /*-----------------------------------------------------------------------------*/ + using ScriptList = System::Collections::Generic::List; + using ScriptDictionary = System::Collections::Generic::Dictionary; + using ScriptQueue = System::Collections::Generic::Queue; + + /*-----------------------------------------------------------------------------*/ + /* Static Data Members */ + /*-----------------------------------------------------------------------------*/ + static ScriptDictionary scripts; + static ScriptList awakeList; + static ScriptList startList; + static ScriptList inactiveStartList; + static ScriptQueue disposalQueue; + static System::Collections::Generic::IEnumerable^ scriptTypeList; + static System::Reflection::MethodInfo^ addScriptMethod; + + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + static void removeScript(Script^ script); + static void refreshScriptTypeList(); + static void getGenericMethods(); + static System::Type^ getScriptType(System::String^ scriptName); + static bool isEntityActive(Entity entity); + }; +} // namespace PlushieAPI \ No newline at end of file