Add script runtime lifecycle skeleton

This commit is contained in:
2026-03-26 20:45:41 +08:00
parent a78593e7e1
commit 9a2d77b81d
10 changed files with 813 additions and 0 deletions

View 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

View 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

View File

@@ -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;

View 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