Prepare script lifecycle and data layer

This commit is contained in:
2026-03-26 20:14:58 +08:00
parent 5ca5ca1f19
commit 0921f2a459
20 changed files with 1367 additions and 26 deletions

View File

@@ -34,16 +34,7 @@ public:
Scene* GetScene() const;
bool IsEnabled() const { return m_enabled; }
void SetEnabled(bool enabled) {
if (m_enabled != enabled) {
m_enabled = enabled;
if (m_enabled) {
OnEnable();
} else {
OnDisable();
}
}
}
void SetEnabled(bool enabled);
protected:
Component() = default;
@@ -58,4 +49,4 @@ protected:
};
} // namespace Components
} // namespace XCEngine
} // namespace XCEngine

View File

@@ -208,10 +208,15 @@ public:
void Deserialize(std::istream& is);
private:
void NotifyComponentsBecameActive();
void NotifyComponentsBecameInactive();
void PropagateActiveInHierarchyChange(bool oldParentActiveInHierarchy, bool newParentActiveInHierarchy);
ID m_id = INVALID_ID;
uint64_t m_uuid = 0;
std::string m_name;
bool m_activeSelf = true;
bool m_started = false;
GameObject* m_parent = nullptr;
std::vector<GameObject*> m_children;

View File

@@ -0,0 +1,51 @@
#pragma once
#include <XCEngine/Components/Component.h>
#include <XCEngine/Scripting/ScriptFieldStorage.h>
#include <cstdint>
#include <string>
namespace XCEngine {
namespace Scripting {
class ScriptComponent : public Components::Component {
public:
ScriptComponent();
std::string GetName() const override { return "ScriptComponent"; }
uint64_t GetScriptComponentUUID() const { return m_scriptComponentUUID; }
const std::string& GetAssemblyName() const { return m_assemblyName; }
void SetAssemblyName(const std::string& assemblyName) { m_assemblyName = assemblyName; }
const std::string& GetNamespaceName() const { return m_namespaceName; }
void SetNamespaceName(const std::string& namespaceName) { m_namespaceName = namespaceName; }
const std::string& GetClassName() const { return m_className; }
void SetClassName(const std::string& className) { m_className = className; }
void SetScriptClass(const std::string& namespaceName, const std::string& className);
void SetScriptClass(const std::string& assemblyName, const std::string& namespaceName, const std::string& className);
bool HasScriptClass() const { return !m_className.empty(); }
std::string GetFullClassName() const;
ScriptFieldStorage& GetFieldStorage() { return m_fieldStorage; }
const ScriptFieldStorage& GetFieldStorage() const { return m_fieldStorage; }
void SetFieldStorage(const ScriptFieldStorage& fieldStorage) { m_fieldStorage = fieldStorage; }
void Serialize(std::ostream& os) const override;
void Deserialize(std::istream& is) override;
private:
uint64_t m_scriptComponentUUID = 0;
std::string m_assemblyName = "GameScripts";
std::string m_namespaceName;
std::string m_className;
ScriptFieldStorage m_fieldStorage;
};
} // namespace Scripting
} // namespace XCEngine

View File

@@ -0,0 +1,65 @@
#pragma once
#include <XCEngine/Core/Math/Vector2.h>
#include <XCEngine/Core/Math/Vector3.h>
#include <XCEngine/Core/Math/Vector4.h>
#include <cstdint>
#include <string>
#include <variant>
namespace XCEngine {
namespace Scripting {
enum class ScriptFieldType {
None = 0,
Float,
Double,
Bool,
Int32,
UInt64,
String,
Vector2,
Vector3,
Vector4,
GameObject
};
struct GameObjectReference {
uint64_t gameObjectUUID = 0;
bool operator==(const GameObjectReference& other) const {
return gameObjectUUID == other.gameObjectUUID;
}
bool operator!=(const GameObjectReference& other) const {
return !(*this == other);
}
};
using ScriptFieldValue = std::variant<
std::monostate,
float,
double,
bool,
int32_t,
uint64_t,
std::string,
Math::Vector2,
Math::Vector3,
Math::Vector4,
GameObjectReference>;
std::string ScriptFieldTypeToString(ScriptFieldType type);
bool TryParseScriptFieldType(const std::string& value, ScriptFieldType& outType);
bool IsScriptFieldValueCompatible(ScriptFieldType type, const ScriptFieldValue& value);
ScriptFieldValue CreateDefaultScriptFieldValue(ScriptFieldType type);
std::string SerializeScriptFieldValue(ScriptFieldType type, const ScriptFieldValue& value);
bool TryDeserializeScriptFieldValue(ScriptFieldType type, const std::string& value, ScriptFieldValue& outValue);
std::string EscapeScriptString(const std::string& value);
std::string UnescapeScriptString(const std::string& value);
} // namespace Scripting
} // namespace XCEngine

