feat(scripting): add field model editing and defaults support
This commit is contained in:
@@ -1298,6 +1298,73 @@ std::vector<std::string> MonoScriptRuntime::GetScriptClassNames(const std::strin
|
||||
return classNames;
|
||||
}
|
||||
|
||||
bool MonoScriptRuntime::TryGetClassFieldMetadata(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
const std::string& className,
|
||||
std::vector<ScriptFieldMetadata>& outFields) const {
|
||||
outFields.clear();
|
||||
|
||||
const ClassMetadata* metadata = FindClassMetadata(assemblyName, namespaceName, className);
|
||||
if (!metadata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outFields.reserve(metadata->fields.size());
|
||||
for (const auto& [fieldName, fieldMetadata] : metadata->fields) {
|
||||
outFields.push_back(ScriptFieldMetadata{fieldName, fieldMetadata.type});
|
||||
}
|
||||
|
||||
std::sort(
|
||||
outFields.begin(),
|
||||
outFields.end(),
|
||||
[](const ScriptFieldMetadata& lhs, const ScriptFieldMetadata& rhs) {
|
||||
return lhs.name < rhs.name;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MonoScriptRuntime::TryGetClassFieldDefaultValues(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
const std::string& className,
|
||||
std::vector<ScriptFieldDefaultValue>& outFields) const {
|
||||
outFields.clear();
|
||||
|
||||
const ClassMetadata* metadata = FindClassMetadata(assemblyName, namespaceName, className);
|
||||
if (!metadata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetCurrentDomain();
|
||||
|
||||
MonoObject* instance = mono_object_new(m_appDomain, metadata->monoClass);
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mono_runtime_object_init(instance);
|
||||
|
||||
outFields.reserve(metadata->fields.size());
|
||||
for (const auto& [fieldName, fieldMetadata] : metadata->fields) {
|
||||
ScriptFieldValue value;
|
||||
if (!TryReadFieldValue(instance, fieldMetadata, value)) {
|
||||
outFields.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
outFields.push_back(ScriptFieldDefaultValue{fieldName, fieldMetadata.type, value});
|
||||
}
|
||||
|
||||
std::sort(
|
||||
outFields.begin(),
|
||||
outFields.end(),
|
||||
[](const ScriptFieldDefaultValue& lhs, const ScriptFieldDefaultValue& rhs) {
|
||||
return lhs.fieldName < rhs.fieldName;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MonoScriptRuntime::HasManagedInstance(const ScriptComponent* component) const {
|
||||
const InstanceData* instanceData = FindInstance(component);
|
||||
return instanceData != nullptr && GetManagedObject(*instanceData) != nullptr;
|
||||
@@ -1347,6 +1414,91 @@ void MonoScriptRuntime::OnRuntimeStop(Components::Scene* scene) {
|
||||
GetInternalCallDeltaTime() = 0.0f;
|
||||
}
|
||||
|
||||
bool MonoScriptRuntime::TrySetManagedFieldValue(
|
||||
const ScriptRuntimeContext& context,
|
||||
const std::string& fieldName,
|
||||
const ScriptFieldValue& value) {
|
||||
const InstanceData* instanceData = FindInstance(context);
|
||||
if (!instanceData || !instanceData->classMetadata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto metadataIt = instanceData->classMetadata->fields.find(fieldName);
|
||||
if (metadataIt == instanceData->classMetadata->fields.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsScriptFieldValueCompatible(metadataIt->second.type, value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MonoObject* instance = GetManagedObject(*instanceData);
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return TrySetFieldValue(instance, metadataIt->second, value);
|
||||
}
|
||||
|
||||
bool MonoScriptRuntime::TryGetManagedFieldValue(
|
||||
const ScriptRuntimeContext& context,
|
||||
const std::string& fieldName,
|
||||
ScriptFieldValue& outValue) const {
|
||||
const InstanceData* instanceData = FindInstance(context);
|
||||
if (!instanceData || !instanceData->classMetadata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto metadataIt = instanceData->classMetadata->fields.find(fieldName);
|
||||
if (metadataIt == instanceData->classMetadata->fields.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MonoObject* instance = GetManagedObject(*instanceData);
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return TryReadFieldValue(instance, metadataIt->second, outValue);
|
||||
}
|
||||
|
||||
void MonoScriptRuntime::SyncManagedFieldsToStorage(const ScriptRuntimeContext& context) {
|
||||
if (!context.component) {
|
||||
return;
|
||||
}
|
||||
|
||||
const InstanceData* instanceData = FindInstance(context);
|
||||
if (!instanceData || !instanceData->classMetadata) {
|
||||
return;
|
||||
}
|
||||
|
||||
MonoObject* instance = GetManagedObject(*instanceData);
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptFieldStorage& fieldStorage = context.component->GetFieldStorage();
|
||||
const std::vector<std::string> fieldNames = fieldStorage.GetFieldNames();
|
||||
for (const std::string& fieldName : fieldNames) {
|
||||
StoredScriptField* storedField = fieldStorage.FindField(fieldName);
|
||||
if (!storedField) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto metadataIt = instanceData->classMetadata->fields.find(fieldName);
|
||||
if (metadataIt == instanceData->classMetadata->fields.end() || storedField->type != metadataIt->second.type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ScriptFieldValue value;
|
||||
if (!TryReadFieldValue(instance, metadataIt->second, value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fieldStorage.SetFieldValue(fieldName, storedField->type, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool MonoScriptRuntime::CreateScriptInstance(const ScriptRuntimeContext& context) {
|
||||
if (!context.component) {
|
||||
SetError("Cannot create a managed script instance without a ScriptComponent.");
|
||||
|
||||
@@ -11,6 +11,54 @@ void NullScriptRuntime::OnRuntimeStop(Components::Scene* scene) {
|
||||
(void)scene;
|
||||
}
|
||||
|
||||
bool NullScriptRuntime::TryGetClassFieldMetadata(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
const std::string& className,
|
||||
std::vector<ScriptFieldMetadata>& outFields) const {
|
||||
(void)assemblyName;
|
||||
(void)namespaceName;
|
||||
(void)className;
|
||||
outFields.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NullScriptRuntime::TryGetClassFieldDefaultValues(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
const std::string& className,
|
||||
std::vector<ScriptFieldDefaultValue>& outFields) const {
|
||||
(void)assemblyName;
|
||||
(void)namespaceName;
|
||||
(void)className;
|
||||
outFields.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NullScriptRuntime::TrySetManagedFieldValue(
|
||||
const ScriptRuntimeContext& context,
|
||||
const std::string& fieldName,
|
||||
const ScriptFieldValue& value) {
|
||||
(void)context;
|
||||
(void)fieldName;
|
||||
(void)value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NullScriptRuntime::TryGetManagedFieldValue(
|
||||
const ScriptRuntimeContext& context,
|
||||
const std::string& fieldName,
|
||||
ScriptFieldValue& outValue) const {
|
||||
(void)context;
|
||||
(void)fieldName;
|
||||
(void)outValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
void NullScriptRuntime::SyncManagedFieldsToStorage(const ScriptRuntimeContext& context) {
|
||||
(void)context;
|
||||
}
|
||||
|
||||
bool NullScriptRuntime::CreateScriptInstance(const ScriptRuntimeContext& context) {
|
||||
return context.component != nullptr;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,51 @@
|
||||
namespace XCEngine {
|
||||
namespace Scripting {
|
||||
|
||||
namespace {
|
||||
|
||||
std::unordered_map<std::string, ScriptFieldValue> CollectClassDefaultValues(
|
||||
const IScriptRuntime* runtime,
|
||||
const ScriptComponent* component,
|
||||
ScriptFieldClassStatus classStatus) {
|
||||
std::unordered_map<std::string, ScriptFieldValue> defaultValues;
|
||||
if (!runtime || !component || classStatus != ScriptFieldClassStatus::Available || !component->HasScriptClass()) {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
std::vector<ScriptFieldDefaultValue> fields;
|
||||
if (!runtime->TryGetClassFieldDefaultValues(
|
||||
component->GetAssemblyName(),
|
||||
component->GetNamespaceName(),
|
||||
component->GetClassName(),
|
||||
fields)) {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
defaultValues.reserve(fields.size());
|
||||
for (const ScriptFieldDefaultValue& field : fields) {
|
||||
if (field.fieldName.empty() || !IsScriptFieldValueCompatible(field.type, field.value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
defaultValues.emplace(field.fieldName, field.value);
|
||||
}
|
||||
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
ScriptFieldValue ResolveScriptFieldDefaultValue(
|
||||
const ScriptFieldMetadata& metadata,
|
||||
const std::unordered_map<std::string, ScriptFieldValue>& defaultValues) {
|
||||
const auto it = defaultValues.find(metadata.name);
|
||||
if (it != defaultValues.end() && IsScriptFieldValueCompatible(metadata.type, it->second)) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return CreateDefaultScriptFieldValue(metadata.type);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ScriptEngine& ScriptEngine::Get() {
|
||||
static ScriptEngine instance;
|
||||
return instance;
|
||||
@@ -203,6 +248,346 @@ bool ScriptEngine::HasRuntimeInstance(const ScriptComponent* component) const {
|
||||
return state && state->instanceCreated;
|
||||
}
|
||||
|
||||
bool ScriptEngine::TrySetScriptFieldValue(
|
||||
ScriptComponent* component,
|
||||
const std::string& fieldName,
|
||||
ScriptFieldType type,
|
||||
const ScriptFieldValue& value) {
|
||||
if (!component || fieldName.empty() || !IsScriptFieldValueCompatible(type, value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (component->HasScriptClass()) {
|
||||
std::vector<ScriptFieldMetadata> fields;
|
||||
if (m_runtime->TryGetClassFieldMetadata(
|
||||
component->GetAssemblyName(),
|
||||
component->GetNamespaceName(),
|
||||
component->GetClassName(),
|
||||
fields)) {
|
||||
const auto fieldIt = std::find_if(
|
||||
fields.begin(),
|
||||
fields.end(),
|
||||
[&fieldName](const ScriptFieldMetadata& metadata) {
|
||||
return metadata.name == fieldName;
|
||||
});
|
||||
if (fieldIt == fields.end() || fieldIt->type != type) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScriptInstanceState* state = m_runtimeRunning ? FindState(component) : nullptr;
|
||||
if (state && state->instanceCreated && !m_runtime->TrySetManagedFieldValue(state->context, fieldName, value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return component->GetFieldStorage().SetFieldValue(fieldName, type, value);
|
||||
}
|
||||
|
||||
bool ScriptEngine::TryGetScriptFieldValue(
|
||||
const ScriptComponent* component,
|
||||
const std::string& fieldName,
|
||||
ScriptFieldValue& outValue) const {
|
||||
if (!component || fieldName.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ScriptInstanceState* state = m_runtimeRunning ? FindState(component) : nullptr;
|
||||
if (state && state->instanceCreated && m_runtime->TryGetManagedFieldValue(state->context, fieldName, outValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const StoredScriptField* storedField = component->GetFieldStorage().FindField(fieldName);
|
||||
if (!storedField) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outValue = storedField->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptEngine::ApplyScriptFieldWrites(
|
||||
ScriptComponent* component,
|
||||
const std::vector<ScriptFieldWriteRequest>& requests,
|
||||
std::vector<ScriptFieldWriteResult>& outResults) {
|
||||
outResults.clear();
|
||||
if (!component) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptFieldModel model;
|
||||
if (!TryGetScriptFieldModel(component, model)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, ScriptFieldValue> defaultValues =
|
||||
CollectClassDefaultValues(m_runtime, component, model.classStatus);
|
||||
|
||||
std::unordered_map<std::string, const ScriptFieldSnapshot*> fieldByName;
|
||||
fieldByName.reserve(model.fields.size());
|
||||
for (const ScriptFieldSnapshot& field : model.fields) {
|
||||
fieldByName.emplace(field.metadata.name, &field);
|
||||
}
|
||||
|
||||
outResults.reserve(requests.size());
|
||||
|
||||
bool allApplied = true;
|
||||
for (const ScriptFieldWriteRequest& request : requests) {
|
||||
ScriptFieldWriteResult result;
|
||||
result.fieldName = request.fieldName;
|
||||
result.type = request.type;
|
||||
|
||||
if (request.fieldName.empty()) {
|
||||
result.status = ScriptFieldWriteStatus::EmptyFieldName;
|
||||
allApplied = false;
|
||||
outResults.push_back(std::move(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IsScriptFieldValueCompatible(request.type, request.value)) {
|
||||
result.status = ScriptFieldWriteStatus::InvalidValue;
|
||||
allApplied = false;
|
||||
outResults.push_back(std::move(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto fieldIt = fieldByName.find(request.fieldName);
|
||||
if (fieldIt == fieldByName.end()) {
|
||||
result.status = ScriptFieldWriteStatus::UnknownField;
|
||||
allApplied = false;
|
||||
outResults.push_back(std::move(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
const ScriptFieldSnapshot& field = *fieldIt->second;
|
||||
if (field.metadata.type != request.type) {
|
||||
result.status = ScriptFieldWriteStatus::TypeMismatch;
|
||||
allApplied = false;
|
||||
outResults.push_back(std::move(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (model.classStatus == ScriptFieldClassStatus::Available && !field.declaredInClass) {
|
||||
result.status = ScriptFieldWriteStatus::StoredOnlyField;
|
||||
allApplied = false;
|
||||
outResults.push_back(std::move(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool applied = field.declaredInClass
|
||||
? TrySetScriptFieldValue(component, request.fieldName, request.type, request.value)
|
||||
: component->GetFieldStorage().SetFieldValue(request.fieldName, request.type, request.value);
|
||||
if (!applied) {
|
||||
result.status = ScriptFieldWriteStatus::ApplyFailed;
|
||||
allApplied = false;
|
||||
outResults.push_back(std::move(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
result.status = ScriptFieldWriteStatus::Applied;
|
||||
outResults.push_back(std::move(result));
|
||||
}
|
||||
|
||||
return allApplied;
|
||||
}
|
||||
|
||||
bool ScriptEngine::ClearScriptFieldOverrides(
|
||||
ScriptComponent* component,
|
||||
const std::vector<ScriptFieldClearRequest>& requests,
|
||||
std::vector<ScriptFieldClearResult>& outResults) {
|
||||
outResults.clear();
|
||||
if (!component) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptFieldModel model;
|
||||
if (!TryGetScriptFieldModel(component, model)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, ScriptFieldValue> defaultValues =
|
||||
CollectClassDefaultValues(m_runtime, component, model.classStatus);
|
||||
|
||||
std::unordered_map<std::string, const ScriptFieldSnapshot*> fieldByName;
|
||||
fieldByName.reserve(model.fields.size());
|
||||
for (const ScriptFieldSnapshot& field : model.fields) {
|
||||
fieldByName.emplace(field.metadata.name, &field);
|
||||
}
|
||||
|
||||
ScriptInstanceState* state = m_runtimeRunning ? FindState(component) : nullptr;
|
||||
const bool hasLiveInstance = state && state->instanceCreated;
|
||||
|
||||
outResults.reserve(requests.size());
|
||||
|
||||
bool allApplied = true;
|
||||
for (const ScriptFieldClearRequest& request : requests) {
|
||||
ScriptFieldClearResult result;
|
||||
result.fieldName = request.fieldName;
|
||||
|
||||
if (request.fieldName.empty()) {
|
||||
result.status = ScriptFieldClearStatus::EmptyFieldName;
|
||||
allApplied = false;
|
||||
outResults.push_back(std::move(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto fieldIt = fieldByName.find(request.fieldName);
|
||||
if (fieldIt == fieldByName.end()) {
|
||||
result.status = ScriptFieldClearStatus::UnknownField;
|
||||
allApplied = false;
|
||||
outResults.push_back(std::move(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
const ScriptFieldSnapshot& field = *fieldIt->second;
|
||||
|
||||
bool resetManagedValue = false;
|
||||
if (field.declaredInClass && hasLiveInstance) {
|
||||
if (!m_runtime->TrySetManagedFieldValue(
|
||||
state->context,
|
||||
field.metadata.name,
|
||||
ResolveScriptFieldDefaultValue(field.metadata, defaultValues))) {
|
||||
result.status = ScriptFieldClearStatus::ApplyFailed;
|
||||
allApplied = false;
|
||||
outResults.push_back(std::move(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
resetManagedValue = true;
|
||||
}
|
||||
|
||||
bool removedStoredValue = false;
|
||||
if (field.hasStoredValue) {
|
||||
removedStoredValue = component->GetFieldStorage().Remove(field.metadata.name);
|
||||
if (!removedStoredValue) {
|
||||
result.status = ScriptFieldClearStatus::ApplyFailed;
|
||||
allApplied = false;
|
||||
outResults.push_back(std::move(result));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!removedStoredValue && !resetManagedValue) {
|
||||
result.status = ScriptFieldClearStatus::NoValueToClear;
|
||||
allApplied = false;
|
||||
outResults.push_back(std::move(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
result.status = ScriptFieldClearStatus::Applied;
|
||||
outResults.push_back(std::move(result));
|
||||
}
|
||||
|
||||
return allApplied;
|
||||
}
|
||||
|
||||
bool ScriptEngine::TryGetScriptFieldModel(
|
||||
const ScriptComponent* component,
|
||||
ScriptFieldModel& outModel) const {
|
||||
outModel = ScriptFieldModel{};
|
||||
if (!component) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<ScriptFieldMetadata> metadataFields;
|
||||
if (!component->HasScriptClass()) {
|
||||
outModel.classStatus = ScriptFieldClassStatus::Unassigned;
|
||||
} else if (m_runtime->TryGetClassFieldMetadata(
|
||||
component->GetAssemblyName(),
|
||||
component->GetNamespaceName(),
|
||||
component->GetClassName(),
|
||||
metadataFields)) {
|
||||
outModel.classStatus = ScriptFieldClassStatus::Available;
|
||||
} else {
|
||||
outModel.classStatus = ScriptFieldClassStatus::Missing;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, ScriptFieldValue> defaultValues =
|
||||
CollectClassDefaultValues(m_runtime, component, outModel.classStatus);
|
||||
|
||||
const ScriptInstanceState* state = m_runtimeRunning ? FindState(component) : nullptr;
|
||||
std::unordered_map<std::string, size_t> fieldIndexByName;
|
||||
fieldIndexByName.reserve(metadataFields.size());
|
||||
|
||||
for (const ScriptFieldMetadata& metadata : metadataFields) {
|
||||
ScriptFieldSnapshot snapshot;
|
||||
snapshot.metadata = metadata;
|
||||
snapshot.declaredInClass = true;
|
||||
snapshot.hasDefaultValue = true;
|
||||
snapshot.defaultValue = ResolveScriptFieldDefaultValue(metadata, defaultValues);
|
||||
snapshot.value = snapshot.defaultValue;
|
||||
snapshot.valueSource = ScriptFieldValueSource::DefaultValue;
|
||||
|
||||
const StoredScriptField* storedField = component->GetFieldStorage().FindField(metadata.name);
|
||||
if (storedField) {
|
||||
snapshot.hasStoredValue = true;
|
||||
snapshot.storedType = storedField->type;
|
||||
snapshot.storedValue = storedField->value;
|
||||
if (storedField->type != metadata.type) {
|
||||
snapshot.issue = ScriptFieldIssue::TypeMismatch;
|
||||
}
|
||||
}
|
||||
|
||||
if (state && state->instanceCreated && m_runtime->TryGetManagedFieldValue(state->context, metadata.name, snapshot.value)) {
|
||||
snapshot.hasValue = true;
|
||||
snapshot.valueSource = ScriptFieldValueSource::ManagedValue;
|
||||
} else if (storedField && storedField->type == metadata.type) {
|
||||
snapshot.hasValue = true;
|
||||
snapshot.value = storedField->value;
|
||||
snapshot.valueSource = ScriptFieldValueSource::StoredValue;
|
||||
}
|
||||
|
||||
fieldIndexByName.emplace(metadata.name, outModel.fields.size());
|
||||
outModel.fields.push_back(std::move(snapshot));
|
||||
}
|
||||
|
||||
for (const std::string& fieldName : component->GetFieldStorage().GetFieldNames()) {
|
||||
const StoredScriptField* storedField = component->GetFieldStorage().FindField(fieldName);
|
||||
if (!storedField) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto fieldIndexIt = fieldIndexByName.find(fieldName);
|
||||
if (fieldIndexIt != fieldIndexByName.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ScriptFieldSnapshot snapshot;
|
||||
snapshot.metadata = ScriptFieldMetadata{fieldName, storedField->type};
|
||||
snapshot.hasValue = true;
|
||||
snapshot.value = storedField->value;
|
||||
snapshot.valueSource = ScriptFieldValueSource::StoredValue;
|
||||
snapshot.issue = ScriptFieldIssue::StoredOnly;
|
||||
snapshot.hasStoredValue = true;
|
||||
snapshot.storedType = storedField->type;
|
||||
snapshot.storedValue = storedField->value;
|
||||
outModel.fields.push_back(std::move(snapshot));
|
||||
}
|
||||
|
||||
if (outModel.classStatus != ScriptFieldClassStatus::Available) {
|
||||
std::sort(
|
||||
outModel.fields.begin(),
|
||||
outModel.fields.end(),
|
||||
[](const ScriptFieldSnapshot& lhs, const ScriptFieldSnapshot& rhs) {
|
||||
return lhs.metadata.name < rhs.metadata.name;
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptEngine::TryGetScriptFieldSnapshots(
|
||||
const ScriptComponent* component,
|
||||
std::vector<ScriptFieldSnapshot>& outFields) const {
|
||||
ScriptFieldModel model;
|
||||
if (!TryGetScriptFieldModel(component, model)) {
|
||||
outFields.clear();
|
||||
return false;
|
||||
}
|
||||
outFields = std::move(model.fields);
|
||||
return !outFields.empty();
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -372,6 +757,7 @@ bool ScriptEngine::EnsureScriptReady(ScriptInstanceState& state, bool invokeEnab
|
||||
|
||||
void ScriptEngine::InvokeLifecycleMethod(ScriptInstanceState& state, ScriptLifecycleMethod method, float deltaTime) {
|
||||
m_runtime->InvokeMethod(state.context, method, deltaTime);
|
||||
m_runtime->SyncManagedFieldsToStorage(state.context);
|
||||
}
|
||||
|
||||
void ScriptEngine::StopTrackingScript(ScriptInstanceState& state, bool runtimeStopping) {
|
||||
|
||||
Reference in New Issue
Block a user