feat(scripting): add field model editing and defaults support
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/Scripting/ScriptField.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
|
||||
@@ -39,6 +43,29 @@ public:
|
||||
virtual void OnRuntimeStart(Components::Scene* scene) = 0;
|
||||
virtual void OnRuntimeStop(Components::Scene* scene) = 0;
|
||||
|
||||
virtual bool TryGetClassFieldMetadata(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
const std::string& className,
|
||||
std::vector<ScriptFieldMetadata>& outFields) const = 0;
|
||||
virtual bool TryGetClassFieldDefaultValues(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
const std::string& className,
|
||||
std::vector<ScriptFieldDefaultValue>& outFields) const = 0;
|
||||
|
||||
virtual bool TrySetManagedFieldValue(
|
||||
const ScriptRuntimeContext& context,
|
||||
const std::string& fieldName,
|
||||
const ScriptFieldValue& value) = 0;
|
||||
|
||||
virtual bool TryGetManagedFieldValue(
|
||||
const ScriptRuntimeContext& context,
|
||||
const std::string& fieldName,
|
||||
ScriptFieldValue& outValue) const = 0;
|
||||
|
||||
virtual void SyncManagedFieldsToStorage(const ScriptRuntimeContext& context) = 0;
|
||||
|
||||
virtual bool CreateScriptInstance(const ScriptRuntimeContext& context) = 0;
|
||||
virtual void DestroyScriptInstance(const ScriptRuntimeContext& context) = 0;
|
||||
|
||||
|
||||
@@ -50,6 +50,16 @@ public:
|
||||
const std::string& namespaceName,
|
||||
const std::string& className) const;
|
||||
std::vector<std::string> GetScriptClassNames(const std::string& assemblyName = std::string()) const;
|
||||
bool TryGetClassFieldMetadata(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
const std::string& className,
|
||||
std::vector<ScriptFieldMetadata>& outFields) const override;
|
||||
bool TryGetClassFieldDefaultValues(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
const std::string& className,
|
||||
std::vector<ScriptFieldDefaultValue>& outFields) const override;
|
||||
|
||||
bool HasManagedInstance(const ScriptComponent* component) const;
|
||||
size_t GetManagedInstanceCount() const { return m_instances.size(); }
|
||||
@@ -79,6 +89,15 @@ public:
|
||||
|
||||
void OnRuntimeStart(Components::Scene* scene) override;
|
||||
void OnRuntimeStop(Components::Scene* scene) override;
|
||||
bool TrySetManagedFieldValue(
|
||||
const ScriptRuntimeContext& context,
|
||||
const std::string& fieldName,
|
||||
const ScriptFieldValue& value) override;
|
||||
bool TryGetManagedFieldValue(
|
||||
const ScriptRuntimeContext& context,
|
||||
const std::string& fieldName,
|
||||
ScriptFieldValue& outValue) const override;
|
||||
void SyncManagedFieldsToStorage(const ScriptRuntimeContext& context) override;
|
||||
bool CreateScriptInstance(const ScriptRuntimeContext& context) override;
|
||||
void DestroyScriptInstance(const ScriptRuntimeContext& context) override;
|
||||
void InvokeMethod(const ScriptRuntimeContext& context, ScriptLifecycleMethod method, float deltaTime) override;
|
||||
|
||||
@@ -9,6 +9,25 @@ class NullScriptRuntime : public IScriptRuntime {
|
||||
public:
|
||||
void OnRuntimeStart(Components::Scene* scene) override;
|
||||
void OnRuntimeStop(Components::Scene* scene) override;
|
||||
bool TryGetClassFieldMetadata(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
const std::string& className,
|
||||
std::vector<ScriptFieldMetadata>& outFields) const override;
|
||||
bool TryGetClassFieldDefaultValues(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
const std::string& className,
|
||||
std::vector<ScriptFieldDefaultValue>& outFields) const override;
|
||||
bool TrySetManagedFieldValue(
|
||||
const ScriptRuntimeContext& context,
|
||||
const std::string& fieldName,
|
||||
const ScriptFieldValue& value) override;
|
||||
bool TryGetManagedFieldValue(
|
||||
const ScriptRuntimeContext& context,
|
||||
const std::string& fieldName,
|
||||
ScriptFieldValue& outValue) const override;
|
||||
void SyncManagedFieldsToStorage(const ScriptRuntimeContext& context) override;
|
||||
|
||||
bool CreateScriptInstance(const ScriptRuntimeContext& context) override;
|
||||
void DestroyScriptInstance(const ScriptRuntimeContext& context) override;
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
#include <XCEngine/Scripting/IScriptRuntime.h>
|
||||
#include <XCEngine/Scripting/NullScriptRuntime.h>
|
||||
#include <XCEngine/Scripting/ScriptFieldStorage.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@@ -37,6 +40,60 @@ public:
|
||||
bool HasTrackedScriptComponent(const ScriptComponent* component) const;
|
||||
bool HasRuntimeInstance(const ScriptComponent* component) const;
|
||||
size_t GetTrackedScriptCount() const { return m_scriptOrder.size(); }
|
||||
bool TrySetScriptFieldValue(
|
||||
ScriptComponent* component,
|
||||
const std::string& fieldName,
|
||||
ScriptFieldType type,
|
||||
const ScriptFieldValue& value);
|
||||
bool TryGetScriptFieldValue(
|
||||
const ScriptComponent* component,
|
||||
const std::string& fieldName,
|
||||
ScriptFieldValue& outValue) const;
|
||||
bool ApplyScriptFieldWrites(
|
||||
ScriptComponent* component,
|
||||
const std::vector<ScriptFieldWriteRequest>& requests,
|
||||
std::vector<ScriptFieldWriteResult>& outResults);
|
||||
bool ClearScriptFieldOverrides(
|
||||
ScriptComponent* component,
|
||||
const std::vector<ScriptFieldClearRequest>& requests,
|
||||
std::vector<ScriptFieldClearResult>& outResults);
|
||||
bool TryGetScriptFieldModel(
|
||||
const ScriptComponent* component,
|
||||
ScriptFieldModel& outModel) const;
|
||||
bool TryGetScriptFieldSnapshots(
|
||||
const ScriptComponent* component,
|
||||
std::vector<ScriptFieldSnapshot>& outFields) const;
|
||||
|
||||
template<typename T>
|
||||
bool TrySetScriptFieldValue(ScriptComponent* component, const std::string& fieldName, const T& value) {
|
||||
using ValueType = std::decay_t<T>;
|
||||
return TrySetScriptFieldValue(
|
||||
component,
|
||||
fieldName,
|
||||
ScriptFieldTypeResolver<ValueType>::value,
|
||||
ScriptFieldValue(ValueType(value)));
|
||||
}
|
||||
|
||||
bool TrySetScriptFieldValue(ScriptComponent* component, const std::string& fieldName, const char* value) {
|
||||
return TrySetScriptFieldValue(component, fieldName, std::string(value ? value : ""));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool TryGetScriptFieldValue(const ScriptComponent* component, const std::string& fieldName, T& outValue) const {
|
||||
ScriptFieldValue value;
|
||||
if (!TryGetScriptFieldValue(component, fieldName, value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
using ValueType = std::decay_t<T>;
|
||||
const ValueType* typedValue = std::get_if<ValueType>(&value);
|
||||
if (!typedValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outValue = *typedValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
struct ScriptInstanceKey {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Scripting {
|
||||
@@ -37,6 +38,56 @@ struct GameObjectReference {
|
||||
}
|
||||
};
|
||||
|
||||
struct ScriptFieldMetadata {
|
||||
std::string name;
|
||||
ScriptFieldType type = ScriptFieldType::None;
|
||||
|
||||
bool operator==(const ScriptFieldMetadata& other) const {
|
||||
return name == other.name && type == other.type;
|
||||
}
|
||||
|
||||
bool operator!=(const ScriptFieldMetadata& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
enum class ScriptFieldClassStatus {
|
||||
Unassigned = 0,
|
||||
Available,
|
||||
Missing
|
||||
};
|
||||
|
||||
enum class ScriptFieldValueSource {
|
||||
None = 0,
|
||||
DefaultValue,
|
||||
StoredValue,
|
||||
ManagedValue
|
||||
};
|
||||
|
||||
enum class ScriptFieldIssue {
|
||||
None = 0,
|
||||
StoredOnly,
|
||||
TypeMismatch
|
||||
};
|
||||
|
||||
enum class ScriptFieldWriteStatus {
|
||||
Applied = 0,
|
||||
EmptyFieldName,
|
||||
UnknownField,
|
||||
InvalidValue,
|
||||
TypeMismatch,
|
||||
StoredOnlyField,
|
||||
ApplyFailed
|
||||
};
|
||||
|
||||
enum class ScriptFieldClearStatus {
|
||||
Applied = 0,
|
||||
EmptyFieldName,
|
||||
UnknownField,
|
||||
NoValueToClear,
|
||||
ApplyFailed
|
||||
};
|
||||
|
||||
using ScriptFieldValue = std::variant<
|
||||
std::monostate,
|
||||
float,
|
||||
@@ -50,6 +101,80 @@ using ScriptFieldValue = std::variant<
|
||||
Math::Vector4,
|
||||
GameObjectReference>;
|
||||
|
||||
struct ScriptFieldDefaultValue {
|
||||
std::string fieldName;
|
||||
ScriptFieldType type = ScriptFieldType::None;
|
||||
ScriptFieldValue value = std::monostate{};
|
||||
|
||||
bool operator==(const ScriptFieldDefaultValue& other) const {
|
||||
return fieldName == other.fieldName
|
||||
&& type == other.type
|
||||
&& value == other.value;
|
||||
}
|
||||
|
||||
bool operator!=(const ScriptFieldDefaultValue& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
struct ScriptFieldSnapshot {
|
||||
ScriptFieldMetadata metadata;
|
||||
bool declaredInClass = false;
|
||||
bool hasDefaultValue = false;
|
||||
ScriptFieldValue defaultValue = std::monostate{};
|
||||
bool hasValue = false;
|
||||
ScriptFieldValue value = std::monostate{};
|
||||
ScriptFieldValueSource valueSource = ScriptFieldValueSource::None;
|
||||
ScriptFieldIssue issue = ScriptFieldIssue::None;
|
||||
bool hasStoredValue = false;
|
||||
ScriptFieldType storedType = ScriptFieldType::None;
|
||||
ScriptFieldValue storedValue = std::monostate{};
|
||||
|
||||
bool operator==(const ScriptFieldSnapshot& other) const {
|
||||
return metadata == other.metadata
|
||||
&& declaredInClass == other.declaredInClass
|
||||
&& hasDefaultValue == other.hasDefaultValue
|
||||
&& defaultValue == other.defaultValue
|
||||
&& hasValue == other.hasValue
|
||||
&& value == other.value
|
||||
&& valueSource == other.valueSource
|
||||
&& issue == other.issue
|
||||
&& hasStoredValue == other.hasStoredValue
|
||||
&& storedType == other.storedType
|
||||
&& storedValue == other.storedValue;
|
||||
}
|
||||
|
||||
bool operator!=(const ScriptFieldSnapshot& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
struct ScriptFieldModel {
|
||||
ScriptFieldClassStatus classStatus = ScriptFieldClassStatus::Unassigned;
|
||||
std::vector<ScriptFieldSnapshot> fields;
|
||||
};
|
||||
|
||||
struct ScriptFieldWriteRequest {
|
||||
std::string fieldName;
|
||||
ScriptFieldType type = ScriptFieldType::None;
|
||||
ScriptFieldValue value = std::monostate{};
|
||||
};
|
||||
|
||||
struct ScriptFieldWriteResult {
|
||||
std::string fieldName;
|
||||
ScriptFieldType type = ScriptFieldType::None;
|
||||
ScriptFieldWriteStatus status = ScriptFieldWriteStatus::ApplyFailed;
|
||||
};
|
||||
|
||||
struct ScriptFieldClearRequest {
|
||||
std::string fieldName;
|
||||
};
|
||||
|
||||
struct ScriptFieldClearResult {
|
||||
std::string fieldName;
|
||||
ScriptFieldClearStatus status = ScriptFieldClearStatus::ApplyFailed;
|
||||
};
|
||||
|
||||
std::string ScriptFieldTypeToString(ScriptFieldType type);
|
||||
bool TryParseScriptFieldType(const std::string& value, ScriptFieldType& outType);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user