Fix inherited C# scene not inheriting parent's fields (3.2)
When a child scene inherits a parent scene with a C# root node, the parent scene's export variables appear to assume values set in the parent scene, in the child scene's Inspector. However, when the child scene is played, the parent scene's export variables assume default values. When a node is created, it inherits its parent C# script's fields from the map CSharpScriptInstance::script->member_info. However this map was not initialized outside the editor, and this commit ensured it is. This fixes issues #36480 and #37581. This is a manual backport of PR #38638 for 3.2.
This commit is contained in:
parent
d784cb23ec
commit
23d51ac325
|
@ -2315,37 +2315,46 @@ void CSharpScript::_update_member_info_no_exports() {
|
||||||
bool CSharpScript::_update_exports() {
|
bool CSharpScript::_update_exports() {
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
if (!Engine::get_singleton()->is_editor_hint())
|
bool is_editor = Engine::get_singleton()->is_editor_hint();
|
||||||
return false;
|
if (is_editor)
|
||||||
|
|
||||||
placeholder_fallback_enabled = true; // until proven otherwise
|
placeholder_fallback_enabled = true; // until proven otherwise
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!valid)
|
if (!valid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
if (exports_invalidated) {
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (!is_editor || exports_invalidated)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
GD_MONO_SCOPE_THREAD_ATTACH;
|
GD_MONO_SCOPE_THREAD_ATTACH;
|
||||||
|
|
||||||
exports_invalidated = false;
|
|
||||||
|
|
||||||
changed = true;
|
changed = true;
|
||||||
|
|
||||||
member_info.clear();
|
member_info.clear();
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
MonoObject *tmp_object = nullptr;
|
||||||
|
Object *tmp_native = nullptr;
|
||||||
|
uint32_t tmp_pinned_gchandle = 0;
|
||||||
|
|
||||||
|
if (is_editor) {
|
||||||
|
exports_invalidated = false;
|
||||||
|
|
||||||
exported_members_cache.clear();
|
exported_members_cache.clear();
|
||||||
exported_members_defval_cache.clear();
|
exported_members_defval_cache.clear();
|
||||||
|
|
||||||
// Here we create a temporary managed instance of the class to get the initial values
|
// Here we create a temporary managed instance of the class to get the initial values
|
||||||
|
tmp_object = mono_object_new(mono_domain_get(), script_class->get_mono_ptr());
|
||||||
MonoObject *tmp_object = mono_object_new(mono_domain_get(), script_class->get_mono_ptr());
|
|
||||||
|
|
||||||
if (!tmp_object) {
|
if (!tmp_object) {
|
||||||
ERR_PRINT("Failed to allocate temporary MonoObject.");
|
ERR_PRINT("Failed to allocate temporary MonoObject.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t tmp_pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(tmp_object); // pin it (not sure if needed)
|
tmp_pinned_gchandle = MonoGCHandle::new_strong_handle_pinned(tmp_object); // pin it (not sure if needed)
|
||||||
|
|
||||||
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
|
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
|
||||||
|
|
||||||
|
@ -2355,7 +2364,7 @@ bool CSharpScript::_update_exports() {
|
||||||
MonoException *ctor_exc = NULL;
|
MonoException *ctor_exc = NULL;
|
||||||
ctor->invoke(tmp_object, NULL, &ctor_exc);
|
ctor->invoke(tmp_object, NULL, &ctor_exc);
|
||||||
|
|
||||||
Object *tmp_native = GDMonoMarshal::unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(tmp_object));
|
tmp_native = GDMonoMarshal::unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(tmp_object));
|
||||||
|
|
||||||
if (ctor_exc) {
|
if (ctor_exc) {
|
||||||
// TODO: Should we free 'tmp_native' if the exception was thrown after its creation?
|
// TODO: Should we free 'tmp_native' if the exception was thrown after its creation?
|
||||||
|
@ -2367,6 +2376,8 @@ bool CSharpScript::_update_exports() {
|
||||||
GDMonoUtils::debug_print_unhandled_exception(ctor_exc);
|
GDMonoUtils::debug_print_unhandled_exception(ctor_exc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
GDMonoClass *top = script_class;
|
GDMonoClass *top = script_class;
|
||||||
|
|
||||||
|
@ -2382,16 +2393,16 @@ bool CSharpScript::_update_exports() {
|
||||||
if (_get_member_export(field, /* inspect export: */ true, prop_info, exported)) {
|
if (_get_member_export(field, /* inspect export: */ true, prop_info, exported)) {
|
||||||
StringName member_name = field->get_name();
|
StringName member_name = field->get_name();
|
||||||
|
|
||||||
if (exported) {
|
|
||||||
member_info[member_name] = prop_info;
|
member_info[member_name] = prop_info;
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (is_editor && exported) {
|
||||||
exported_members_cache.push_front(prop_info);
|
exported_members_cache.push_front(prop_info);
|
||||||
|
|
||||||
if (tmp_object) {
|
if (tmp_object) {
|
||||||
exported_members_defval_cache[member_name] = GDMonoMarshal::mono_object_to_variant(field->get_value(tmp_object));
|
exported_members_defval_cache[member_name] = GDMonoMarshal::mono_object_to_variant(field->get_value(tmp_object));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
member_info[member_name] = prop_info;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2403,8 +2414,9 @@ bool CSharpScript::_update_exports() {
|
||||||
if (_get_member_export(property, /* inspect export: */ true, prop_info, exported)) {
|
if (_get_member_export(property, /* inspect export: */ true, prop_info, exported)) {
|
||||||
StringName member_name = property->get_name();
|
StringName member_name = property->get_name();
|
||||||
|
|
||||||
if (exported) {
|
|
||||||
member_info[member_name] = prop_info;
|
member_info[member_name] = prop_info;
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (is_editor && exported) {
|
||||||
exported_members_cache.push_front(prop_info);
|
exported_members_cache.push_front(prop_info);
|
||||||
|
|
||||||
if (tmp_object) {
|
if (tmp_object) {
|
||||||
|
@ -2417,15 +2429,16 @@ bool CSharpScript::_update_exports() {
|
||||||
exported_members_defval_cache[member_name] = GDMonoMarshal::mono_object_to_variant(ret);
|
exported_members_defval_cache[member_name] = GDMonoMarshal::mono_object_to_variant(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
member_info[member_name] = prop_info;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
top = top->get_parent_class();
|
top = top->get_parent_class();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (is_editor) {
|
||||||
// Need to check this here, before disposal
|
// Need to check this here, before disposal
|
||||||
bool base_ref = Object::cast_to<Reference>(tmp_native) != NULL;
|
bool base_ref = Object::cast_to<Reference>(tmp_native) != NULL;
|
||||||
|
|
||||||
|
@ -2451,7 +2464,11 @@ bool CSharpScript::_update_exports() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (is_editor) {
|
||||||
placeholder_fallback_enabled = false;
|
placeholder_fallback_enabled = false;
|
||||||
|
|
||||||
if (placeholders.size()) {
|
if (placeholders.size()) {
|
||||||
|
@ -2464,10 +2481,10 @@ bool CSharpScript::_update_exports() {
|
||||||
E->get()->update(propnames, values);
|
E->get()->update(propnames, values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class) {
|
void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class) {
|
||||||
|
@ -2538,7 +2555,6 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Ve
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
|
||||||
/**
|
/**
|
||||||
* Returns false if there was an error, otherwise true.
|
* Returns false if there was an error, otherwise true.
|
||||||
* If there was an error, r_prop_info and r_exported are not assigned any value.
|
* If there was an error, r_prop_info and r_exported are not assigned any value.
|
||||||
|
@ -2552,8 +2568,10 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
|
||||||
(m_member->get_enclosing_class()->get_full_name() + "." + (String)m_member->get_name())
|
(m_member->get_enclosing_class()->get_full_name() + "." + (String)m_member->get_name())
|
||||||
|
|
||||||
if (p_member->is_static()) {
|
if (p_member->is_static()) {
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
if (p_member->has_attribute(CACHED_CLASS(ExportAttribute)))
|
if (p_member->has_attribute(CACHED_CLASS(ExportAttribute)))
|
||||||
ERR_PRINTS("Cannot export member because it is static: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
|
ERR_PRINTS("Cannot export member because it is static: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2575,13 +2593,17 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
|
||||||
if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) {
|
if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) {
|
||||||
GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member);
|
GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member);
|
||||||
if (!property->has_getter()) {
|
if (!property->has_getter()) {
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
if (exported)
|
if (exported)
|
||||||
ERR_PRINTS("Read-only property cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
|
ERR_PRINTS("Read-only property cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!property->has_setter()) {
|
if (!property->has_setter()) {
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
if (exported)
|
if (exported)
|
||||||
ERR_PRINTS("Write-only property (without getter) cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
|
ERR_PRINTS("Write-only property (without getter) cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2600,10 +2622,13 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
|
||||||
String hint_string;
|
String hint_string;
|
||||||
|
|
||||||
if (variant_type == Variant::NIL) {
|
if (variant_type == Variant::NIL) {
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
ERR_PRINTS("Unknown exported member type: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
|
ERR_PRINTS("Unknown exported member type: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
int hint_res = _try_get_member_export_hint(p_member, type, variant_type, /* allow_generics: */ true, hint, hint_string);
|
int hint_res = _try_get_member_export_hint(p_member, type, variant_type, /* allow_generics: */ true, hint, hint_string);
|
||||||
|
|
||||||
ERR_FAIL_COND_V_MSG(hint_res == -1, false,
|
ERR_FAIL_COND_V_MSG(hint_res == -1, false,
|
||||||
|
@ -2614,6 +2639,7 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
|
||||||
hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
|
hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
|
||||||
hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
|
hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
r_prop_info = PropertyInfo(variant_type, (String)p_member->get_name(), hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE);
|
r_prop_info = PropertyInfo(variant_type, (String)p_member->get_name(), hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE);
|
||||||
r_exported = true;
|
r_exported = true;
|
||||||
|
@ -2623,6 +2649,7 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
|
||||||
#undef MEMBER_FULL_QUALIFIED_NAME
|
#undef MEMBER_FULL_QUALIFIED_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string) {
|
int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string) {
|
||||||
|
|
||||||
GD_MONO_ASSERT_THREAD_ATTACHED;
|
GD_MONO_ASSERT_THREAD_ATTACHED;
|
||||||
|
|
|
@ -133,8 +133,8 @@ class CSharpScript : public Script {
|
||||||
bool _get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms);
|
bool _get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms);
|
||||||
|
|
||||||
bool _update_exports();
|
bool _update_exports();
|
||||||
#ifdef TOOLS_ENABLED
|
|
||||||
bool _get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported);
|
bool _get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported);
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
static int _try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string);
|
static int _try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue