Prepare script lifecycle and data layer
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
51
engine/include/XCEngine/Scripting/ScriptComponent.h
Normal file
51
engine/include/XCEngine/Scripting/ScriptComponent.h
Normal 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
|
||||
65
engine/include/XCEngine/Scripting/ScriptField.h
Normal file
65
engine/include/XCEngine/Scripting/ScriptField.h
Normal 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
|
||||
124
engine/include/XCEngine/Scripting/ScriptFieldStorage.h
Normal file
124
engine/include/XCEngine/Scripting/ScriptFieldStorage.h
Normal 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
|
||||
Reference in New Issue
Block a user