Add script runtime lifecycle skeleton
This commit is contained in:
@@ -241,12 +241,17 @@ add_library(XCEngine STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/AudioClip/AudioLoader.cpp
|
||||
|
||||
# Scripting
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Scripting/IScriptRuntime.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Scripting/NullScriptRuntime.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Scripting/ScriptField.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Scripting/ScriptFieldStorage.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Scripting/ScriptComponent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Scripting/ScriptEngine.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Scripting/NullScriptRuntime.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Scripting/ScriptField.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Scripting/ScriptFieldStorage.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Scripting/ScriptComponent.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Scripting/ScriptEngine.cpp
|
||||
|
||||
# Components
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Components/Component.h
|
||||
|
||||
52
engine/include/XCEngine/Scripting/IScriptRuntime.h
Normal file
52
engine/include/XCEngine/Scripting/IScriptRuntime.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace XCEngine {
|
||||
|
||||
namespace Components {
|
||||
class GameObject;
|
||||
class Scene;
|
||||
}
|
||||
|
||||
namespace Scripting {
|
||||
|
||||
class ScriptComponent;
|
||||
|
||||
enum class ScriptLifecycleMethod {
|
||||
Awake = 0,
|
||||
OnEnable,
|
||||
Start,
|
||||
FixedUpdate,
|
||||
Update,
|
||||
LateUpdate,
|
||||
OnDisable,
|
||||
OnDestroy
|
||||
};
|
||||
|
||||
struct ScriptRuntimeContext {
|
||||
Components::Scene* scene = nullptr;
|
||||
Components::GameObject* gameObject = nullptr;
|
||||
ScriptComponent* component = nullptr;
|
||||
uint64_t gameObjectUUID = 0;
|
||||
uint64_t scriptComponentUUID = 0;
|
||||
};
|
||||
|
||||
class IScriptRuntime {
|
||||
public:
|
||||
virtual ~IScriptRuntime() = default;
|
||||
|
||||
virtual void OnRuntimeStart(Components::Scene* scene) = 0;
|
||||
virtual void OnRuntimeStop(Components::Scene* scene) = 0;
|
||||
|
||||
virtual bool CreateScriptInstance(const ScriptRuntimeContext& context) = 0;
|
||||
virtual void DestroyScriptInstance(const ScriptRuntimeContext& context) = 0;
|
||||
|
||||
virtual void InvokeMethod(
|
||||
const ScriptRuntimeContext& context,
|
||||
ScriptLifecycleMethod method,
|
||||
float deltaTime) = 0;
|
||||
};
|
||||
|
||||
} // namespace Scripting
|
||||
} // namespace XCEngine
|
||||
23
engine/include/XCEngine/Scripting/NullScriptRuntime.h
Normal file
23
engine/include/XCEngine/Scripting/NullScriptRuntime.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/Scripting/IScriptRuntime.h>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Scripting {
|
||||
|
||||
class NullScriptRuntime : public IScriptRuntime {
|
||||
public:
|
||||
void OnRuntimeStart(Components::Scene* scene) override;
|
||||
void OnRuntimeStop(Components::Scene* scene) override;
|
||||
|
||||
bool CreateScriptInstance(const ScriptRuntimeContext& context) override;
|
||||
void DestroyScriptInstance(const ScriptRuntimeContext& context) override;
|
||||
|
||||
void InvokeMethod(
|
||||
const ScriptRuntimeContext& context,
|
||||
ScriptLifecycleMethod method,
|
||||
float deltaTime) override;
|
||||
};
|
||||
|
||||
} // namespace Scripting
|
||||
} // namespace XCEngine
|
||||
@@ -36,6 +36,10 @@ public:
|
||||
const ScriptFieldStorage& GetFieldStorage() const { return m_fieldStorage; }
|
||||
void SetFieldStorage(const ScriptFieldStorage& fieldStorage) { m_fieldStorage = fieldStorage; }
|
||||
|
||||
void OnEnable() override;
|
||||
void OnDisable() override;
|
||||
void OnDestroy() override;
|
||||
|
||||
void Serialize(std::ostream& os) const override;
|
||||
void Deserialize(std::istream& is) override;
|
||||
|
||||
|
||||
88
engine/include/XCEngine/Scripting/ScriptEngine.h
Normal file
88
engine/include/XCEngine/Scripting/ScriptEngine.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/Scripting/IScriptRuntime.h>
|
||||
#include <XCEngine/Scripting/NullScriptRuntime.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Scripting {
|
||||
|
||||
class ScriptComponent;
|
||||
|
||||
class ScriptEngine {
|
||||
public:
|
||||
static ScriptEngine& Get();
|
||||
|
||||
void SetRuntime(IScriptRuntime* runtime);
|
||||
IScriptRuntime* GetRuntime() const { return m_runtime; }
|
||||
|
||||
void OnRuntimeStart(Components::Scene* scene);
|
||||
void OnRuntimeStop();
|
||||
|
||||
void OnFixedUpdate(float fixedDeltaTime);
|
||||
void OnUpdate(float deltaTime);
|
||||
void OnLateUpdate(float deltaTime);
|
||||
|
||||
void OnScriptComponentEnabled(ScriptComponent* component);
|
||||
void OnScriptComponentDisabled(ScriptComponent* component);
|
||||
void OnScriptComponentDestroyed(ScriptComponent* component);
|
||||
|
||||
bool IsRuntimeRunning() const { return m_runtimeRunning; }
|
||||
Components::Scene* GetRuntimeScene() const { return m_runtimeScene; }
|
||||
|
||||
bool HasTrackedScriptComponent(const ScriptComponent* component) const;
|
||||
bool HasRuntimeInstance(const ScriptComponent* component) const;
|
||||
size_t GetTrackedScriptCount() const { return m_scriptOrder.size(); }
|
||||
|
||||
private:
|
||||
struct ScriptInstanceKey {
|
||||
uint64_t gameObjectUUID = 0;
|
||||
uint64_t scriptComponentUUID = 0;
|
||||
|
||||
bool operator==(const ScriptInstanceKey& other) const {
|
||||
return gameObjectUUID == other.gameObjectUUID
|
||||
&& scriptComponentUUID == other.scriptComponentUUID;
|
||||
}
|
||||
};
|
||||
|
||||
struct ScriptInstanceKeyHasher {
|
||||
size_t operator()(const ScriptInstanceKey& key) const;
|
||||
};
|
||||
|
||||
struct ScriptInstanceState {
|
||||
ScriptRuntimeContext context;
|
||||
bool instanceCreated = false;
|
||||
bool awakeCalled = false;
|
||||
bool enabled = false;
|
||||
bool startCalled = false;
|
||||
bool startPending = false;
|
||||
};
|
||||
|
||||
ScriptEngine() = default;
|
||||
|
||||
void CollectScriptComponents(Components::GameObject* gameObject);
|
||||
ScriptInstanceState* TrackScriptComponent(ScriptComponent* component);
|
||||
ScriptInstanceState* FindState(const ScriptComponent* component);
|
||||
const ScriptInstanceState* FindState(const ScriptComponent* component) const;
|
||||
void RemoveTrackedScriptComponent(const ScriptComponent* component);
|
||||
|
||||
bool ShouldScriptRun(const ScriptInstanceState& state) const;
|
||||
bool EnsureScriptReady(ScriptInstanceState& state, bool invokeEnableIfNeeded);
|
||||
void InvokeLifecycleMethod(ScriptInstanceState& state, ScriptLifecycleMethod method, float deltaTime = 0.0f);
|
||||
void StopTrackingScript(ScriptInstanceState& state, bool runtimeStopping);
|
||||
|
||||
NullScriptRuntime m_nullRuntime;
|
||||
IScriptRuntime* m_runtime = &m_nullRuntime;
|
||||
Components::Scene* m_runtimeScene = nullptr;
|
||||
bool m_runtimeRunning = false;
|
||||
|
||||
std::unordered_map<ScriptInstanceKey, ScriptInstanceState, ScriptInstanceKeyHasher> m_scriptStates;
|
||||
std::vector<ScriptInstanceKey> m_scriptOrder;
|
||||
};
|
||||
|
||||
} // namespace Scripting
|
||||
} // namespace XCEngine
|
||||
32
engine/src/Scripting/NullScriptRuntime.cpp
Normal file
32
engine/src/Scripting/NullScriptRuntime.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "Scripting/NullScriptRuntime.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Scripting {
|
||||
|
||||
void NullScriptRuntime::OnRuntimeStart(Components::Scene* scene) {
|
||||
(void)scene;
|
||||
}
|
||||
|
||||
void NullScriptRuntime::OnRuntimeStop(Components::Scene* scene) {
|
||||
(void)scene;
|
||||
}
|
||||
|
||||
bool NullScriptRuntime::CreateScriptInstance(const ScriptRuntimeContext& context) {
|
||||
return context.component != nullptr;
|
||||
}
|
||||
|
||||
void NullScriptRuntime::DestroyScriptInstance(const ScriptRuntimeContext& context) {
|
||||
(void)context;
|
||||
}
|
||||
|
||||
void NullScriptRuntime::InvokeMethod(
|
||||
const ScriptRuntimeContext& context,
|
||||
ScriptLifecycleMethod method,
|
||||
float deltaTime) {
|
||||
(void)context;
|
||||
(void)method;
|
||||
(void)deltaTime;
|
||||
}
|
||||
|
||||
} // namespace Scripting
|
||||
} // namespace XCEngine
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "Scripting/ScriptComponent.h"
|
||||
|
||||
#include "Scripting/ScriptEngine.h"
|
||||
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
|
||||
@@ -44,6 +46,18 @@ std::string ScriptComponent::GetFullClassName() const {
|
||||
return m_namespaceName + "." + m_className;
|
||||
}
|
||||
|
||||
void ScriptComponent::OnEnable() {
|
||||
ScriptEngine::Get().OnScriptComponentEnabled(this);
|
||||
}
|
||||
|
||||
void ScriptComponent::OnDisable() {
|
||||
ScriptEngine::Get().OnScriptComponentDisabled(this);
|
||||
}
|
||||
|
||||
void ScriptComponent::OnDestroy() {
|
||||
ScriptEngine::Get().OnScriptComponentDestroyed(this);
|
||||
}
|
||||
|
||||
void ScriptComponent::Serialize(std::ostream& os) const {
|
||||
os << "scriptComponentUUID=" << m_scriptComponentUUID << ";";
|
||||
os << "assembly=" << EscapeScriptString(m_assemblyName) << ";";
|
||||
|
||||
355
engine/src/Scripting/ScriptEngine.cpp
Normal file
355
engine/src/Scripting/ScriptEngine.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
#include "Scripting/ScriptEngine.h"
|
||||
|
||||
#include "Components/GameObject.h"
|
||||
#include "Scene/Scene.h"
|
||||
#include "Scripting/ScriptComponent.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Scripting {
|
||||
|
||||
ScriptEngine& ScriptEngine::Get() {
|
||||
static ScriptEngine instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void ScriptEngine::SetRuntime(IScriptRuntime* runtime) {
|
||||
m_runtime = runtime ? runtime : &m_nullRuntime;
|
||||
}
|
||||
|
||||
void ScriptEngine::OnRuntimeStart(Components::Scene* scene) {
|
||||
OnRuntimeStop();
|
||||
|
||||
if (!scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_runtimeScene = scene;
|
||||
m_runtimeRunning = true;
|
||||
m_runtime->OnRuntimeStart(scene);
|
||||
|
||||
for (Components::GameObject* root : scene->GetRootGameObjects()) {
|
||||
CollectScriptComponents(root);
|
||||
}
|
||||
|
||||
for (const ScriptInstanceKey& key : m_scriptOrder) {
|
||||
auto it = m_scriptStates.find(key);
|
||||
if (it == m_scriptStates.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ScriptInstanceState& state = it->second;
|
||||
if (!ShouldScriptRun(state)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EnsureScriptReady(state, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::OnRuntimeStop() {
|
||||
if (!m_runtimeRunning) {
|
||||
m_runtimeScene = nullptr;
|
||||
m_scriptStates.clear();
|
||||
m_scriptOrder.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<ScriptInstanceKey> keys = m_scriptOrder;
|
||||
for (const ScriptInstanceKey& key : keys) {
|
||||
auto it = m_scriptStates.find(key);
|
||||
if (it != m_scriptStates.end()) {
|
||||
StopTrackingScript(it->second, true);
|
||||
}
|
||||
}
|
||||
|
||||
Components::Scene* stoppedScene = m_runtimeScene;
|
||||
m_scriptStates.clear();
|
||||
m_scriptOrder.clear();
|
||||
m_runtimeRunning = false;
|
||||
m_runtimeScene = nullptr;
|
||||
m_runtime->OnRuntimeStop(stoppedScene);
|
||||
}
|
||||
|
||||
void ScriptEngine::OnFixedUpdate(float fixedDeltaTime) {
|
||||
if (!m_runtimeRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const ScriptInstanceKey& key : m_scriptOrder) {
|
||||
auto it = m_scriptStates.find(key);
|
||||
if (it == m_scriptStates.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ScriptInstanceState& state = it->second;
|
||||
if (!ShouldScriptRun(state) || !EnsureScriptReady(state, true) || !state.enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
InvokeLifecycleMethod(state, ScriptLifecycleMethod::FixedUpdate, fixedDeltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::OnUpdate(float deltaTime) {
|
||||
if (!m_runtimeRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const ScriptInstanceKey& key : m_scriptOrder) {
|
||||
auto it = m_scriptStates.find(key);
|
||||
if (it == m_scriptStates.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ScriptInstanceState& state = it->second;
|
||||
if (!ShouldScriptRun(state) || !EnsureScriptReady(state, true) || !state.enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state.startPending && !state.startCalled) {
|
||||
InvokeLifecycleMethod(state, ScriptLifecycleMethod::Start);
|
||||
state.startCalled = true;
|
||||
state.startPending = false;
|
||||
}
|
||||
|
||||
InvokeLifecycleMethod(state, ScriptLifecycleMethod::Update, deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::OnLateUpdate(float deltaTime) {
|
||||
if (!m_runtimeRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const ScriptInstanceKey& key : m_scriptOrder) {
|
||||
auto it = m_scriptStates.find(key);
|
||||
if (it == m_scriptStates.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ScriptInstanceState& state = it->second;
|
||||
if (!ShouldScriptRun(state) || !EnsureScriptReady(state, true) || !state.enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
InvokeLifecycleMethod(state, ScriptLifecycleMethod::LateUpdate, deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::OnScriptComponentEnabled(ScriptComponent* component) {
|
||||
if (!m_runtimeRunning || !component) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptInstanceState* state = TrackScriptComponent(component);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldScriptRun(*state)) {
|
||||
EnsureScriptReady(*state, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::OnScriptComponentDisabled(ScriptComponent* component) {
|
||||
if (!m_runtimeRunning || !component) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptInstanceState* state = FindState(component);
|
||||
if (!state || !state->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
InvokeLifecycleMethod(*state, ScriptLifecycleMethod::OnDisable);
|
||||
state->enabled = false;
|
||||
}
|
||||
|
||||
void ScriptEngine::OnScriptComponentDestroyed(ScriptComponent* component) {
|
||||
if (!m_runtimeRunning || !component) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptInstanceState* state = FindState(component);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
|
||||
StopTrackingScript(*state, false);
|
||||
}
|
||||
|
||||
bool ScriptEngine::HasTrackedScriptComponent(const ScriptComponent* component) const {
|
||||
return FindState(component) != nullptr;
|
||||
}
|
||||
|
||||
bool ScriptEngine::HasRuntimeInstance(const ScriptComponent* component) const {
|
||||
const ScriptInstanceState* state = FindState(component);
|
||||
return state && state->instanceCreated;
|
||||
}
|
||||
|
||||
size_t ScriptEngine::ScriptInstanceKeyHasher::operator()(const ScriptInstanceKey& key) const {
|
||||
const size_t h1 = std::hash<uint64_t>{}(key.gameObjectUUID);
|
||||
const size_t h2 = std::hash<uint64_t>{}(key.scriptComponentUUID);
|
||||
return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));
|
||||
}
|
||||
|
||||
void ScriptEngine::CollectScriptComponents(Components::GameObject* gameObject) {
|
||||
if (!gameObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ScriptComponent* component : gameObject->GetComponents<ScriptComponent>()) {
|
||||
TrackScriptComponent(component);
|
||||
}
|
||||
|
||||
for (Components::GameObject* child : gameObject->GetChildren()) {
|
||||
CollectScriptComponents(child);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptEngine::ScriptInstanceState* ScriptEngine::TrackScriptComponent(ScriptComponent* component) {
|
||||
if (!component || !component->GetGameObject()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ScriptInstanceKey key{
|
||||
component->GetGameObject()->GetUUID(),
|
||||
component->GetScriptComponentUUID()
|
||||
};
|
||||
|
||||
auto it = m_scriptStates.find(key);
|
||||
if (it != m_scriptStates.end()) {
|
||||
it->second.context.scene = component->GetScene();
|
||||
it->second.context.gameObject = component->GetGameObject();
|
||||
it->second.context.component = component;
|
||||
it->second.context.gameObjectUUID = component->GetGameObject()->GetUUID();
|
||||
it->second.context.scriptComponentUUID = component->GetScriptComponentUUID();
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
ScriptInstanceState state;
|
||||
state.context.scene = component->GetScene();
|
||||
state.context.gameObject = component->GetGameObject();
|
||||
state.context.component = component;
|
||||
state.context.gameObjectUUID = component->GetGameObject()->GetUUID();
|
||||
state.context.scriptComponentUUID = component->GetScriptComponentUUID();
|
||||
|
||||
auto [insertedIt, inserted] = m_scriptStates.emplace(key, std::move(state));
|
||||
if (inserted) {
|
||||
m_scriptOrder.push_back(key);
|
||||
}
|
||||
|
||||
return &insertedIt->second;
|
||||
}
|
||||
|
||||
ScriptEngine::ScriptInstanceState* ScriptEngine::FindState(const ScriptComponent* component) {
|
||||
if (!component || !component->GetGameObject()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ScriptInstanceKey key{
|
||||
component->GetGameObject()->GetUUID(),
|
||||
component->GetScriptComponentUUID()
|
||||
};
|
||||
|
||||
auto it = m_scriptStates.find(key);
|
||||
return it != m_scriptStates.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
const ScriptEngine::ScriptInstanceState* ScriptEngine::FindState(const ScriptComponent* component) const {
|
||||
if (!component || !component->GetGameObject()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ScriptInstanceKey key{
|
||||
component->GetGameObject()->GetUUID(),
|
||||
component->GetScriptComponentUUID()
|
||||
};
|
||||
|
||||
auto it = m_scriptStates.find(key);
|
||||
return it != m_scriptStates.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
void ScriptEngine::RemoveTrackedScriptComponent(const ScriptComponent* component) {
|
||||
if (!component || !component->GetGameObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ScriptInstanceKey key{
|
||||
component->GetGameObject()->GetUUID(),
|
||||
component->GetScriptComponentUUID()
|
||||
};
|
||||
|
||||
m_scriptStates.erase(key);
|
||||
m_scriptOrder.erase(
|
||||
std::remove(m_scriptOrder.begin(), m_scriptOrder.end(), key),
|
||||
m_scriptOrder.end());
|
||||
}
|
||||
|
||||
bool ScriptEngine::ShouldScriptRun(const ScriptInstanceState& state) const {
|
||||
return m_runtimeRunning
|
||||
&& state.context.scene == m_runtimeScene
|
||||
&& state.context.scene != nullptr
|
||||
&& state.context.scene->IsActive()
|
||||
&& state.context.gameObject != nullptr
|
||||
&& state.context.gameObject->IsActiveInHierarchy()
|
||||
&& state.context.component != nullptr
|
||||
&& state.context.component->IsEnabled()
|
||||
&& state.context.component->HasScriptClass();
|
||||
}
|
||||
|
||||
bool ScriptEngine::EnsureScriptReady(ScriptInstanceState& state, bool invokeEnableIfNeeded) {
|
||||
if (!state.context.component || !state.context.gameObject || !state.context.scene || !state.context.component->HasScriptClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!state.instanceCreated) {
|
||||
if (!m_runtime->CreateScriptInstance(state.context)) {
|
||||
return false;
|
||||
}
|
||||
state.instanceCreated = true;
|
||||
}
|
||||
|
||||
if (!state.awakeCalled) {
|
||||
InvokeLifecycleMethod(state, ScriptLifecycleMethod::Awake);
|
||||
state.awakeCalled = true;
|
||||
}
|
||||
|
||||
if (invokeEnableIfNeeded && !state.enabled && ShouldScriptRun(state)) {
|
||||
InvokeLifecycleMethod(state, ScriptLifecycleMethod::OnEnable);
|
||||
state.enabled = true;
|
||||
if (!state.startCalled) {
|
||||
state.startPending = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptEngine::InvokeLifecycleMethod(ScriptInstanceState& state, ScriptLifecycleMethod method, float deltaTime) {
|
||||
m_runtime->InvokeMethod(state.context, method, deltaTime);
|
||||
}
|
||||
|
||||
void ScriptEngine::StopTrackingScript(ScriptInstanceState& state, bool runtimeStopping) {
|
||||
if (state.enabled) {
|
||||
InvokeLifecycleMethod(state, ScriptLifecycleMethod::OnDisable);
|
||||
state.enabled = false;
|
||||
}
|
||||
|
||||
if (state.instanceCreated) {
|
||||
InvokeLifecycleMethod(state, ScriptLifecycleMethod::OnDestroy);
|
||||
m_runtime->DestroyScriptInstance(state.context);
|
||||
state.instanceCreated = false;
|
||||
}
|
||||
|
||||
state.startPending = false;
|
||||
|
||||
if (!runtimeStopping) {
|
||||
RemoveTrackedScriptComponent(state.context.component);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Scripting
|
||||
} // namespace XCEngine
|
||||
Reference in New Issue
Block a user