-
-
Notifications
You must be signed in to change notification settings - Fork 21.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix generic arrays and dictionaries in .NET not calling set_typed
#98545
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -182,18 +182,7 @@ internal static unsafe void GetScriptNativeName(IntPtr scriptPtr, godot_string_n | |
return; | ||
} | ||
|
||
var native = GodotObject.InternalGetClassNativeBase(scriptType); | ||
|
||
var field = native.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static | | ||
BindingFlags.Public | BindingFlags.NonPublic); | ||
|
||
if (field == null) | ||
{ | ||
*outRes = default; | ||
return; | ||
} | ||
|
||
var nativeName = (StringName?)field.GetValue(null); | ||
var nativeName = GodotObject.InternalGetClassNativeBaseName(scriptType); | ||
|
||
if (nativeName == null) | ||
{ | ||
|
@@ -658,10 +647,14 @@ internal static godot_bool TryReloadRegisteredScriptWithClass(IntPtr scriptPtr) | |
|
||
private static unsafe void GetScriptTypeInfo(Type scriptType, godot_csharp_type_info* outTypeInfo) | ||
{ | ||
Type native = GodotObject.InternalGetClassNativeBase(scriptType); | ||
|
||
godot_string className = Marshaling.ConvertStringToNative(ReflectionUtils.ConstructTypeName(scriptType)); | ||
|
||
StringName? nativeBase = GodotObject.InternalGetClassNativeBaseName(scriptType); | ||
|
||
godot_string_name nativeBaseName = nativeBase != null | ||
? NativeFuncs.godotsharp_string_name_new_copy((godot_string_name)nativeBase.NativeValue) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to copy the StringName? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm fairly certain that this is necessary. At the very least, it's consistent with how If I'm understanding this correctly, it's effectively the same as an implicit call to StringName's copy constructor within C++. This is important to maintain a correct refcount; I tested what happens when a copy isn't made, and I get the following errors when I close the editor:
I suppose given the static lifetime of the StringNames returned by There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I think you are 100% correct. I was also thinking about passing a pointer to the underlying native form, but I agree it's safer to do the copy. |
||
: default; | ||
|
||
bool isTool = scriptType.IsDefined(typeof(ToolAttribute), inherit: false); | ||
|
||
// If the type is nested and the parent type is a tool script, | ||
|
@@ -686,6 +679,7 @@ private static unsafe void GetScriptTypeInfo(Type scriptType, godot_csharp_type_ | |
godot_string iconPath = Marshaling.ConvertStringToNative(iconAttr?.Path); | ||
|
||
outTypeInfo->ClassName = className; | ||
outTypeInfo->NativeBaseName = nativeBaseName; | ||
outTypeInfo->IconPath = iconPath; | ||
outTypeInfo->IsTool = isTool.ToGodotBool(); | ||
outTypeInfo->IsGlobalClass = isGlobalClass.ToGodotBool(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -199,6 +199,44 @@ internal static Variant.Type ConvertManagedTypeToVariantType(Type type, out bool | |
return Variant.Type.Nil; | ||
} | ||
|
||
internal static void GetTypedCollectionParameterInfo<T>( | ||
out Variant.Type variantType, | ||
out godot_string_name className, | ||
out godot_ref script) | ||
{ | ||
variantType = ConvertManagedTypeToVariantType(typeof(T), out _); | ||
|
||
if (variantType != Variant.Type.Object) | ||
{ | ||
className = default; | ||
script = default; | ||
return; | ||
} | ||
|
||
godot_ref scriptRef = default; | ||
|
||
if (!GodotObject.IsNativeClass(typeof(T))) | ||
{ | ||
unsafe | ||
{ | ||
Godot.Bridge.ScriptManagerBridge.GetOrLoadOrCreateScriptForType(typeof(T), &scriptRef); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm guessing we don't expect this to ever create a script here, since if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is possible for the construction of a collection to trigger The stacktrace for such a call looks like this:
I'm not aware of any issues that might arise in this scenario. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, thank you. I don't think there should be any issues with this. |
||
} | ||
|
||
// Don't call GodotObject.InternalGetClassNativeBaseName here! | ||
// godot_dictionary_set_typed and godot_array_set_typed will call CSharpScript::get_instance_base_type | ||
// when a script is passed, because this is better for performance than using reflection to find the | ||
// native base type. | ||
className = default; | ||
} | ||
else | ||
{ | ||
StringName? nativeBaseName = GodotObject.InternalGetClassNativeBaseName(typeof(T)); | ||
className = nativeBaseName != null ? (godot_string_name)nativeBaseName.NativeValue : default; | ||
} | ||
|
||
script = scriptRef; | ||
} | ||
|
||
// String | ||
|
||
public static unsafe godot_string ConvertStringToNative(string? p_mono_string) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now that there is more common logic, should these array and dictionary constructors generally use
: this() { .. }
or is it still worth checking/throwing prior?