diff options
Diffstat (limited to 'modules/mono')
19 files changed, 442 insertions, 635 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 9520598f5c..4316f38bd2 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -109,7 +109,7 @@ Error CSharpLanguage::execute_file(const String &p_path) { return OK; } -extern void *godotsharp_pinvoke_funcs[138]; +extern void *godotsharp_pinvoke_funcs[164]; [[maybe_unused]] volatile void **do_not_strip_godotsharp_pinvoke_funcs; void CSharpLanguage::init() { @@ -705,19 +705,14 @@ void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) { void CSharpLanguage::frame() { if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != nullptr) { - const Ref<MonoGCHandleRef> &task_scheduler_handle = GDMonoCache::cached_data.task_scheduler_handle; - - if (task_scheduler_handle.is_valid()) { - MonoObject *task_scheduler = task_scheduler_handle->get_target(); - - if (task_scheduler) { - MonoException *exc = nullptr; - CACHED_METHOD_THUNK(GodotTaskScheduler, Activate).invoke(task_scheduler, &exc); + MonoException *exc = nullptr; + gdmono->get_core_api_assembly() + ->get_class("Godot", "ScriptManager") + ->get_method("FrameCallback") + ->invoke(nullptr, &exc); - if (exc) { - GDMonoUtils::debug_unhandled_exception(exc); - } - } + if (exc) { + GDMonoUtils::debug_unhandled_exception(exc); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs index 6475237002..5f84bb530f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs @@ -1,20 +1,14 @@ -using System.Runtime.CompilerServices; - namespace Godot { public static class Dispatcher { - /// <summary> - /// Implements an external instance of GodotTaskScheduler. - /// </summary> - /// <returns>A GodotTaskScheduler instance.</returns> - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern GodotTaskScheduler godot_icall_DefaultGodotTaskScheduler(); + internal static GodotTaskScheduler DefaultGodotTaskScheduler; + + private static void InitializeDefaultGodotTaskScheduler() + { + DefaultGodotTaskScheduler = new GodotTaskScheduler(); + } - /// <summary> - /// Initializes the synchronization context as the context of the GodotTaskScheduler. - /// </summary> - public static GodotSynchronizationContext SynchronizationContext => - godot_icall_DefaultGodotTaskScheduler().Context; + public static GodotSynchronizationContext SynchronizationContext => DefaultGodotTaskScheduler.Context; } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs index 691fd85964..340780bb45 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs @@ -1,5 +1,5 @@ using System; -using System.Runtime.CompilerServices; +using Godot.NativeInterop; namespace Godot { @@ -32,10 +32,20 @@ namespace Godot /// </returns> public static WeakRef WeakRef(Object obj) { - return godot_icall_Object_weakref(GetPtr(obj)); - } + if (!IsInstanceValid(obj)) + return null; + + using godot_ref weakRef = default; + + unsafe + { + NativeFuncs.godotsharp_weakref(GetPtr(obj), &weakRef); + } - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern WeakRef godot_icall_Object_weakref(IntPtr obj); + if (weakRef.IsNull) + return null; + + return (WeakRef)InteropUtils.UnmanagedGetManaged(weakRef._reference); + } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index e8ea8f379b..9d237b8d93 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -5,7 +5,6 @@ using real_t = System.Single; #endif using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; using Godot.NativeInterop; namespace Godot @@ -30,7 +29,9 @@ namespace Godot public static unsafe object Bytes2Var(byte[] bytes, bool allowObjects = false) { using var varBytes = Marshaling.mono_array_to_PackedByteArray(bytes); - return godot_icall_GD_bytes2var(&varBytes, allowObjects); + using godot_variant ret = default; + NativeFuncs.godotsharp_bytes2var(&varBytes, allowObjects, &ret); + return Marshaling.variant_to_mono_object(&ret); } /// <summary> @@ -48,9 +49,12 @@ namespace Godot /// </code> /// </example> /// <returns>The <c>Variant</c> converted to the given <paramref name="type"/>.</returns> - public static object Convert(object what, Variant.Type type) + public static unsafe object Convert(object what, Variant.Type type) { - return godot_icall_GD_convert(what, type); + using var whatVariant = Marshaling.mono_object_to_variant(what); + using godot_variant ret = default; + NativeFuncs.godotsharp_convert(&whatVariant, (int)type, &ret); + return Marshaling.variant_to_mono_object(&ret); } /// <summary> @@ -64,7 +68,7 @@ namespace Godot return (real_t)Math.Exp(db * 0.11512925464970228420089957273422); } - private static object[] GetPrintParams(object[] parameters) + private static string[] GetPrintParams(object[] parameters) { if (parameters == null) { @@ -84,9 +88,10 @@ namespace Godot /// </example> /// <param name="var">Variable that will be hashed.</param> /// <returns>Hash of the variable passed.</returns> - public static int Hash(object var) + public static unsafe int Hash(object var) { - return godot_icall_GD_hash(var); + using var variant = Marshaling.mono_object_to_variant(var); + return NativeFuncs.godotsharp_hash(&variant); } /// <summary> @@ -112,7 +117,7 @@ namespace Godot /// <returns>The <see cref="Object"/> instance.</returns> public static Object InstanceFromId(ulong instanceId) { - return godot_icall_GD_instance_from_id(instanceId); + return InteropUtils.UnmanagedGetManaged(NativeFuncs.godotsharp_instance_from_id(instanceId)); } /// <summary> @@ -202,9 +207,10 @@ namespace Godot /// </code> /// </example> /// <param name="message">Error message.</param> - public static void PushError(string message) + public static unsafe void PushError(string message) { - godot_icall_GD_pusherror(message); + using var godotStr = Marshaling.mono_string_to_godot(message); + NativeFuncs.godotsharp_pusherror(&godotStr); } /// <summary> @@ -214,9 +220,10 @@ namespace Godot /// GD.PushWarning("test warning"); // Prints "test warning" to debugger and terminal as warning call /// </example> /// <param name="message">Warning message.</param> - public static void PushWarning(string message) + public static unsafe void PushWarning(string message) { - godot_icall_GD_pushwarning(message); + using var godotStr = Marshaling.mono_string_to_godot(message); + NativeFuncs.godotsharp_pushwarning(&godotStr); } /// <summary> @@ -235,9 +242,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static void Print(params object[] what) + public static unsafe void Print(params object[] what) { - godot_icall_GD_print(GetPrintParams(what)); + string str = string.Concat(GetPrintParams(what)); + using var godotStr = Marshaling.mono_string_to_godot(str); + NativeFuncs.godotsharp_print(&godotStr); } /// <summary> @@ -264,9 +273,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static void PrintRich(params object[] what) + public static unsafe void PrintRich(params object[] what) { - godot_icall_GD_print_rich(GetPrintParams(what)); + string str = string.Concat(GetPrintParams(what)); + using var godotStr = Marshaling.mono_string_to_godot(str); + NativeFuncs.godotsharp_print_rich(&godotStr); } /// <summary> @@ -286,9 +297,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static void PrintErr(params object[] what) + public static unsafe void PrintErr(params object[] what) { - godot_icall_GD_printerr(GetPrintParams(what)); + string str = string.Concat(GetPrintParams(what)); + using var godotStr = Marshaling.mono_string_to_godot(str); + NativeFuncs.godotsharp_printerr(&godotStr); } /// <summary> @@ -306,9 +319,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static void PrintRaw(params object[] what) + public static unsafe void PrintRaw(params object[] what) { - godot_icall_GD_printraw(GetPrintParams(what)); + string str = string.Concat(GetPrintParams(what)); + using var godotStr = Marshaling.mono_string_to_godot(str); + NativeFuncs.godotsharp_printraw(&godotStr); } /// <summary> @@ -320,9 +335,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static void PrintS(params object[] what) + public static unsafe void PrintS(params object[] what) { - godot_icall_GD_prints(GetPrintParams(what)); + string str = string.Join(' ', GetPrintParams(what)); + using var godotStr = Marshaling.mono_string_to_godot(str); + NativeFuncs.godotsharp_prints(&godotStr); } /// <summary> @@ -334,9 +351,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static void PrintT(params object[] what) + public static unsafe void PrintT(params object[] what) { - godot_icall_GD_printt(GetPrintParams(what)); + string str = string.Join('\t', GetPrintParams(what)); + using var godotStr = Marshaling.mono_string_to_godot(str); + NativeFuncs.godotsharp_printt(&godotStr); } /// <summary> @@ -350,7 +369,7 @@ namespace Godot /// <returns>A random <see langword="float"/> number.</returns> public static float Randf() { - return godot_icall_GD_randf(); + return NativeFuncs.godotsharp_randf(); } /// <summary> @@ -360,7 +379,7 @@ namespace Godot /// <returns>A random normally-distributed <see langword="float"/> number.</returns> public static double Randfn(double mean, double deviation) { - return godot_icall_GD_randfn(mean, deviation); + return NativeFuncs.godotsharp_randfn(mean, deviation); } /// <summary> @@ -378,7 +397,7 @@ namespace Godot /// <returns>A random <see langword="uint"/> number.</returns> public static uint Randi() { - return godot_icall_GD_randi(); + return NativeFuncs.godotsharp_randi(); } /// <summary> @@ -391,7 +410,7 @@ namespace Godot /// </summary> public static void Randomize() { - godot_icall_GD_randomize(); + NativeFuncs.godotsharp_randomize(); } /// <summary> @@ -406,7 +425,7 @@ namespace Godot /// <returns>A random <see langword="double"/> number inside the given range.</returns> public static double RandRange(double from, double to) { - return godot_icall_GD_randf_range(from, to); + return NativeFuncs.godotsharp_randf_range(from, to); } /// <summary> @@ -423,7 +442,7 @@ namespace Godot /// <returns>A random <see langword="int"/> number inside the given range.</returns> public static int RandRange(int from, int to) { - return godot_icall_GD_randi_range(from, to); + return NativeFuncs.godotsharp_randi_range(from, to); } /// <summary> @@ -436,7 +455,7 @@ namespace Godot /// <returns>A random <see langword="uint"/> number.</returns> public static uint RandFromSeed(ref ulong seed) { - return godot_icall_GD_rand_seed(seed, out seed); + return NativeFuncs.godotsharp_rand_from_seed(seed, out seed); } /// <summary> @@ -493,7 +512,7 @@ namespace Godot /// <param name="seed">Seed that will be used.</param> public static void Seed(ulong seed) { - godot_icall_GD_seed(seed); + NativeFuncs.godotsharp_seed(seed); } /// <summary> @@ -501,9 +520,12 @@ namespace Godot /// </summary> /// <param name="what">Arguments that will converted to string.</param> /// <returns>The string formed by the given arguments.</returns> - public static string Str(params object[] what) + public static unsafe string Str(params object[] what) { - return godot_icall_GD_str(what); + using var whatGodotArray = Marshaling.mono_array_to_Array(what); + using godot_string ret = default; + NativeFuncs.godotsharp_str(&whatGodotArray, &ret); + return Marshaling.mono_string_from_godot(&ret); } /// <summary> @@ -518,18 +540,12 @@ namespace Godot /// </example> /// <param name="str">String that will be converted to Variant.</param> /// <returns>The decoded <c>Variant</c>.</returns> - public static object Str2Var(string str) + public static unsafe object Str2Var(string str) { - return godot_icall_GD_str2var(str); - } - - /// <summary> - /// Returns whether the given class exists in <see cref="ClassDB"/>. - /// </summary> - /// <returns>If the class exists in <see cref="ClassDB"/>.</returns> - public static bool TypeExists(StringName type) - { - return godot_icall_GD_type_exists(ref type.NativeValue); + using var godotStr = Marshaling.mono_string_to_godot(str); + using godot_variant ret = default; + NativeFuncs.godotsharp_str2var(&godotStr, &ret); + return Marshaling.variant_to_mono_object(&ret); } /// <summary> @@ -543,12 +559,11 @@ namespace Godot /// <returns>The <c>Variant</c> encoded as an array of bytes.</returns> public static unsafe byte[] Var2Bytes(object var, bool fullObjects = false) { - godot_packed_byte_array varBytes; - godot_icall_GD_var2bytes(var, fullObjects, &varBytes); + using var variant = Marshaling.mono_object_to_variant(var); + using godot_packed_byte_array varBytes = default; + NativeFuncs.godotsharp_var2bytes(&variant, fullObjects, &varBytes); using (varBytes) - { return Marshaling.PackedByteArray_to_mono_array(&varBytes); - } } /// <summary> @@ -568,9 +583,12 @@ namespace Godot /// </example> /// <param name="var">Variant that will be converted to string.</param> /// <returns>The <c>Variant</c> encoded as a string.</returns> - public static string Var2Str(object var) + public static unsafe string Var2Str(object var) { - return godot_icall_GD_var2str(var); + using var variant = Marshaling.mono_object_to_variant(var); + using godot_string ret = default; + NativeFuncs.godotsharp_var2str(&variant, &ret); + return Marshaling.mono_string_from_godot(&ret); } /// <summary> @@ -579,85 +597,7 @@ namespace Godot /// <returns>The <see cref="Variant.Type"/> for the given <paramref name="type"/>.</returns> public static Variant.Type TypeToVariantType(Type type) { - return godot_icall_TypeToVariantType(type); + return Marshaling.managed_to_variant_type(type, out bool _); } - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern unsafe object godot_icall_GD_bytes2var(godot_packed_byte_array* bytes, bool allowObjects); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object godot_icall_GD_convert(object what, Variant.Type type); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern int godot_icall_GD_hash(object var); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern Object godot_icall_GD_instance_from_id(ulong instanceId); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_GD_print(object[] what); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_GD_print_rich(object[] what); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_GD_printerr(object[] what); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_GD_printraw(object[] what); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_GD_prints(object[] what); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_GD_printt(object[] what); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_GD_randomize(); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern uint godot_icall_GD_randi(); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern float godot_icall_GD_randf(); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern int godot_icall_GD_randi_range(int from, int to); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern double godot_icall_GD_randf_range(double from, double to); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern double godot_icall_GD_randfn(double mean, double deviation); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern uint godot_icall_GD_rand_seed(ulong seed, out ulong newSeed); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_GD_seed(ulong seed); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern string godot_icall_GD_str(object[] what); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object godot_icall_GD_str2var(string str); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool godot_icall_GD_type_exists(ref godot_string_name type); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern unsafe void godot_icall_GD_var2bytes(object what, bool fullObjects, godot_packed_byte_array* bytes); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern string godot_icall_GD_var2str(object var); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_GD_pusherror(string type); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_GD_pushwarning(string type); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern Variant.Type godot_icall_TypeToVariantType(Type type); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs index ddcb6b9091..865863cd3e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs @@ -36,6 +36,8 @@ namespace Godot.NativeInterop NativeFuncs.godotsharp_ref_destroy(ref this); _reference = IntPtr.Zero; } + + public bool IsNull => _reference == IntPtr.Zero; } [SuppressMessage("ReSharper", "InconsistentNaming")] diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs index 590fb082e8..e0819b2857 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -18,8 +18,10 @@ namespace Godot.NativeInterop fieldInfo.SetValue(obj, valueObj); } - public static Variant.Type managed_to_variant_type(Type type, ref bool r_nil_is_variant) + public static Variant.Type managed_to_variant_type(Type type, out bool r_nil_is_variant) { + r_nil_is_variant = false; + switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: @@ -199,8 +201,6 @@ namespace Godot.NativeInterop } } - r_nil_is_variant = false; - // Unknown return Variant.Type.Nil; } @@ -711,7 +711,7 @@ namespace Godot.NativeInterop if (typeof(Godot.Object[]).IsAssignableFrom(type)) { using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); - return Array_to_mono_array_of_type(&godotArray, type); + return Array_to_mono_array_of_godot_object_type(&godotArray, type); } if (type == typeof(object[])) @@ -1136,7 +1136,7 @@ namespace Godot.NativeInterop return ret; } - public static unsafe object Array_to_mono_array_of_type(godot_array* p_array, Type type) + public static unsafe object Array_to_mono_array_of_godot_object_type(godot_array* p_array, Type type) { var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( NativeFuncs.godotsharp_array_new_copy(p_array)); @@ -1144,7 +1144,9 @@ namespace Godot.NativeInterop int length = array.Count; object ret = Activator.CreateInstance(type, length); - array.CopyTo((object[])ret, 0); // variant_to_mono_object handled by Collections.Array + // variant_to_mono_object handled by Collections.Array + // variant_to_mono_object_of_type is not needed because target element types are Godot.Object (or derived) + array.CopyTo((object[])ret, 0); return ret; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs index 0680ec7be5..adbf5eb9b6 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs @@ -510,5 +510,89 @@ namespace Godot.NativeInterop [DllImport(GodotDllName)] public static extern bool godotsharp_node_path_is_absolute(ref godot_node_path p_self); + + // GD, etc + + [DllImport(GodotDllName)] + public static extern void godotsharp_bytes2var(godot_packed_byte_array* p_bytes, bool p_allow_objects, + godot_variant* r_ret); + + [DllImport(GodotDllName)] + public static extern void godotsharp_convert(godot_variant* p_what, int p_type, godot_variant* r_ret); + + [DllImport(GodotDllName)] + public static extern int godotsharp_hash(godot_variant* var); + + [DllImport(GodotDllName)] + public static extern IntPtr godotsharp_instance_from_id(ulong instanceId); + + [DllImport(GodotDllName)] + public static extern void godotsharp_print(godot_string* p_what); + + [DllImport(GodotDllName)] + public static extern void godotsharp_print_rich(godot_string* p_what); + + [DllImport(GodotDllName)] + public static extern void godotsharp_printerr(godot_string* p_what); + + [DllImport(GodotDllName)] + public static extern void godotsharp_printraw(godot_string* p_what); + + [DllImport(GodotDllName)] + public static extern void godotsharp_prints(godot_string* p_what); + + [DllImport(GodotDllName)] + public static extern void godotsharp_printt(godot_string* p_what); + + [DllImport(GodotDllName)] + public static extern float godotsharp_randf(); + + [DllImport(GodotDllName)] + public static extern uint godotsharp_randi(); + + [DllImport(GodotDllName)] + public static extern void godotsharp_randomize(); + + [DllImport(GodotDllName)] + public static extern double godotsharp_randf_range(double from, double to); + + [DllImport(GodotDllName)] + public static extern double godotsharp_randfn(double mean, double deviation); + + [DllImport(GodotDllName)] + public static extern int godotsharp_randi_range(int from, int to); + + [DllImport(GodotDllName)] + public static extern uint godotsharp_rand_from_seed(ulong seed, out ulong newSeed); + + [DllImport(GodotDllName)] + public static extern void godotsharp_seed(ulong seed); + + [DllImport(GodotDllName)] + public static extern void godotsharp_weakref(IntPtr obj, godot_ref* r_weak_ref); + + [DllImport(GodotDllName)] + public static extern string godotsharp_str(godot_array* p_what, godot_string* r_ret); + + [DllImport(GodotDllName)] + public static extern void godotsharp_str2var(godot_string* p_str, godot_variant* r_ret); + + [DllImport(GodotDllName)] + public static extern void godotsharp_var2bytes(godot_variant* what, bool fullObjects, + godot_packed_byte_array* bytes); + + [DllImport(GodotDllName)] + public static extern void godotsharp_var2str(godot_variant* var, godot_string* r_ret); + + [DllImport(GodotDllName)] + public static extern void godotsharp_pusherror(godot_string* type); + + [DllImport(GodotDllName)] + public static extern void godotsharp_pushwarning(godot_string* type); + + // Object + + [DllImport(GodotDllName)] + public static extern string godotsharp_object_to_string(IntPtr ptr, godot_string* r_str); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs index 9c4265517e..7bbaef62fa 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.CompilerServices; +using Godot.NativeInterop; namespace Godot { @@ -101,9 +102,11 @@ namespace Godot /// Converts this <see cref="Object"/> to a string. /// </summary> /// <returns>A string representation of this object.</returns> - public override string ToString() + public override unsafe string ToString() { - return godot_icall_Object_ToString(GetPtr(this)); + using godot_string str = default; + NativeFuncs.godotsharp_object_to_string(GetPtr(this), &str); + return Marshaling.mono_string_from_godot(&str); } /// <summary> @@ -190,8 +193,5 @@ namespace Godot [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void godot_icall_Object_ConnectEventSignals(IntPtr obj); - - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern string godot_icall_Object_ToString(IntPtr ptr); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/ScriptManager.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/ScriptManager.cs new file mode 100644 index 0000000000..e92688f5bb --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/ScriptManager.cs @@ -0,0 +1,10 @@ +namespace Godot +{ + internal class ScriptManager + { + internal static void FrameCallback() + { + Dispatcher.DefaultGodotTaskScheduler?.Activate(); + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index 0709723da0..36faf92144 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -71,6 +71,7 @@ <Compile Include="Core\NativeInterop\NativeFuncs.cs" /> <Compile Include="Core\NativeInterop\InteropStructs.cs" /> <Compile Include="Core\NativeInterop\Marshaling.cs" /> + <Compile Include="Core\ScriptManager.cs" /> <Compile Include="Core\SignalInfo.cs" /> <Compile Include="Core\SignalAwaiter.cs" /> <Compile Include="Core\StringExtensions.cs" /> diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index c252ee47f4..d56b70e739 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -124,50 +124,14 @@ void godot_icall_Object_ConnectEventSignals(Object *p_ptr) { } } -MonoObject *godot_icall_Object_weakref(Object *p_ptr) { - if (!p_ptr) { - return nullptr; - } - - Ref<WeakRef> wref; - RefCounted *rc = Object::cast_to<RefCounted>(p_ptr); - - if (rc) { - Ref<RefCounted> r = rc; - if (!r.is_valid()) { - return nullptr; - } - - wref.instantiate(); - wref->set_ref(r); - } else { - wref.instantiate(); - wref->set_obj(p_ptr); - } - - return GDMonoUtils::unmanaged_get_managed(wref.ptr()); -} - int32_t godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter) { StringName signal = p_signal ? *p_signal : StringName(); return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter); } -MonoString *godot_icall_Object_ToString(Object *p_ptr) { -#ifdef DEBUG_ENABLED - // Cannot happen in C#; would get an ObjectDisposedException instead. - CRASH_COND(p_ptr == nullptr); -#endif - // Can't call 'Object::to_string()' here, as that can end up calling 'ToString' again resulting in an endless circular loop. - String result = "[" + p_ptr->get_class() + ":" + itos(p_ptr->get_instance_id()) + "]"; - return GDMonoMarshal::mono_string_from_godot(result); -} - void godot_register_object_icalls() { GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Disposed", godot_icall_Object_Disposed); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_RefCounted_Disposed", godot_icall_RefCounted_Disposed); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", godot_icall_Object_ConnectEventSignals); - GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ToString", godot_icall_Object_ToString); - GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_weakref", godot_icall_Object_weakref); GDMonoUtils::add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", godot_icall_SignalAwaiter_connect); } diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp deleted file mode 100644 index b315831819..0000000000 --- a/modules/mono/glue/gd_glue.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/*************************************************************************/ -/* gd_glue.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "core/io/marshalls.h" -#include "core/os/os.h" -#include "core/string/ustring.h" -#include "core/variant/array.h" -#include "core/variant/variant.h" -#include "core/variant/variant_parser.h" - -#include "../mono_gd/gd_mono_cache.h" -#include "../mono_gd/gd_mono_marshal.h" -#include "../mono_gd/gd_mono_utils.h" - -MonoObject *godot_icall_GD_bytes2var(PackedByteArray *p_bytes, MonoBoolean p_allow_objects) { - Variant ret; - Error err = decode_variant(ret, p_bytes->ptr(), p_bytes->size(), nullptr, p_allow_objects); - if (err != OK) { - ret = RTR("Not enough bytes for decoding bytes, or invalid format."); - } - return GDMonoMarshal::variant_to_mono_object(ret); -} - -MonoObject *godot_icall_GD_convert(MonoObject *p_what, int32_t p_type) { - Variant what = GDMonoMarshal::mono_object_to_variant(p_what); - const Variant *args[1] = { &what }; - Callable::CallError ce; - Variant ret; - Variant::construct(Variant::Type(p_type), ret, args, 1, ce); - ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr); - return GDMonoMarshal::variant_to_mono_object(ret); -} - -int godot_icall_GD_hash(MonoObject *p_var) { - return GDMonoMarshal::mono_object_to_variant(p_var).hash(); -} - -MonoObject *godot_icall_GD_instance_from_id(uint64_t p_instance_id) { - return GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(ObjectID(p_instance_id))); -} - -void godot_icall_GD_print(MonoArray *p_what) { - String str; - int length = mono_array_length(p_what); - - for (int i = 0; i < length; i++) { - MonoObject *elem = mono_array_get(p_what, MonoObject *, i); - - MonoException *exc = nullptr; - String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc); - - if (exc) { - GDMonoUtils::set_pending_exception(exc); - return; - } - - str += elem_str; - } - - print_line(str); -} - -void godot_icall_GD_print_rich(MonoArray *p_what) { - String str; - int length = mono_array_length(p_what); - - for (int i = 0; i < length; i++) { - MonoObject *elem = mono_array_get(p_what, MonoObject *, i); - - MonoException *exc = nullptr; - String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc); - - if (exc) { - GDMonoUtils::set_pending_exception(exc); - return; - } - - str += elem_str; - } - - print_line_rich(str); -} - -void godot_icall_GD_printerr(MonoArray *p_what) { - String str; - int length = mono_array_length(p_what); - - for (int i = 0; i < length; i++) { - MonoObject *elem = mono_array_get(p_what, MonoObject *, i); - - MonoException *exc = nullptr; - String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc); - - if (exc) { - GDMonoUtils::set_pending_exception(exc); - return; - } - - str += elem_str; - } - - print_error(str); -} - -void godot_icall_GD_printraw(MonoArray *p_what) { - String str; - int length = mono_array_length(p_what); - - for (int i = 0; i < length; i++) { - MonoObject *elem = mono_array_get(p_what, MonoObject *, i); - - MonoException *exc = nullptr; - String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc); - - if (exc) { - GDMonoUtils::set_pending_exception(exc); - return; - } - - str += elem_str; - } - - OS::get_singleton()->print("%s", str.utf8().get_data()); -} - -void godot_icall_GD_prints(MonoArray *p_what) { - String str; - int length = mono_array_length(p_what); - - for (int i = 0; i < length; i++) { - MonoObject *elem = mono_array_get(p_what, MonoObject *, i); - - MonoException *exc = nullptr; - String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc); - - if (exc) { - GDMonoUtils::set_pending_exception(exc); - return; - } - - if (i) { - str += " "; - } - - str += elem_str; - } - - print_line(str); -} - -void godot_icall_GD_printt(MonoArray *p_what) { - String str; - int length = mono_array_length(p_what); - - for (int i = 0; i < length; i++) { - MonoObject *elem = mono_array_get(p_what, MonoObject *, i); - - MonoException *exc = nullptr; - String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc); - - if (exc) { - GDMonoUtils::set_pending_exception(exc); - return; - } - - if (i) { - str += "\t"; - } - - str += elem_str; - } - - print_line(str); -} - -void godot_icall_GD_randomize() { - Math::randomize(); -} - -uint32_t godot_icall_GD_randi() { - return Math::rand(); -} - -float godot_icall_GD_randf() { - return Math::randf(); -} - -int32_t godot_icall_GD_randi_range(int32_t from, int32_t to) { - return Math::random(from, to); -} - -double godot_icall_GD_randf_range(double from, double to) { - return Math::random(from, to); -} - -double godot_icall_GD_randfn(double mean, double deviation) { - return Math::randfn(mean, deviation); -} - -uint32_t godot_icall_GD_rand_seed(uint64_t seed, uint64_t *newSeed) { - uint32_t ret = Math::rand_from_seed(&seed); - *newSeed = seed; - return ret; -} - -void godot_icall_GD_seed(uint64_t p_seed) { - Math::seed(p_seed); -} - -MonoString *godot_icall_GD_str(MonoArray *p_what) { - String str; - Array what = GDMonoMarshal::mono_array_to_Array(p_what); - - for (int i = 0; i < what.size(); i++) { - String os = what[i].operator String(); - - if (i == 0) { - str = os; - } else { - str += os; - } - } - - return GDMonoMarshal::mono_string_from_godot(str); -} - -MonoObject *godot_icall_GD_str2var(MonoString *p_str) { - Variant ret; - - VariantParser::StreamString ss; - ss.s = GDMonoMarshal::mono_string_to_godot(p_str); - - String errs; - int line; - Error err = VariantParser::parse(&ss, ret, errs, line); - if (err != OK) { - String err_str = "Parse error at line " + itos(line) + ": " + errs + "."; - ERR_PRINT(err_str); - ret = err_str; - } - - return GDMonoMarshal::variant_to_mono_object(ret); -} - -MonoBoolean godot_icall_GD_type_exists(StringName *p_type) { - StringName type = p_type ? *p_type : StringName(); - return ClassDB::class_exists(type); -} - -void godot_icall_GD_pusherror(MonoString *p_str) { - ERR_PRINT(GDMonoMarshal::mono_string_to_godot(p_str)); -} - -void godot_icall_GD_pushwarning(MonoString *p_str) { - WARN_PRINT(GDMonoMarshal::mono_string_to_godot(p_str)); -} - -void godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects, PackedByteArray *r_bytes) { - memnew_placement(r_bytes, PackedByteArray); - - Variant var = GDMonoMarshal::mono_object_to_variant(p_var); - - int len; - Error err = encode_variant(var, nullptr, len, p_full_objects); - ERR_FAIL_COND_MSG(err != OK, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."); - - r_bytes->resize(len); - encode_variant(var, r_bytes->ptrw(), len, p_full_objects); -} - -MonoString *godot_icall_GD_var2str(MonoObject *p_var) { - String vars; - VariantWriter::write_to_string(GDMonoMarshal::mono_object_to_variant(p_var), vars); - return GDMonoMarshal::mono_string_from_godot(vars); -} - -uint32_t godot_icall_TypeToVariantType(MonoReflectionType *p_refl_type) { - return (uint32_t)GDMonoMarshal::managed_to_variant_type(ManagedType::from_reftype(p_refl_type)); -} - -MonoObject *godot_icall_DefaultGodotTaskScheduler() { - return GDMonoCache::cached_data.task_scheduler_handle->get_target(); -} - -void godot_register_gd_icalls() { - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_bytes2var", godot_icall_GD_bytes2var); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_convert", godot_icall_GD_convert); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_hash", godot_icall_GD_hash); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", godot_icall_GD_instance_from_id); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pusherror", godot_icall_GD_pusherror); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pushwarning", godot_icall_GD_pushwarning); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_print", godot_icall_GD_print); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_print_rich", godot_icall_GD_print_rich); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printerr", godot_icall_GD_printerr); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printraw", godot_icall_GD_printraw); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_prints", godot_icall_GD_prints); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printt", godot_icall_GD_printt); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randomize", godot_icall_GD_randomize); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randi", godot_icall_GD_randi); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randf", godot_icall_GD_randf); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randi_range", godot_icall_GD_randi_range); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randf_range", godot_icall_GD_randf_range); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randfn", godot_icall_GD_randfn); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_rand_seed", godot_icall_GD_rand_seed); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_seed", godot_icall_GD_seed); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_str", godot_icall_GD_str); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_str2var", godot_icall_GD_str2var); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_type_exists", godot_icall_GD_type_exists); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_var2bytes", godot_icall_GD_var2bytes); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_var2str", godot_icall_GD_var2str); - GDMonoUtils::add_internal_call("Godot.GD::godot_icall_TypeToVariantType", godot_icall_TypeToVariantType); - - // Dispatcher - GDMonoUtils::add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", godot_icall_DefaultGodotTaskScheduler); -} diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp index f5a04bf05c..2860386127 100644 --- a/modules/mono/glue/runtime_interop.cpp +++ b/modules/mono/glue/runtime_interop.cpp @@ -29,8 +29,10 @@ /*************************************************************************/ #include "core/config/engine.h" +#include "core/io/marshalls.h" #include "core/object/class_db.h" #include "core/object/method_bind.h" +#include "core/os/os.h" #include "core/string/string_name.h" #include "../interop_types.h" @@ -839,12 +841,194 @@ GD_PINVOKE_EXPORT bool godotsharp_node_path_is_absolute(const NodePath *p_self) return p_self->is_absolute(); } +GD_PINVOKE_EXPORT void godotsharp_randomize() { + Math::randomize(); +} + +GD_PINVOKE_EXPORT uint32_t godotsharp_randi() { + return Math::rand(); +} + +GD_PINVOKE_EXPORT float godotsharp_randf() { + return Math::randf(); +} + +GD_PINVOKE_EXPORT int32_t godotsharp_randi_range(int32_t p_from, int32_t p_to) { + return Math::random(p_from, p_to); +} + +GD_PINVOKE_EXPORT double godotsharp_randf_range(double p_from, double p_to) { + return Math::random(p_from, p_to); +} + +GD_PINVOKE_EXPORT double godotsharp_randfn(double p_mean, double p_deviation) { + return Math::randfn(p_mean, p_deviation); +} + +GD_PINVOKE_EXPORT void godotsharp_seed(uint64_t p_seed) { + Math::seed(p_seed); +} + +GD_PINVOKE_EXPORT uint32_t godotsharp_rand_from_seed(uint64_t p_seed, uint64_t *r_new_seed) { + uint32_t ret = Math::rand_from_seed(&p_seed); + *r_new_seed = p_seed; + return ret; +} + +GD_PINVOKE_EXPORT void godotsharp_weakref(Object *p_ptr, Ref<RefCounted> *r_weak_ref) { + if (!p_ptr) { + return; + } + + Ref<WeakRef> wref; + RefCounted *rc = Object::cast_to<RefCounted>(p_ptr); + + if (rc) { + Ref<RefCounted> r = rc; + if (!r.is_valid()) { + return; + } + + wref.instantiate(); + wref->set_ref(r); + } else { + wref.instantiate(); + wref->set_obj(p_ptr); + } + + memnew_placement(r_weak_ref, Ref<RefCounted>(wref)); +} + +GD_PINVOKE_EXPORT void godotsharp_str(const godot_array *p_what, godot_string *r_ret) { + String &str = *memnew_placement(r_ret, String); + const Array &what = *reinterpret_cast<const Array *>(p_what); + + for (int i = 0; i < what.size(); i++) { + String os = what[i].operator String(); + + if (i == 0) { + str = os; + } else { + str += os; + } + } +} + +GD_PINVOKE_EXPORT void godotsharp_print(const godot_string *p_what) { + print_line(*reinterpret_cast<const String *>(p_what)); +} + +GD_PINVOKE_EXPORT void godotsharp_print_rich(const godot_string *p_what) { + print_line_rich(*reinterpret_cast<const String *>(p_what)); +} + +GD_PINVOKE_EXPORT void godotsharp_printerr(const godot_string *p_what) { + print_error(*reinterpret_cast<const String *>(p_what)); +} + +GD_PINVOKE_EXPORT void godotsharp_printt(const godot_string *p_what) { + print_line(*reinterpret_cast<const String *>(p_what)); +} + +GD_PINVOKE_EXPORT void godotsharp_prints(const godot_string *p_what) { + print_line(*reinterpret_cast<const String *>(p_what)); +} + +GD_PINVOKE_EXPORT void godotsharp_printraw(const godot_string *p_what) { + OS::get_singleton()->print("%s", reinterpret_cast<const String *>(p_what)->utf8().get_data()); +} + +GD_PINVOKE_EXPORT void godotsharp_pusherror(const godot_string *p_str) { + ERR_PRINT(*reinterpret_cast<const String *>(p_str)); +} + +GD_PINVOKE_EXPORT void godotsharp_pushwarning(const godot_string *p_str) { + WARN_PRINT(*reinterpret_cast<const String *>(p_str)); +} + +GD_PINVOKE_EXPORT void godotsharp_var2str(const godot_variant *p_var, godot_string *r_ret) { + const Variant &var = *reinterpret_cast<const Variant *>(p_var); + String &vars = *memnew_placement(r_ret, String); + VariantWriter::write_to_string(var, vars); +} + +GD_PINVOKE_EXPORT void godotsharp_str2var(const godot_string *p_str, godot_variant *r_ret) { + Variant ret; + + VariantParser::StreamString ss; + ss.s = *reinterpret_cast<const String *>(p_str); + + String errs; + int line; + Error err = VariantParser::parse(&ss, ret, errs, line); + if (err != OK) { + String err_str = "Parse error at line " + itos(line) + ": " + errs + "."; + ERR_PRINT(err_str); + ret = err_str; + } + memnew_placement(r_ret, Variant(ret)); +} + +GD_PINVOKE_EXPORT void godotsharp_var2bytes(const godot_variant *p_var, bool p_full_objects, godot_packed_array *r_bytes) { + const Variant &var = *reinterpret_cast<const Variant *>(p_var); + PackedByteArray &bytes = *memnew_placement(r_bytes, PackedByteArray); + + int len; + Error err = encode_variant(var, nullptr, len, p_full_objects); + ERR_FAIL_COND_MSG(err != OK, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."); + + bytes.resize(len); + encode_variant(var, bytes.ptrw(), len, p_full_objects); +} + +GD_PINVOKE_EXPORT void godotsharp_bytes2var(const godot_packed_array *p_bytes, bool p_allow_objects, godot_variant *r_ret) { + const PackedByteArray *bytes = reinterpret_cast<const PackedByteArray *>(p_bytes); + Variant ret; + Error err = decode_variant(ret, bytes->ptr(), bytes->size(), nullptr, p_allow_objects); + if (err != OK) { + ret = RTR("Not enough bytes for decoding bytes, or invalid format."); + } + memnew_placement(r_ret, Variant(ret)); +} + +GD_PINVOKE_EXPORT int godotsharp_hash(const godot_variant *p_var) { + return reinterpret_cast<const Variant *>(p_var)->hash(); +} + +GD_PINVOKE_EXPORT void godotsharp_convert(const godot_variant *p_what, int32_t p_type, godot_variant *r_ret) { + const Variant *args[1] = { reinterpret_cast<const Variant *>(p_what) }; + Callable::CallError ce; + Variant ret; + Variant::construct(Variant::Type(p_type), ret, args, 1, ce); + if (ce.error != Callable::CallError::CALL_OK) { + memnew_placement(r_ret, Variant); + ERR_FAIL_MSG("Unable to convert parameter from '" + + Variant::get_type_name(reinterpret_cast<const Variant *>(p_what)->get_type()) + + "' to '" + Variant::get_type_name(Variant::Type(p_type)) + "'."); + } + memnew_placement(r_ret, Variant(ret)); +} + +GD_PINVOKE_EXPORT Object *godotsharp_instance_from_id(uint64_t p_instance_id) { + return ObjectDB::get_instance(ObjectID(p_instance_id)); +} + +GD_PINVOKE_EXPORT void godotsharp_object_to_string(Object *p_ptr, godot_string *r_str) { +#ifdef DEBUG_ENABLED + // Cannot happen in C#; would get an ObjectDisposedException instead. + CRASH_COND(p_ptr == nullptr); +#endif + // Can't call 'Object::to_string()' here, as that can end up calling 'ToString' again resulting in an endless circular loop. + memnew_placement(r_str, + String("[" + p_ptr->get_class() + ":" + itos(p_ptr->get_instance_id()) + "]")); +} + #ifdef __cplusplus } #endif // We need this to prevent the functions from being stripped. -void *godotsharp_pinvoke_funcs[138] = { +void *godotsharp_pinvoke_funcs[164] = { (void *)godotsharp_method_bind_get_method, (void *)godotsharp_get_class_constructor, (void *)godotsharp_invoke_class_constructor, @@ -982,5 +1166,31 @@ void *godotsharp_pinvoke_funcs[138] = { (void *)godotsharp_node_path_get_name_count, (void *)godotsharp_node_path_get_subname, (void *)godotsharp_node_path_get_subname_count, - (void *)godotsharp_node_path_is_absolute + (void *)godotsharp_node_path_is_absolute, + (void *)godotsharp_randomize, + (void *)godotsharp_randi, + (void *)godotsharp_randf, + (void *)godotsharp_randi_range, + (void *)godotsharp_randf_range, + (void *)godotsharp_randfn, + (void *)godotsharp_seed, + (void *)godotsharp_rand_from_seed, + (void *)godotsharp_weakref, + (void *)godotsharp_str, + (void *)godotsharp_print, + (void *)godotsharp_print_rich, + (void *)godotsharp_printerr, + (void *)godotsharp_printt, + (void *)godotsharp_prints, + (void *)godotsharp_printraw, + (void *)godotsharp_pusherror, + (void *)godotsharp_pushwarning, + (void *)godotsharp_var2str, + (void *)godotsharp_str2var, + (void *)godotsharp_var2bytes, + (void *)godotsharp_bytes2var, + (void *)godotsharp_hash, + (void *)godotsharp_convert, + (void *)godotsharp_instance_from_id, + (void *)godotsharp_object_to_string, }; diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index b45b71aea7..bf387be4c8 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -442,14 +442,12 @@ bool GDMono::_are_api_assemblies_out_of_sync() { return out_of_sync; } -void godot_register_gd_icalls(); void godot_register_object_icalls(); void godot_register_scene_tree_icalls(); void godot_register_placeholder_icalls(); void GDMono::_register_internal_calls() { // Registers internal calls that were not generated. - godot_register_gd_icalls(); godot_register_object_icalls(); godot_register_scene_tree_icalls(); godot_register_placeholder_icalls(); @@ -987,6 +985,8 @@ Error GDMono::_load_scripts_domain() { Error GDMono::_unload_scripts_domain() { ERR_FAIL_NULL_V(scripts_domain, ERR_BUG); + CSharpLanguage::get_singleton()->_on_scripts_domain_about_to_unload(); + print_verbose("Mono: Finalizing scripts domain..."); if (mono_domain_get() != root_domain) { @@ -1040,8 +1040,6 @@ Error GDMono::_unload_scripts_domain() { Error GDMono::reload_scripts_domain() { ERR_FAIL_COND_V(!runtime_initialized, ERR_BUG); - CSharpLanguage::get_singleton()->_on_scripts_domain_about_to_unload(); - if (scripts_domain) { Error domain_unload_err = _unload_scripts_domain(); ERR_FAIL_COND_V_MSG(domain_unload_err != OK, domain_unload_err, "Mono: Failed to unload scripts domain."); diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp index 08660e3701..54e49cf5f5 100644 --- a/modules/mono/mono_gd/gd_mono_cache.cpp +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -116,7 +116,6 @@ void CachedData::clear_godot_api_cache() { methodthunk_GodotObject_Dispose.nullify(); methodthunk_SignalAwaiter_SignalCallback.nullify(); - methodthunk_GodotTaskScheduler_Activate.nullify(); methodthunk_Delegate_Equals.nullify(); @@ -137,8 +136,6 @@ void CachedData::clear_godot_api_cache() { methodthunk_Marshaling_SetFieldValue.nullify(); methodthunk_MarshalUtils_TypeHasFlagsAttribute.nullify(); - - task_scheduler_handle = Ref<MonoGCHandleRef>(); } #define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class)) @@ -197,7 +194,6 @@ void update_godot_api_cache() { CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, CACHED_CLASS(GodotObject)->get_method("Dispose", 0)); CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)); - CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)); CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TrySerializeDelegateWithGCHandle, GODOT_API_CLASS(DelegateUtils)->get_method("TrySerializeDelegateWithGCHandle", 2)); CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TryDeserializeDelegateWithGCHandle, GODOT_API_CLASS(DelegateUtils)->get_method("TryDeserializeDelegateWithGCHandle", 2)); @@ -233,10 +229,16 @@ void update_godot_api_cache() { CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4)); #endif - // TODO Move to CSharpLanguage::init() and do handle disposal - MonoObject *task_scheduler = mono_object_new(mono_domain_get(), GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr()); - GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler)); - cached_data.task_scheduler_handle = MonoGCHandleRef::create_strong(task_scheduler); + MonoException *exc = nullptr; + GDMono::get_singleton() + ->get_core_api_assembly() + ->get_class("Godot", "Dispatcher") + ->get_method("InitializeDefaultGodotTaskScheduler") + ->invoke(nullptr, &exc); + + if (exc) { + GDMonoUtils::debug_unhandled_exception(exc); + } cached_data.godot_api_cache_updated = true; } diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index 0db32b5885..5876583260 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -90,7 +90,6 @@ struct CachedData { GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose; GDMonoMethodThunk<MonoObject *, MonoArray *> methodthunk_SignalAwaiter_SignalCallback; - GDMonoMethodThunk<MonoObject *> methodthunk_GodotTaskScheduler_Activate; GDMonoMethodThunkR<MonoBoolean, MonoObject *, MonoObject *> methodthunk_Delegate_Equals; @@ -114,8 +113,6 @@ struct CachedData { GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeHasFlagsAttribute; - Ref<MonoGCHandleRef> task_scheduler_handle; - bool corlib_cache_updated; bool godot_api_cache_updated; diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index ef6a008a25..8828ec588b 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -40,9 +40,7 @@ namespace GDMonoMarshal { // TODO: Those are just temporary until the code that needs them is moved to C# Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant) { - if (p_type.type_encoding == MONO_TYPE_VOID) { - return Variant::NIL; - } + CRASH_COND(p_type.type_class == nullptr); MonoReflectionType *refltype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); MonoBoolean nil_is_variant = false; @@ -137,59 +135,6 @@ Variant mono_object_to_variant_no_err(MonoObject *p_obj) { return mono_object_to_variant_impl(p_obj, /* fail_with_err: */ false); } -String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) { - if (p_obj == nullptr) { - return String("null"); - } - - Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj); - - if (var.get_type() == Variant::NIL) { // `&& p_obj != nullptr` but omitted because always true - // Cannot convert MonoObject* to Variant; fallback to 'ToString()'. - MonoException *exc = nullptr; - MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc); - - if (exc) { - if (r_exc) { - *r_exc = exc; - } - return String(); - } - - return GDMonoMarshal::mono_string_to_godot(mono_str); - } else { - return var.operator String(); - } -} - -MonoArray *Array_to_mono_array(const Array &p_array) { - int length = p_array.size(); - MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), length); - - for (int i = 0; i < length; i++) { - MonoObject *boxed = variant_to_mono_object(p_array[i]); - mono_array_setref(ret, i, boxed); - } - - return ret; -} - -Array mono_array_to_Array(MonoArray *p_array) { - Array ret; - if (!p_array) { - return ret; - } - int length = mono_array_length(p_array); - ret.resize(length); - - for (int i = 0; i < length; i++) { - MonoObject *elem = mono_array_get(p_array, MonoObject *, i); - ret[i] = mono_object_to_variant(elem); - } - - return ret; -} - MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array) { const String *r = p_array.ptr(); int length = p_array.size(); diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 16683de51a..fbe5795df5 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -88,15 +88,6 @@ _FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var) { Variant mono_object_to_variant(MonoObject *p_obj); Variant mono_object_to_variant_no_err(MonoObject *p_obj); -/// Tries to convert the MonoObject* to Variant and then convert the Variant to String. -/// If the MonoObject* cannot be converted to Variant, then 'ToString()' is called instead. -String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc); - -// Array - -MonoArray *Array_to_mono_array(const Array &p_array); -Array mono_array_to_Array(MonoArray *p_array); - // PackedStringArray MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array); diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index 04f6005338..97d3c82230 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -253,9 +253,13 @@ const MethodInfo &GDMonoMethod::get_method_info() { method_info.name = name; bool nil_is_variant = false; - method_info.return_val = PropertyInfo(GDMonoMarshal::managed_to_variant_type(return_type, &nil_is_variant), ""); - if (method_info.return_val.type == Variant::NIL && nil_is_variant) { - method_info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + if (return_type.type_encoding == MONO_TYPE_VOID) { + method_info.return_val = PropertyInfo(Variant::NIL, ""); + } else { + method_info.return_val = PropertyInfo(GDMonoMarshal::managed_to_variant_type(return_type, &nil_is_variant), ""); + if (method_info.return_val.type == Variant::NIL && nil_is_variant) { + method_info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + } } Vector<StringName> names; |