Jelajahi Sumber

C#: Re-write GD and some other icalls as P/Invoke

Ignacio Roldán Etcheverry 4 tahun lalu
induk
melakukan
5e37d073bb

+ 8 - 13
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);
 		}
 	}
 }

+ 7 - 13
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;
     }
 }

+ 15 - 5
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);
+        }
     }
 }

+ 70 - 130
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);
     }
 }

+ 2 - 0
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")]

+ 8 - 6
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;
         }

+ 84 - 0
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);
     }
 }

+ 5 - 5
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);
     }
 }

+ 10 - 0
modules/mono/glue/GodotSharp/GodotSharp/Core/ScriptManager.cs

@@ -0,0 +1,10 @@
+namespace Godot
+{
+    internal class ScriptManager
+    {
+        internal static void FrameCallback()
+        {
+            Dispatcher.DefaultGodotTaskScheduler?.Activate();
+        }
+    }
+}

+ 1 - 0
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" />

+ 0 - 36
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);
 }

+ 0 - 342
modules/mono/glue/gd_glue.cpp

@@ -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);
-}

+ 212 - 2
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,
 };

+ 2 - 4
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.");

+ 10 - 8
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;
 }

+ 0 - 3
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;
 

+ 1 - 56
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();

+ 0 - 9
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);

+ 7 - 3
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;