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.");
|
||||
|
||||
Reference in New Issue
Block a user