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

This commit is contained in:
Ignacio Roldán Etcheverry 2021-09-12 19:50:13 +02:00
parent bbde1b1f09
commit 3f1a620102
19 changed files with 422 additions and 592 deletions

View file

@ -106,7 +106,7 @@ Error CSharpLanguage::execute_file(const String &p_path) {
return OK;
}
extern void *godotsharp_pinvoke_funcs[130];
extern void *godotsharp_pinvoke_funcs[154];
[[maybe_unused]] volatile void **do_not_strip_godotsharp_pinvoke_funcs;
void CSharpLanguage::init() {
@ -717,19 +717,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;
MonoException *exc = nullptr;
gdmono->get_core_api_assembly()
->get_class("Godot", "ScriptManager")
->get_method("FrameCallback")
->invoke(nullptr, &exc);
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);
if (exc) {
GDMonoUtils::debug_unhandled_exception(exc);
}
}
if (exc) {
GDMonoUtils::debug_unhandled_exception(exc);
}
}
}

View file

@ -1,13 +1,14 @@
using System.Runtime.CompilerServices;
namespace Godot
{
public static class Dispatcher
{
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern GodotTaskScheduler godot_icall_DefaultGodotTaskScheduler();
internal static GodotTaskScheduler DefaultGodotTaskScheduler;
public static GodotSynchronizationContext SynchronizationContext =>
godot_icall_DefaultGodotTaskScheduler().Context;
private static void InitializeDefaultGodotTaskScheduler()
{
DefaultGodotTaskScheduler = new GodotTaskScheduler();
}
public static GodotSynchronizationContext SynchronizationContext => DefaultGodotTaskScheduler.Context;
}
}

View file

@ -1,5 +1,5 @@
using System;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
namespace Godot
{
@ -12,10 +12,20 @@ namespace Godot
public static WeakRef WeakRef(Object obj)
{
return godot_icall_Object_weakref(Object.GetPtr(obj));
}
if (!IsInstanceValid(obj))
return null;
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static WeakRef godot_icall_Object_weakref(IntPtr obj);
using godot_ref weakRef = default;
unsafe
{
NativeFuncs.godotsharp_weakref(GetPtr(obj), &weakRef);
}
if (weakRef.IsNull)
return null;
return (WeakRef)InteropUtils.UnmanagedGetManaged(weakRef._reference);
}
}
}

View file

@ -5,7 +5,6 @@ using real_t = System.Single;
#endif
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
// TODO: Add comments describing what this class does. It is not obvious.
@ -17,12 +16,17 @@ 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);
}
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, type, &ret);
return Marshaling.variant_to_mono_object(&ret);
}
public static real_t Db2Linear(real_t db)
@ -30,7 +34,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)
{
@ -40,14 +44,15 @@ namespace Godot
return Array.ConvertAll(parameters, x => x?.ToString() ?? "null");
}
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);
}
public static Object InstanceFromId(ulong instanceId)
{
return godot_icall_GD_instance_from_id(instanceId);
return InteropUtils.UnmanagedGetManaged(NativeFuncs.godotsharp_instance_from_id(instanceId));
}
public static real_t Linear2Db(real_t linear)
@ -65,19 +70,23 @@ namespace Godot
return ResourceLoader.Load<T>(path);
}
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);
}
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);
}
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);
}
public static void PrintStack()
@ -85,54 +94,62 @@ namespace Godot
Print(System.Environment.StackTrace);
}
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);
}
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);
}
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);
}
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);
}
public static float Randf()
{
return godot_icall_GD_randf();
return NativeFuncs.godotsharp_randf();
}
public static uint Randi()
{
return godot_icall_GD_randi();
return NativeFuncs.godotsharp_randi();
}
public static void Randomize()
{
godot_icall_GD_randomize();
NativeFuncs.godotsharp_randomize();
}
public static double RandRange(double from, double to)
{
return godot_icall_GD_randf_range(from, to);
return NativeFuncs.godotsharp_randf_range(from, to);
}
public static int RandRange(int from, int to)
{
return godot_icall_GD_randi_range(from, to);
return NativeFuncs.godotsharp_randi_range(from, to);
}
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);
}
public static IEnumerable<int> Range(int end)
@ -167,114 +184,45 @@ namespace Godot
public static void Seed(ulong seed)
{
godot_icall_GD_seed(seed);
NativeFuncs.godotsharp_seed(seed);
}
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);
}
public static object Str2Var(string str)
public static unsafe object Str2Var(string str)
{
return godot_icall_GD_str2var(str);
}
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);
}
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);
}
}
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);
}
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_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 float godot_icall_GD_randf();
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern uint godot_icall_GD_randi();
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void godot_icall_GD_randomize();
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern double godot_icall_GD_randf_range(double from, double to);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int godot_icall_GD_randi_range(int from, int to);
[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);
}
}

View file

@ -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")]

View file

@ -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:
@ -190,8 +192,6 @@ namespace Godot.NativeInterop
}
}
r_nil_is_variant = false;
// Unknown
return Variant.Type.Nil;
}
@ -687,7 +687,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[]))
@ -1106,7 +1106,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));
@ -1114,7 +1114,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;
}

View file

@ -485,5 +485,83 @@ 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, Variant.Type 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_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 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);
}
}

View file