View File

@@ -0,0 +1,124 @@
#pragma once
#include <XCEngine/Scripting/ScriptField.h>
#include <istream>
#include <ostream>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <vector>
namespace XCEngine {
namespace Scripting {
struct StoredScriptField {
ScriptFieldType type = ScriptFieldType::None;
ScriptFieldValue value = std::monostate{};
};
template<typename T>
struct ScriptFieldTypeResolver;
template<>
struct ScriptFieldTypeResolver<float> {
static constexpr ScriptFieldType value = ScriptFieldType::Float;
};
template<>
struct ScriptFieldTypeResolver<double> {
static constexpr ScriptFieldType value = ScriptFieldType::Double;
};
template<>
struct ScriptFieldTypeResolver<bool> {
static constexpr ScriptFieldType value = ScriptFieldType::Bool;
};
template<>
struct ScriptFieldTypeResolver<int32_t> {
static constexpr ScriptFieldType value = ScriptFieldType::Int32;
};
template<>
struct ScriptFieldTypeResolver<uint64_t> {
static constexpr ScriptFieldType value = ScriptFieldType::UInt64;
};
template<>
struct ScriptFieldTypeResolver<std::string> {
static constexpr ScriptFieldType value = ScriptFieldType::String;
};
template<>
struct ScriptFieldTypeResolver<Math::Vector2> {
static constexpr ScriptFieldType value = ScriptFieldType::Vector2;
};
template<>
struct ScriptFieldTypeResolver<Math::Vector3> {
static constexpr ScriptFieldType value = ScriptFieldType::Vector3;
};
template<>
struct ScriptFieldTypeResolver<Math::Vector4> {
static constexpr ScriptFieldType value = ScriptFieldType::Vector4;
};
template<>
struct ScriptFieldTypeResolver<GameObjectReference> {
static constexpr ScriptFieldType value = ScriptFieldType::GameObject;
};
class ScriptFieldStorage {
public:
template<typename T>
bool SetFieldValue(const std::string& fieldName, const T& value) {
using ValueType = std::decay_t<T>;
return SetFieldValue(fieldName, ScriptFieldTypeResolver<ValueType>::value, ScriptFieldValue(ValueType(value)));
}
bool SetFieldValue(const std::string& fieldName, const char* value) {
return SetFieldValue<std::string>(fieldName, value ? std::string(value) : std::string());
}
bool SetFieldValue(const std::string& fieldName, ScriptFieldType type, const ScriptFieldValue& value);
template<typename T>
bool TryGetFieldValue(const std::string& fieldName, T& outValue) const {
const StoredScriptField* field = FindField(fieldName);
if (!field) {
return false;
}
const auto* storedValue = std::get_if<std::decay_t<T>>(&field->value);
if (!storedValue) {
return false;
}
outValue = *storedValue;
return true;
}
const StoredScriptField* FindField(const std::string& fieldName) const;
StoredScriptField* FindField(const std::string& fieldName);
bool Contains(const std::string& fieldName) const;
bool Remove(const std::string& fieldName);
void Clear();
size_t GetFieldCount() const { return m_fields.size(); }
std::vector<std::string> GetFieldNames() const;
std::string SerializeToString() const;
void DeserializeFromString(const std::string& data);
void Serialize(std::ostream& os) const;
void Deserialize(std::istream& is);
private:
std::unordered_map<std::string, StoredScriptField> m_fields;
};
} // namespace Scripting
} // namespace XCEngine