677 lines
22 KiB
C++
677 lines
22 KiB
C++
/************************************************************************************//*!
|
|
\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 <sstream>
|
|
// External Dependencies
|
|
#include "ECS_Base/Managers/SHEntityManager.h"
|
|
#include "Tools/SHLog.h"
|
|
// Project Headers
|
|
#include "Utility/Debug.hxx"
|
|
#include "Utility/Convert.hxx"
|
|
#include "Script.hxx"
|
|
#include "Engine/Entity.hxx"
|
|
#include "Serialisation/ReflectionUtilities.hxx"
|
|
|
|
namespace SHADE
|
|
{
|
|
/*---------------------------------------------------------------------------------*/
|
|
/* Scripts Manipulation Functions */
|
|
/*---------------------------------------------------------------------------------*/
|
|
generic<typename T>
|
|
T ScriptStore::AddScript(Entity entity)
|
|
{
|
|
// Check if entity exists
|
|
if (!EntityUtils::IsValid(entity))
|
|
throw gcnew System::ArgumentException("Invalid Entity provided to add a Script to.");
|
|
|
|
System::Collections::Generic::List<Script^> ^ 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<Script^>();
|
|
scripts.Add(entity, entityScriptList);
|
|
}
|
|
else
|
|
{
|
|
entityScriptList = scripts[entity];
|
|
}
|
|
|
|
// Create the script and add it in
|
|
array<Object^>^ params = gcnew array<Object^>{GameObject(entity)};
|
|
Script^ script = safe_cast<Script^>(System::Activator::CreateInstance(T::typeid, params));
|
|
entityScriptList->Add(script);
|
|
awakeList.Add(script);
|
|
startList.Add(script);
|
|
script->OnAttached();
|
|
|
|
return safe_cast<T>(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<T>() 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!";
|
|
Debug::LogError(oss.str());
|
|
return false;
|
|
}
|
|
|
|
// Otherwise, add the script
|
|
System::Reflection::MethodInfo^ method = addScriptMethod->MakeGenericMethod(scriptType);
|
|
try
|
|
{
|
|
array<Object^>^ params = gcnew array<Object^>{entity};
|
|
createdScript = safe_cast<Script^>(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) << ")";
|
|
Debug::LogError(oss.str());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
generic<typename T>
|
|
T ScriptStore::GetScript(Entity entity)
|
|
{
|
|
// Check if entity exists
|
|
if (!EntityUtils::IsValid(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<T>(script);
|
|
return actualScript;
|
|
}
|
|
catch (System::InvalidCastException^)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return T();
|
|
}
|
|
|
|
generic <typename T>
|
|
T ScriptStore::GetScriptInChildren(Entity entity)
|
|
{
|
|
// Check if entity exists and is a valid GameObject
|
|
if (!EntityUtils::IsValid(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 Entity's SceneGraphNode
|
|
SHSceneNode* sceneGraphNode = SHSceneManager::GetCurrentSceneGraph().GetNode(entity);
|
|
if (sceneGraphNode == nullptr)
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "[ECS_CLI] Failed to retrieve SceneGraphNode of entity #" << entity << ". This should not happen!";
|
|
SHLog::Warning(oss.str());
|
|
return T();
|
|
}
|
|
|
|
// Search direct children first
|
|
for (const auto& child : sceneGraphNode->GetChildren())
|
|
{
|
|
T script = GetScript<T>(child->GetEntityID());
|
|
if (script != nullptr)
|
|
return script;
|
|
}
|
|
|
|
// Search their children
|
|
for (const auto& child : sceneGraphNode->GetChildren())
|
|
{
|
|
T script = GetScript<T>(child->GetEntityID());
|
|
if (script != nullptr)
|
|
return script;
|
|
}
|
|
|
|
// None here
|
|
return T();
|
|
}
|
|
|
|
generic <typename T>
|
|
System::Collections::Generic::IEnumerable<T>^ ScriptStore::GetScripts(Entity entity)
|
|
{
|
|
// Check if entity exists and is a valid GameObject
|
|
if (!EntityUtils::IsValid(entity))
|
|
throw gcnew System::ArgumentException("Invalid Entity provided to get a Script from.");
|
|
|
|
// Create a list to store entries
|
|
System::Collections::Generic::List<T>^ foundScripts = gcnew System::Collections::Generic::List<T>();
|
|
|
|
// 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<T>(script);
|
|
foundScripts->Add(actualScript);
|
|
}
|
|
catch (System::InvalidCastException^)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return foundScripts;
|
|
}
|
|
System::Collections::Generic::IEnumerable<Script^>^ ScriptStore::GetAllScripts(Entity entity)
|
|
{
|
|
// Check if entity exists
|
|
if (!EntityUtils::IsValid(entity))
|
|
return nullptr;
|
|
|
|
// Check if entity exists in the script storage
|
|
if (scripts.ContainsKey(entity))
|
|
{
|
|
return scripts[entity];
|
|
}
|
|
return nullptr;
|
|
}
|
|
generic<typename T>
|
|
void ScriptStore::RemoveScript(Entity entity)
|
|
{
|
|
// Check if entity exists
|
|
if (!EntityUtils::IsValid(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<T>(script);
|
|
removeScript(script);
|
|
}
|
|
catch (System::InvalidCastException^)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
bool ScriptStore::RemoveScript(Entity entity, Script^ script)
|
|
{
|
|
// Check if entity exists
|
|
if (!EntityUtils::IsValid(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 in the script storage
|
|
if (!scripts.ContainsKey(entity))
|
|
return;
|
|
|
|
// Search for and clear
|
|
System::Collections::Generic::List<Script^>^ 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 in the script storage
|
|
if (!scripts.ContainsKey(entity))
|
|
return;
|
|
|
|
// Clear all
|
|
System::Collections::Generic::List<Script^>^ 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();
|
|
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, ScriptList^> 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<System::Type^>^ ScriptStore::GetAvailableScriptList()
|
|
{
|
|
return scriptTypeList;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------------*/
|
|
/* Script Execution Functions */
|
|
/*---------------------------------------------------------------------------------*/
|
|
void ScriptStore::ExecuteFixedUpdate()
|
|
{
|
|
SAFE_NATIVE_CALL_BEGIN
|
|
for each (System::Collections::Generic::KeyValuePair<Entity, ScriptList^> 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, ScriptList^> 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, ScriptList^> 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::IntPtr yamlNodePtr)
|
|
{
|
|
SAFE_NATIVE_CALL_BEGIN
|
|
// Convert to pointer
|
|
YAML::Node* yamlNode = reinterpret_cast<YAML::Node*>(yamlNodePtr.ToPointer());
|
|
|
|
// Check if yamlNode is valid
|
|
if (yamlNode == nullptr)
|
|
{
|
|
Debug::LogWarning("[ScriptStore] Attempted to serialise scripts with an invalid YAML Node! Skipping.");
|
|
return false;
|
|
}
|
|
|
|
// Check if entity exists, otherwise nothing
|
|
if (!EntityUtils::IsValid(entity))
|
|
{
|
|
Debug::LogWarning("[ScriptStore] Attempted to serialise scripts for an invalid Entity! Skipping.");
|
|
return false;
|
|
}
|
|
|
|
// Check if entity exists in the script storage
|
|
if (!scripts.ContainsKey(entity))
|
|
return true;
|
|
|
|
// Serialise each script
|
|
yamlNode->SetStyle(YAML::EmitterStyle::Block);
|
|
System::Collections::Generic::List<Script^>^ scriptList = scripts[entity];
|
|
for each (Script^ script in scriptList)
|
|
{
|
|
ReflectionUtilities::Serialise(script, *yamlNode);
|
|
}
|
|
|
|
return true;
|
|
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
|
|
return false;
|
|
}
|
|
|
|
bool ScriptStore::DeserialiseScripts(Entity entity, System::IntPtr yamlNodePtr)
|
|
{
|
|
SAFE_NATIVE_CALL_BEGIN
|
|
// Convert to pointer
|
|
YAML::Node* yamlNode = reinterpret_cast<YAML::Node*>(yamlNodePtr.ToPointer());
|
|
|
|
// Check if yamlNode is valid
|
|
if (yamlNode == nullptr)
|
|
{
|
|
Debug::LogWarning("[ScriptStore] Attempted to deserialise scripts with an invalid YAML Node! Skipping.");
|
|
return false;
|
|
}
|
|
|
|
// Check if entity exists, otherwise nothing
|
|
if (!EntityUtils::IsValid(entity))
|
|
{
|
|
Debug::LogWarning("[ScriptStore] Attempted to deserialise scripts for an invalid Entity! Skipping.");
|
|
return false;
|
|
}
|
|
|
|
// Go through all elements in the node
|
|
for (YAML::Node& node : *yamlNode)
|
|
{
|
|
// Get the name of the script
|
|
if (!node["Type"])
|
|
{
|
|
Debug::LogWarning("[ScriptStore] Script with no type detected, skipping.");
|
|
continue;
|
|
}
|
|
|
|
System::String^ typeName = Convert::ToCLI(node["Type"].as<std::string>());
|
|
|
|
// Create
|
|
Script^ script;
|
|
if (AddScriptViaNameWithRef(entity, typeName, script))
|
|
{
|
|
// Copy the data in
|
|
ReflectionUtilities::Deserialise(script, node);
|
|
}
|
|
else
|
|
{
|
|
Debug::LogWarning("[ScriptStore] Script with unloaded type detected, skipping.");
|
|
}
|
|
}
|
|
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<System::Type^>^ 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(Script::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<Assembly^>^ assemblies = AppDomain::CurrentDomain->GetAssemblies();
|
|
Func<Assembly^, IEnumerable<Type^>^>^ collectionSelector = gcnew Func<Assembly^, IEnumerable<Type^>^>(selectorFunc);
|
|
Func<Assembly^, Type^, Pair^>^ resultSelector = gcnew Func<Assembly^, Type^, Pair^>(resultSelectorFunc);
|
|
IEnumerable<Pair^>^ selectManyResult = Enumerable::SelectMany(assemblies, collectionSelector, resultSelector);
|
|
|
|
/* Where: Are concrete Scripts */
|
|
Func<Pair^, bool>^ predicate = gcnew Func<Pair^, bool>(predicateFunc);
|
|
IEnumerable<Pair^>^ whereResult = Enumerable::Where(selectManyResult, predicate);
|
|
|
|
/* Select: Select them all */
|
|
Func<Pair^, Type^>^ selector = gcnew Func<Pair^, Type^>(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.";
|
|
Debug::Log(oss.str());
|
|
}
|
|
|
|
void ScriptStore::getGenericMethods()
|
|
{
|
|
addScriptMethod = ScriptStore::typeid->GetMethod("AddScript");
|
|
if (addScriptMethod == nullptr)
|
|
{
|
|
Debug::LogError("[ScriptStore] Failed to get MethodInfo of \"AddScript<T>()\". 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)
|
|
{
|
|
// Get native Entity
|
|
SHEntity* nativeEntity = SHEntityManager::GetEntityByID(entity);
|
|
|
|
// Entity Validity Check
|
|
if (nativeEntity == nullptr)
|
|
return false;
|
|
|
|
// Check active state
|
|
return nativeEntity->GetActive();
|
|
}
|
|
}
|