@ -1,5 +1,6 @@
using System;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
namespace Godot
{
@ -85,9 +86,11 @@ namespace Godot
_disposed = true;
}
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>
@ -170,8 +173,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);
}
}

View file

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

View file

@ -69,6 +69,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" />

View file

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

View file

@ -1,315 +0,0 @@
/*************************************************************************/
/* gd_glue.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 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_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);
}
float godot_icall_GD_randf() {
return Math::randf();
}
uint32_t godot_icall_GD_randi() {
return Math::rand();
}
void godot_icall_GD_randomize() {
Math::randomize();
}
double godot_icall_GD_randf_range(double from, double to) {
return Math::random(from, to);
}
int32_t godot_icall_GD_randi_range(int32_t from, int32_t to) {
return Math::random(from, to);
}
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_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_randf", godot_icall_GD_randf);
GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randi", godot_icall_GD_randi);
GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randomize", godot_icall_GD_randomize);
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_randi_range", godot_icall_GD_randi_range);
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);
}

View file

@ -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 <gdnative/gdnative.h>
@ -700,12 +702,186 @@ bool godotsharp_node_path_is_absolute(const NodePath *p_self) {
return p_self->is_absolute();
}
void godotsharp_randomize() {
Math::randomize();
}
uint32_t godotsharp_randi() {
return Math::rand();
}
float godotsharp_randf() {
return Math::randf();
}
int32_t godotsharp_randi_range(int32_t p_from, int32_t p_to) {
return Math::random(p_from, p_to);
}
double godotsharp_randf_range(double p_from, double p_to) {
return Math::random(p_from, p_to);
}
void godotsharp_seed(uint64_t p_seed) {
Math::seed(p_seed);
}
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;
}
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 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));
}
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;
}
}
}
void godotsharp_print(const godot_string *p_what) {
print_line(*reinterpret_cast<const String *>(p_what));
}
void godotsharp_printerr(const godot_string *p_what) {
print_error(*reinterpret_cast<const String *>(p_what));
}
void godotsharp_printt(const godot_string *p_what) {
print_line(*reinterpret_cast<const String *>(p_what));
}
void godotsharp_prints(const godot_string *p_what) {
print_line(*reinterpret_cast<const String *>(p_what));
}
void godotsharp_printraw(const godot_string *p_what) {
OS::get_singleton()->print("%s", reinterpret_cast<const String *>(p_what)->utf8().get_data());
}
void godotsharp_pusherror(const godot_string *p_str) {
ERR_PRINT(*reinterpret_cast<const String *>(p_str));
}
void godotsharp_pushwarning(const godot_string *p_str) {
WARN_PRINT(*reinterpret_cast<const String *>(p_str));
}
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);
}
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));
}
void godotsharp_var2bytes(const godot_variant *p_var, bool p_full_objects, godot_packed_byte_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);
}
void godotsharp_bytes2var(const godot_packed_byte_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));
}
int godotsharp_hash(const godot_variant *p_var) {
return reinterpret_cast<const Variant *>(p_var)->hash();
}
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));
}
Object *godotsharp_instance_from_id(uint64_t p_instance_id) {
return ObjectDB::get_instance(ObjectID(p_instance_id));
}
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[130] = {
void *godotsharp_pinvoke_funcs[154] = {
(void *)godotsharp_method_bind_get_method,
(void *)godotsharp_get_class_constructor,
(void *)godotsharp_invoke_class_constructor,
@ -835,5 +1011,29 @@ void *godotsharp_pinvoke_funcs[130] = {
(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_seed,
(void *)godotsharp_rand_from_seed,
(void *)godotsharp_weakref,
(void *)godotsharp_str,
(void *)godotsharp_print,
(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,
};

View file

@ -444,22 +444,13 @@ bool GDMono::_are_api_assemblies_out_of_sync() {
return out_of_sync;
}
void godot_register_collections_icalls();
void godot_register_gd_icalls();
void godot_register_node_path_icalls();
void godot_register_object_icalls();
void godot_register_rid_icalls();
void godot_register_string_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_collections_icalls();
godot_register_gd_icalls();
godot_register_node_path_icalls();
godot_register_object_icalls();
godot_register_string_icalls();
godot_register_scene_tree_icalls();
godot_register_placeholder_icalls();
}
@ -1001,6 +992,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) {
@ -1054,8 +1047,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.");

View file

@ -112,7 +112,6 @@ void CachedData::clear_godot_api_cache() {
methodthunk_GodotObject_Dispose.nullify();
methodthunk_SignalAwaiter_SignalCallback.nullify();
methodthunk_GodotTaskScheduler_Activate.nullify();
methodthunk_Delegate_Equals.nullify();
@ -131,8 +130,6 @@ void CachedData::clear_godot_api_cache() {
methodthunk_Marshaling_mono_object_to_variant_out.nullify();
methodthunk_Marshaling_SetFieldValue.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))
@ -188,7 +185,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));
@ -222,10 +218,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;
}

View file

@ -86,7 +86,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;
@ -108,8 +107,6 @@ struct CachedData {
GDMonoMethodThunk<MonoReflectionField *, MonoObject *, const Variant *> methodthunk_Marshaling_SetFieldValue;
Ref<MonoGCHandleRef> task_scheduler_handle;
bool corlib_cache_updated;
bool godot_api_cache_updated;

View file

@ -40,6 +40,8 @@ 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) {
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;
@ -133,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();

View file

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

View file

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