Inherited C# scene not inheriting parent's fields

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 commit is contained in:
pepegadeveloper123 2020-05-11 03:20:11 +09:00
parent 6a0473bcc2
commit 4e00d8520d
2 changed files with 106 additions and 80 deletions

View File

@ -2421,37 +2421,45 @@ void CSharpScript::_update_member_info_no_exports() {
bool CSharpScript::_update_exports() {
#ifdef TOOLS_ENABLED
if (!Engine::get_singleton()->is_editor_hint())
return false;
bool is_editor = Engine::get_singleton()->is_editor_hint();
if (is_editor)
placeholder_fallback_enabled = true; // until proven otherwise
#endif
if (!valid)
return false;
bool changed = false;
if (exports_invalidated) {
#ifdef TOOLS_ENABLED
if (exports_invalidated)
#endif
{
GD_MONO_SCOPE_THREAD_ATTACH;
exports_invalidated = false;
changed = true;
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_defval_cache.clear();
// Here we create a temporary managed instance of the class to get the initial values
MonoObject *tmp_object = mono_object_new(mono_domain_get(), script_class->get_mono_ptr());
tmp_object = mono_object_new(mono_domain_get(), script_class->get_mono_ptr());
if (!tmp_object) {
ERR_PRINT("Failed to allocate temporary MonoObject.");
return false;
}
uint32_t tmp_pinned_gchandle = GDMonoUtils::new_strong_gchandle_pinned(tmp_object); // pin it (not sure if needed)
tmp_pinned_gchandle = GDMonoUtils::new_strong_gchandle_pinned(tmp_object); // pin it (not sure if needed)
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
@ -2461,7 +2469,7 @@ bool CSharpScript::_update_exports() {
MonoException *ctor_exc = nullptr;
ctor->invoke(tmp_object, nullptr, &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) {
// TODO: Should we free 'tmp_native' if the exception was thrown after its creation?
@ -2473,6 +2481,8 @@ bool CSharpScript::_update_exports() {
GDMonoUtils::debug_print_unhandled_exception(ctor_exc);
return false;
}
}
#endif
GDMonoClass *top = script_class;
@ -2488,16 +2498,16 @@ bool CSharpScript::_update_exports() {
if (_get_member_export(field, /* inspect export: */ true, prop_info, exported)) {
StringName member_name = field->get_name();
if (exported) {
member_info[member_name] = prop_info;
#ifdef TOOLS_ENABLED
if (is_editor && exported) {
exported_members_cache.push_front(prop_info);
if (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
}
}
@ -2509,10 +2519,10 @@ bool CSharpScript::_update_exports() {
if (_get_member_export(property, /* inspect export: */ true, prop_info, exported)) {
StringName member_name = property->get_name();
if (exported) {
member_info[member_name] = prop_info;
#ifdef TOOLS_ENABLED
if (is_editor && exported) {
exported_members_cache.push_front(prop_info);
if (tmp_object) {
MonoException *exc = nullptr;
MonoObject *ret = property->get_value(tmp_object, &exc);
@ -2523,15 +2533,16 @@ bool CSharpScript::_update_exports() {
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();
}
#ifdef TOOLS_ENABLED
if (is_editor) {
// Need to check this here, before disposal
bool base_ref = Object::cast_to<Reference>(tmp_native) != nullptr;
@ -2557,7 +2568,11 @@ bool CSharpScript::_update_exports() {
}
}
}
#endif
}
#ifdef TOOLS_ENABLED
if (is_editor) {
placeholder_fallback_enabled = false;
if (placeholders.size()) {
@ -2570,10 +2585,10 @@ bool CSharpScript::_update_exports() {
E->get()->update(propnames, values);
}
}
}
#endif
return changed;
#endif
return false;
}
void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class) {
@ -2679,7 +2694,6 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoMethod *p_delegate_in
return true;
}
#ifdef TOOLS_ENABLED
/**
* 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.
@ -2693,8 +2707,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())
if (p_member->is_static()) {
#ifdef TOOLS_ENABLED
if (p_member->has_attribute(CACHED_CLASS(ExportAttribute)))
ERR_PRINT("Cannot export member because it is static: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
#endif
return false;
}
@ -2716,13 +2732,17 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) {
GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member);
if (!property->has_getter()) {
#ifdef TOOLS_ENABLED
if (exported)
ERR_PRINT("Read-only property cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
#endif
return false;
}
if (!property->has_setter()) {
#ifdef TOOLS_ENABLED
if (exported)
ERR_PRINT("Write-only property (without getter) cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
#endif
return false;
}
}
@ -2742,10 +2762,13 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
String hint_string;
if (variant_type == Variant::NIL && !nil_is_variant) {
#ifdef TOOLS_ENABLED
ERR_PRINT("Unknown exported member type: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
#endif
return false;
}
#ifdef TOOLS_ENABLED
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,
@ -2756,6 +2779,7 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
}
#endif
uint32_t prop_usage = PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE;
@ -2772,6 +2796,7 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
#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) {
if (p_variant_type == Variant::NIL) {

View File

@ -147,8 +147,9 @@ private:
bool _get_signal(GDMonoClass *p_class, GDMonoMethod *p_delegate_invoke, Vector<SignalParameter> &params);
bool _update_exports();
#ifdef TOOLS_ENABLED
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);
#endif