feat(scripting): add field model editing and defaults support

This commit is contained in:
2026-03-28 15:09:42 +08:00
parent 4717b595c4
commit 14c7fd69ec
13 changed files with 2113 additions and 0 deletions

View File

@@ -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.");