summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/mono/csharp_script.cpp1311
-rw-r--r--modules/mono/csharp_script.h85
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs11
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs63
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs23
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs24
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs48
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs154
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs73
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs38
-rw-r--r--modules/mono/editor/bindings_generator.cpp119
-rw-r--r--modules/mono/editor/bindings_generator.h2
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp235
-rw-r--r--modules/mono/editor/godotsharp_export.cpp4
-rw-r--r--modules/mono/editor/godotsharp_export.h4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs123
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs501
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs14
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs62
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs48
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs102
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs30
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs12
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs270
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/ScriptManager.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs34
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj4
-rw-r--r--modules/mono/glue/base_object_glue.cpp26
-rw-r--r--modules/mono/glue/placeholder_glue.cpp161
-rw-r--r--modules/mono/glue/runtime_interop.cpp12
-rw-r--r--modules/mono/glue/scene_tree_glue.cpp81
-rw-r--r--modules/mono/godotsharp_defs.h1
-rw-r--r--modules/mono/godotsharp_dirs.cpp38
-rw-r--r--modules/mono/godotsharp_dirs.h6
-rw-r--r--modules/mono/managed_callable.cpp19
-rw-r--r--modules/mono/managed_callable.h7
-rw-r--r--modules/mono/mono_gc_handle.cpp36
-rw-r--r--modules/mono/mono_gc_handle.h53
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp446
-rw-r--r--modules/mono/mono_gd/gd_mono.h70
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp102
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h41
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp234
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h134
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp569
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h160
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp149
-rw-r--r--modules/mono/mono_gd/gd_mono_field.h78
-rw-r--r--modules/mono/mono_gd/gd_mono_header.h52
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp80
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.h4
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp151
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h97
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp295
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h96
-rw-r--r--modules/mono/mono_gd/gd_mono_method_thunk.h258
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp197
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h78
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp262
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h38
-rw-r--r--modules/mono/mono_gd/i_mono_class_member.h70
-rw-r--r--modules/mono/mono_gd/managed_type.cpp58
-rw-r--r--modules/mono/mono_gd/managed_type.h55
-rw-r--r--modules/mono/mono_gd/support/android_support.cpp2
-rw-r--r--modules/mono/signal_awaiter_utils.cpp79
-rw-r--r--modules/mono/signal_awaiter_utils.h8
79 files changed, 2557 insertions, 5218 deletions
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 4316f38bd2..b088271b18 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -59,8 +59,6 @@
#include "godotsharp_dirs.h"
#include "managed_callable.h"
#include "mono_gd/gd_mono_cache.h"
-#include "mono_gd/gd_mono_class.h"
-#include "mono_gd/gd_mono_marshal.h"
#include "mono_gd/gd_mono_utils.h"
#include "signal_awaiter_utils.h"
#include "utils/macros.h"
@@ -590,6 +588,8 @@ String CSharpLanguage::debug_get_stack_level_source(int p_level) const {
return String();
}
+#warning TODO
+#if 0
Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() {
#ifdef DEBUG_ENABLED
// Printing an error here will result in endless recursion, so we must be careful
@@ -682,6 +682,11 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec
return si;
}
#endif
+#else
+Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() {
+ return Vector<StackInfo>();
+}
+#endif
void CSharpLanguage::post_unsafe_reference(Object *p_obj) {
#ifdef DEBUG_ENABLED
@@ -706,37 +711,13 @@ void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) {
void CSharpLanguage::frame() {
if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != nullptr) {
MonoException *exc = nullptr;
- gdmono->get_core_api_assembly()
- ->get_class("Godot", "ScriptManager")
- ->get_method("FrameCallback")
- ->invoke(nullptr, &exc);
-
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_FrameCallback.invoke(&exc);
if (exc) {
GDMonoUtils::debug_unhandled_exception(exc);
}
}
}
-struct CSharpScriptDepSort {
- // must support sorting so inheritance works properly (parent must be reloaded first)
- bool operator()(const Ref<CSharpScript> &A, const Ref<CSharpScript> &B) const {
- if (A == B) {
- return false; // shouldn't happen but..
- }
- GDMonoClass *I = B->base;
- while (I) {
- if (I == A->script_class) {
- // A is a base of B
- return true;
- }
-
- I = I->get_parent_class();
- }
-
- return false; // not a base
- }
-};
-
void CSharpLanguage::reload_all_scripts() {
#ifdef GD_MONO_HOT_RELOAD
if (is_assembly_reloading_needed()) {
@@ -803,6 +784,8 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
return;
}
+#warning TODO ALCs after switching to .NET 6
+#if 0
// There is no soft reloading with Mono. It's always hard reloading.
List<Ref<CSharpScript>> scripts;
@@ -829,7 +812,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
MonoException *exc = nullptr;
- bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TrySerializeDelegateWithGCHandle)
+ bool success = (bool)GDMonoCache::cached_data.methodthunk_DelegateUtils_TrySerializeDelegateWithGCHandle
.invoke(managed_callable->delegate_handle,
managed_serialized_data, &exc);
@@ -909,7 +892,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
CSharpInstance *csi = static_cast<CSharpInstance *>(obj->get_script_instance());
// Call OnBeforeSerialize
- if (csi->script->script_class->implements_interface(CACHED_CLASS(ISerializationListener))) {
+ if (csi->script->script_class->implements_interface(GDMonoCache::cached_data.class_ISerializationListener)) {
obj->get_script_instance()->call(string_names.on_before_serialize);
}
@@ -977,7 +960,6 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
#ifdef TOOLS_ENABLED
script->exports_invalidated = true;
#endif
- script->signals_invalidated = true;
if (!script->get_path().is_empty()) {
script->reload(p_soft_reload);
@@ -1011,7 +993,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
continue;
}
- bool obj_type = CACHED_CLASS(GodotObject)->is_assignable_from(script_class);
+ bool obj_type = GDMonoCache::cached_data.class_GodotObject->is_assignable_from(script_class);
if (!obj_type) {
// The class no longer inherits Godot.Object, can't reload
script->pending_reload_instances.clear();
@@ -1103,20 +1085,20 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
const StringName &name = G.first;
const Array &serialized_data = G.second;
- HashMap<StringName, CSharpScript::EventSignal>::Iterator match = script->event_signals.find(name);
+ HashMap<StringName, GDMonoField *>::Iterator match = script->event_signals.find(name);
if (!match) {
// The event or its signal attribute were removed
continue;
}
- const CSharpScript::EventSignal &event_signal = match->value;
+ GDMonoField *event_signal_field = match->value;
MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
MonoDelegate *delegate = nullptr;
MonoException *exc = nullptr;
- bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TryDeserializeDelegate).invoke(managed_serialized_data, &delegate, &exc);
+ bool success = (bool)GDMonoCache::cached_data.methodthunk_DelegateUtils_TryDeserializeDelegate.invoke(managed_serialized_data, &delegate, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
@@ -1125,14 +1107,14 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
if (success) {
ERR_CONTINUE(delegate == nullptr);
- event_signal.field->set_value(csi->get_mono_object(), (MonoObject *)delegate);
+ event_signal_field->set_value(csi->get_mono_object(), (MonoObject *)delegate);
} else if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Failed to deserialize event signal delegate\n");
}
}
// Call OnAfterDeserialization
- if (csi->script->script_class->implements_interface(CACHED_CLASS(ISerializationListener))) {
+ if (csi->script->script_class->implements_interface(GDMonoCache::cached_data.class_ISerializationListener)) {
obj->get_script_instance()->call(string_names.on_after_deserialize);
}
}
@@ -1153,7 +1135,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
void *delegate = nullptr;
MonoException *exc = nullptr;
- bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TryDeserializeDelegateWithGCHandle)
+ bool success = (bool)GDMonoCache::cached_data.methodthunk_DelegateUtils_TryDeserializeDelegateWithGCHandle
.invoke(managed_serialized_data, &delegate, &exc);
if (exc) {
@@ -1179,62 +1161,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
NodeDock::get_singleton()->update_lists();
}
#endif
-}
#endif
-
-void CSharpLanguage::lookup_script_for_class(GDMonoClass *p_class) {
- if (!p_class->has_attribute(CACHED_CLASS(ScriptPathAttribute))) {
- return;
- }
-
- MonoObject *attr = p_class->get_attribute(CACHED_CLASS(ScriptPathAttribute));
- String path = CACHED_FIELD(ScriptPathAttribute, path)->get_string_value(attr);
-
- dotnet_script_lookup_map[path] = DotNetScriptLookupInfo(
- p_class->get_namespace(), p_class->get_name(), p_class);
-}
-
-void CSharpLanguage::lookup_scripts_in_assembly(GDMonoAssembly *p_assembly) {
- if (p_assembly->has_attribute(CACHED_CLASS(AssemblyHasScriptsAttribute))) {
- MonoObject *attr = p_assembly->get_attribute(CACHED_CLASS(AssemblyHasScriptsAttribute));
- bool requires_lookup = CACHED_FIELD(AssemblyHasScriptsAttribute, requiresLookup)->get_bool_value(attr);
-
- if (requires_lookup) {
- // This is supported for scenarios where specifying all types would be cumbersome,
- // such as when disabling C# source generators (for whatever reason) or when using a
- // language other than C# that has nothing similar to source generators to automate it.
- MonoImage *image = p_assembly->get_image();
-
- int rows = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF);
-
- for (int i = 1; i < rows; i++) {
- // We don't search inner classes, only top-level.
- MonoClass *mono_class = mono_class_get(image, (i + 1) | MONO_TOKEN_TYPE_DEF);
-
- if (!mono_class_is_assignable_from(CACHED_CLASS_RAW(GodotObject), mono_class)) {
- continue;
- }
-
- GDMonoClass *current = p_assembly->get_class(mono_class);
- if (current) {
- lookup_script_for_class(current);
- }
- }
- } else {
- // This is the most likely scenario as we use C# source generators
- MonoArray *script_types = (MonoArray *)CACHED_FIELD(AssemblyHasScriptsAttribute, scriptTypes)->get_value(attr);
-
- int length = mono_array_length(script_types);
-
- for (int i = 0; i < length; i++) {
- MonoReflectionType *reftype = mono_array_get(script_types, MonoReflectionType *, i);
- ManagedType type = ManagedType::from_reftype(reftype);
- ERR_CONTINUE(!type.type_class);
- lookup_script_for_class(type.type_class);
- }
- }
- }
}
+#endif
void CSharpLanguage::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("cs");
@@ -1308,8 +1237,6 @@ void CSharpLanguage::_on_scripts_domain_about_to_unload() {
}
}
#endif
-
- dotnet_script_lookup_map.clear();
}
#ifdef TOOLS_ENABLED
@@ -1318,18 +1245,20 @@ void CSharpLanguage::_editor_init_callback() {
// Initialize GodotSharpEditor
- GDMonoClass *editor_klass = GDMono::get_singleton()->get_tools_assembly()->get_class("GodotTools", "GodotSharpEditor");
+ MonoClass *editor_klass = mono_class_from_name(
+ GDMono::get_singleton()->get_tools_assembly()->get_image(),
+ "GodotTools", "GodotSharpEditor");
CRASH_COND(editor_klass == nullptr);
- MonoObject *mono_object = mono_object_new(mono_domain_get(), editor_klass->get_mono_ptr());
- CRASH_COND(mono_object == nullptr);
+ MonoMethod *create_instance = mono_class_get_method_from_name(editor_klass, "InternalCreateInstance", 0);
+ CRASH_COND(create_instance == nullptr);
MonoException *exc = nullptr;
- GDMonoUtils::runtime_object_init(mono_object, editor_klass, &exc);
+ MonoObject *ret = mono_runtime_invoke(create_instance, nullptr, nullptr, (MonoObject **)&exc);
UNHANDLED_EXCEPTION(exc);
- EditorPlugin *godotsharp_editor = Object::cast_to<EditorPlugin>(
- GDMonoMarshal::mono_object_to_variant(mono_object).operator Object *());
+ EditorPlugin *godotsharp_editor = *(EditorPlugin **)mono_object_unbox(ret);
+
CRASH_COND(godotsharp_editor == nullptr);
// Enable it as a plugin
@@ -1353,24 +1282,17 @@ void CSharpLanguage::release_script_gchandle(MonoGCHandleData &p_gchandle) {
}
}
-void CSharpLanguage::release_script_gchandle(MonoObject *p_expected_obj, MonoGCHandleData &p_gchandle) {
- uint32_t pinned_gchandle = GDMonoUtils::new_strong_gchandle_pinned(p_expected_obj); // We might lock after this, so pin it
+void CSharpLanguage::release_script_gchandle(void *p_expected_mono_obj_unused, MonoGCHandleData &p_gchandle) {
+#warning KNOWN BUG. DO NOT USE THIS IN PRODUCTION
+ // KNOWN BUG:
+ // I removed the patch from commit e558e1ec09aa27852426bbd24dfa21e9b60cfbfc.
+ // This may cause data races. Re-implementing it without the Mono embedding API would be
+ // too painful and would make the code even more of a mess than it already was.
+ // We will switch from scripts to the new extension system before a release with .NET 6 support.
+ // The problem the old patch was working around won't be present at all with the new extension system.
- if (!p_gchandle.is_released()) { // Do not lock unnecessarily
- MutexLock lock(get_singleton()->script_gchandle_release_mutex);
-
- MonoObject *target = p_gchandle.get_target();
-
- // We release the gchandle if it points to the MonoObject* we expect (otherwise it was
- // already released and could have been replaced) or if we can't get its target MonoObject*
- // (which doesn't necessarily mean it was released, and we want it released in order to
- // avoid locking other threads unnecessarily).
- if (target == p_expected_obj || target == nullptr) {
- p_gchandle.release();
- }
- }
-
- GDMonoUtils::free_gchandle(pinned_gchandle);
+ (void)p_expected_mono_obj_unused;
+ return release_script_gchandle(p_gchandle);
}
CSharpLanguage::CSharpLanguage() {
@@ -1402,18 +1324,25 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
ERR_FAIL_NULL_V(classinfo, false);
type_name = classinfo->name;
- GDMonoClass *type_class = GDMonoUtils::type_get_proxy_class(type_name);
+ bool parent_is_object_class = ClassDB::is_parent_class(p_object->get_class_name(), type_name);
+ ERR_FAIL_COND_V_MSG(!parent_is_object_class, false,
+ "Type inherits from native type '" + type_name + "', so it can't be instantiated in object of type: '" + p_object->get_class() + "'.");
- ERR_FAIL_NULL_V(type_class, false);
+ MonoException *exc = nullptr;
+ GCHandleIntPtr strong_gchandle =
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectBinding
+ .invoke(&type_name, p_object, &exc);
- MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(type_class, type_name, p_object);
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ return false;
+ }
- ERR_FAIL_NULL_V(mono_object, false);
+ ERR_FAIL_NULL_V(strong_gchandle.value, false);
r_script_binding.inited = true;
r_script_binding.type_name = type_name;
- r_script_binding.wrapper_class = type_class; // cache
- r_script_binding.gchandle = MonoGCHandleData::new_strong_handle(mono_object);
+ r_script_binding.gchandle = MonoGCHandleData(strong_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
r_script_binding.owner = p_object;
// Tie managed to unmanaged
@@ -1478,11 +1407,13 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
if (script_binding.inited) {
// Set the native instance field to IntPtr.Zero, if not yet garbage collected.
// This is done to avoid trying to dispose the native instance from Dispose(bool).
- MonoObject *mono_object = script_binding.gchandle.get_target();
- if (mono_object) {
- CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, nullptr);
- }
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_SetGodotObjectPtr
+ .invoke(script_binding.gchandle.get_intptr(), nullptr, &exc);
+ UNHANDLED_EXCEPTION(exc);
+
script_binding.gchandle.release();
+ script_binding.inited = false;
}
csharp_lang->script_bindings.erase(data);
@@ -1517,15 +1448,23 @@ GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token,
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
- MonoObject *target = gchandle.get_target();
- if (!target) {
+ // Release the current weak handle and replace it with a strong handle.
+
+ GCHandleIntPtr old_gchandle = gchandle.get_intptr();
+ gchandle.handle = GCHandleIntPtr(); // No longer owns the handle (released by swap function)
+
+ GCHandleIntPtr new_gchandle;
+ bool create_weak = false;
+ MonoException *exc = nullptr;
+ bool target_alive = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_SwapGCHandleForType
+ .invoke(old_gchandle, &new_gchandle, create_weak, &exc);
+ UNHANDLED_EXCEPTION(exc);
+
+ if (!target_alive) {
return false; // Called after the managed side was collected, so nothing to do here
}
- // Release the current weak handle and replace it with a strong handle.
- MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(target);
- gchandle.release();
- gchandle = strong_gchandle;
+ gchandle = MonoGCHandleData(new_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
}
return false;
@@ -1537,15 +1476,23 @@ GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token,
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
- MonoObject *target = gchandle.get_target();
- if (!target) {
+ // Release the current strong handle and replace it with a weak handle.
+
+ GCHandleIntPtr old_gchandle = gchandle.get_intptr();
+ gchandle.handle = GCHandleIntPtr(); // No longer owns the handle (released by swap function)
+
+ GCHandleIntPtr new_gchandle;
+ bool create_weak = true;
+ MonoException *exc = nullptr;
+ bool target_alive = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_SwapGCHandleForType
+ .invoke(old_gchandle, &new_gchandle, create_weak, &exc);
+ UNHANDLED_EXCEPTION(exc);
+
+ if (!target_alive) {
return refcount == 0; // Called after the managed side was collected, so nothing to do here
}
- // Release the current strong handle and replace it with a weak handle.
- MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(target);
- gchandle.release();
- gchandle = weak_gchandle;
+ gchandle = MonoGCHandleData(new_gchandle, gdmono::GCHandleType::WEAK_HANDLE);
return false;
}
@@ -1590,151 +1537,175 @@ void CSharpLanguage::set_instance_binding(Object *p_object, void *p_binding) {
bool CSharpLanguage::has_instance_binding(Object *p_object) {
return p_object->has_instance_binding(get_singleton());
}
+void CSharpLanguage::tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, const StringName *p_native_name, bool p_ref_counted) {
+ // This method should not fail
-CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) {
- CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(p_script)));
+ CRASH_COND(!p_unmanaged);
- RefCounted *rc = Object::cast_to<RefCounted>(p_owner);
+ // All mono objects created from the managed world (e.g.: 'new Player()')
+ // need to have a CSharpScript in order for their methods to be callable from the unmanaged side
- instance->base_ref_counted = rc != nullptr;
- instance->owner = p_owner;
- instance->gchandle = p_gchandle;
+ RefCounted *rc = Object::cast_to<RefCounted>(p_unmanaged);
- if (instance->base_ref_counted) {
- instance->_reference_owner_unsafe();
+ CRASH_COND(p_ref_counted != (bool)rc);
+
+ MonoGCHandleData gchandle = MonoGCHandleData(p_gchandle_intptr,
+ p_ref_counted ? gdmono::GCHandleType::WEAK_HANDLE : gdmono::GCHandleType::STRONG_HANDLE);
+
+ // If it's just a wrapper Godot class and not a custom inheriting class, then attach a
+ // script binding instead. One of the advantages of this is that if a script is attached
+ // later and it's not a C# script, then the managed object won't have to be disposed.
+ // Another reason for doing this is that this instance could outlive CSharpLanguage, which would
+ // be problematic when using a script. See: https://github.com/godotengine/godot/issues/25621
+
+ CSharpScriptBinding script_binding;
+
+ script_binding.inited = true;
+ script_binding.type_name = *p_native_name;
+ script_binding.gchandle = gchandle;
+ script_binding.owner = p_unmanaged;
+
+ if (p_ref_counted) {
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
+
+ // May not me referenced yet, so we must use init_ref() instead of reference()
+ if (rc->init_ref()) {
+ CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
+ }
}
- p_script->instances.insert(p_owner);
+ // The object was just created, no script instance binding should have been attached
+ CRASH_COND(CSharpLanguage::has_instance_binding(p_unmanaged));
- return instance;
-}
+ void *data;
+ {
+ MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
+ data = (void *)CSharpLanguage::get_singleton()->insert_script_binding(p_unmanaged, script_binding);
+ }
-MonoObject *CSharpInstance::get_mono_object() const {
- ERR_FAIL_COND_V(gchandle.is_released(), nullptr);
- return gchandle.get_target();
+ // Should be thread safe because the object was just created and nothing else should be referencing it
+ CSharpLanguage::set_instance_binding(p_unmanaged, data);
}
-Object *CSharpInstance::get_owner() {
- return owner;
-}
+void CSharpLanguage::tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, CSharpScript *p_script, bool p_ref_counted) {
+ // This method should not fail
-bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
- ERR_FAIL_COND_V(!script.is_valid(), false);
+ CRASH_COND(!p_unmanaged);
- GD_MONO_SCOPE_THREAD_ATTACH;
+ // All mono objects created from the managed world (e.g.: 'new Player()')
+ // need to have a CSharpScript in order for their methods to be callable from the unmanaged side
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL_V(mono_object, false);
+ RefCounted *rc = Object::cast_to<RefCounted>(p_unmanaged);
- GDMonoClass *top = script->script_class;
+ CRASH_COND(p_ref_counted != (bool)rc);
- while (top && top != script->native) {
- GDMonoField *field = top->get_field(p_name);
+ MonoGCHandleData gchandle = MonoGCHandleData(p_gchandle_intptr,
+ p_ref_counted ? gdmono::GCHandleType::WEAK_HANDLE : gdmono::GCHandleType::STRONG_HANDLE);
- if (field) {
- field->set_value_from_variant(mono_object, p_value);
- return true;
- }
+ Ref<CSharpScript> script = p_script;
- GDMonoProperty *property = top->get_property(p_name);
+ CSharpScript::initialize_for_managed_type(script);
- if (property) {
- property->set_value_from_variant(mono_object, p_value);
- return true;
- }
+ CRASH_COND(script.is_null());
- top = top->get_parent_class();
- }
+ CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(p_unmanaged, script.ptr(), gchandle);
- // Call _set
+ p_unmanaged->set_script_and_instance(script, csharp_instance);
+}
- top = script->script_class;
+void CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged) {
+ // This method should not fail
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_set), 2);
+ CRASH_COND(!p_unmanaged);
- if (method) {
- Variant name = p_name;
- const Variant *args[2] = { &name, &p_value };
+ CSharpInstance *instance = CAST_CSHARP_INSTANCE(p_unmanaged->get_script_instance());
- MonoObject *ret = method->invoke(mono_object, args);
+ if (!instance) {
+ return;
+ }
- if (ret && GDMonoMarshal::unbox<MonoBoolean>(ret)) {
- return true;
- }
+ CRASH_COND(!instance->gchandle.is_released());
- break;
- }
+ // Tie managed to unmanaged
+ instance->gchandle = MonoGCHandleData(p_gchandle_intptr, gdmono::GCHandleType::STRONG_HANDLE);
- top = top->get_parent_class();
+ if (instance->base_ref_counted) {
+ instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
}
- return false;
+ {
+ MutexLock lock(CSharpLanguage::get_singleton()->get_script_instances_mutex());
+ // instances is a set, so it's safe to insert multiple times (e.g.: from _internal_new_managed)
+ instance->script->instances.insert(instance->owner);
+ }
}
-bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
- ERR_FAIL_COND_V(!script.is_valid(), false);
+CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) {
+ CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(p_script)));
- GD_MONO_SCOPE_THREAD_ATTACH;
+ RefCounted *rc = Object::cast_to<RefCounted>(p_owner);
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL_V(mono_object, false);
+ instance->base_ref_counted = rc != nullptr;
+ instance->owner = p_owner;
+ instance->gchandle = p_gchandle;
- GDMonoClass *top = script->script_class;
+ if (instance->base_ref_counted) {
+ instance->_reference_owner_unsafe();
+ }
- while (top && top != script->native) {
- GDMonoField *field = top->get_field(p_name);
+ p_script->instances.insert(p_owner);
- if (field) {
- MonoObject *value = field->get_value(mono_object);
- r_ret = GDMonoMarshal::mono_object_to_variant(value);
- return true;
- }
+ return instance;
+}
- GDMonoProperty *property = top->get_property(p_name);
+Object *CSharpInstance::get_owner() {
+ return owner;
+}
- if (property) {
- MonoException *exc = nullptr;
- MonoObject *value = property->get_value(mono_object, &exc);
- if (exc) {
- r_ret = Variant();
- GDMonoUtils::set_pending_exception(exc);
- } else {
- r_ret = GDMonoMarshal::mono_object_to_variant(value);
- }
- return true;
- }
+bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
+ ERR_FAIL_COND_V(!script.is_valid(), false);
- top = top->get_parent_class();
- }
+ GD_MONO_SCOPE_THREAD_ATTACH;
- // Call _get
+ MonoException *exc = nullptr;
+ bool ret = GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Set.invoke(
+ gchandle.get_intptr(), &p_name, &p_value, &exc);
- top = script->script_class;
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ } else if (ret) {
+ return true;
+ }
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_get), 1);
+ return false;
+}
- if (method) {
- Variant name = p_name;
- const Variant *args[1] = { &name };
+bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
+ ERR_FAIL_COND_V(!script.is_valid(), false);
- MonoObject *ret = method->invoke(mono_object, args);
+ GD_MONO_SCOPE_THREAD_ATTACH;
- if (ret) {
- r_ret = GDMonoMarshal::mono_object_to_variant(ret);
- return true;
- }
+ Variant ret_value;
- break;
- }
+ MonoException *exc = nullptr;
+ bool ret = GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Get.invoke(
+ gchandle.get_intptr(), &p_name, &ret_value, &exc);
- top = top->get_parent_class();
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ } else if (ret) {
+ r_ret = ret_value;
+ return true;
}
return false;
}
+#warning TODO
+#if 0
void CSharpInstance::get_properties_state_for_reloading(List<Pair<StringName, Variant>> &r_state) {
List<PropertyInfo> property_list;
get_property_list(&property_list);
@@ -1773,10 +1744,10 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName,
MonoObject *owner_managed = get_mono_object();
ERR_FAIL_NULL(owner_managed);
- for (const KeyValue<StringName, CSharpScript::EventSignal> &E : script->event_signals) {
- const CSharpScript::EventSignal &event_signal = E.value;
+ for (const KeyValue<StringName, GDMonoField *> &E : script->event_signals) {
+ GDMonoField *event_signal_field = E.value;
- MonoDelegate *delegate_field_value = (MonoDelegate *)event_signal.field->get_value(owner_managed);
+ MonoDelegate *delegate_field_value = (MonoDelegate *)event_signal_field->get_value(owner_managed);
if (!delegate_field_value) {
continue; // Empty
}
@@ -1785,7 +1756,7 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName,
MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
MonoException *exc = nullptr;
- bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TrySerializeDelegate)
+ bool success = (bool)GDMonoCache::cached_data.methodthunk_DelegateUtils_TrySerializeDelegate
.invoke(delegate_field_value, managed_serialized_data, &exc);
if (exc) {
@@ -1794,12 +1765,13 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName,
}
if (success) {
- r_state.push_back(Pair<StringName, Array>(event_signal.field->get_name(), serialized_data));
+ r_state.push_back(Pair<StringName, Array>(event_signal_field->get_name(), serialized_data));
} else if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Failed to serialize event signal delegate\n");
}
}
}
+#endif
void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
List<PropertyInfo> props;
@@ -1811,28 +1783,24 @@ void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
GD_MONO_SCOPE_THREAD_ATTACH;
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL(mono_object);
+ StringName method = SNAME("_get_property_list");
- GDMonoClass *top = script->script_class;
-
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_get_property_list), 0);
-
- if (method) {
- MonoObject *ret = method->invoke(mono_object);
+ Variant ret;
+ Callable::CallError call_error;
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Call.invoke(
+ gchandle.get_intptr(), &method, nullptr, 0, &call_error, &ret, &exc);
- if (ret) {
- Array array = Array(GDMonoMarshal::mono_object_to_variant(ret));
- for (int i = 0, size = array.size(); i < size; i++) {
- props.push_back(PropertyInfo::from_dict(array.get(i)));
- }
- }
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ }
- break;
- }
+ ERR_FAIL_COND_MSG(call_error.error != Callable::CallError::CALL_OK,
+ "Error calling '_get_property_list': " + Variant::get_call_error_text(method, nullptr, 0, call_error));
- top = top->get_parent_class();
+ Array array = ret;
+ for (int i = 0, size = array.size(); i < size; i++) {
+ p_properties->push_back(PropertyInfo::from_dict(array.get(i)));
}
for (const PropertyInfo &prop : props) {
@@ -1860,34 +1828,26 @@ bool CSharpInstance::property_can_revert(const StringName &p_name) const {
GD_MONO_SCOPE_THREAD_ATTACH;
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL_V(mono_object, false);
-
- GDMonoClass *top = script->script_class;
-
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_property_can_revert), 1);
-
- if (method) {
- Variant name = p_name;
- const Variant *args[1] = { &name };
+ Callable::CallError call_error;
- MonoObject *ret = method->invoke(mono_object, args);
+ Variant name_arg = p_name;
+ const Variant *args[1] = { &name_arg };
- if (ret) {
- bool can_revert = GDMonoMarshal::mono_object_to_variant(ret);
- if (can_revert) {
- return true;
- }
- }
+ Variant ret;
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Call.invoke(
+ gchandle.get_intptr(), &CACHED_STRING_NAME(_property_can_revert), args, 1, &call_error, &ret, &exc);
- break;
- }
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ return false;
+ }
- top = top->get_parent_class();
+ if (call_error.error != Callable::CallError::CALL_OK) {
+ return false;
}
- return false;
+ return (bool)ret;
}
bool CSharpInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const {
@@ -1895,35 +1855,32 @@ bool CSharpInstance::property_get_revert(const StringName &p_name, Variant &r_re
GD_MONO_SCOPE_THREAD_ATTACH;
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL_V(mono_object, false);
+ Callable::CallError call_error;
- GDMonoClass *top = script->script_class;
+ Variant name_arg = p_name;
+ const Variant *args[1] = { &name_arg };
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_property_get_revert), 1);
-
- if (method) {
- Variant name = p_name;
- const Variant *args[1] = { &name };
-
- MonoObject *ret = method->invoke(mono_object, args);
-
- if (ret) {
- r_ret = GDMonoMarshal::mono_object_to_variant(ret);
- return true;
- }
+ Variant ret;
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Call.invoke(
+ gchandle.get_intptr(), &CACHED_STRING_NAME(_property_get_revert), args, 1, &call_error, &ret, &exc);
- break;
- }
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ return false;
+ }
- top = top->get_parent_class();
+ if (call_error.error != Callable::CallError::CALL_OK) {
+ return false;
}
- return false;
+ r_ret = ret;
+ return true;
}
void CSharpInstance::get_method_list(List<MethodInfo> *p_list) const {
+#warning TODO
+#if 0
if (!script->is_valid() || !script->script_class) {
return;
}
@@ -1944,6 +1901,7 @@ void CSharpInstance::get_method_list(List<MethodInfo> *p_list) const {
top = top->get_parent_class();
}
+#endif
}
bool CSharpInstance::has_method(const StringName &p_method) const {
@@ -1953,17 +1911,19 @@ bool CSharpInstance::has_method(const StringName &p_method) const {
GD_MONO_SCOPE_THREAD_ATTACH;
- GDMonoClass *top = script->script_class;
+ if (!GDMonoCache::cached_data.godot_api_cache_updated) {
+ return false;
+ }
- while (top && top != script->native) {
- if (top->has_fetched_method_unknown_params(p_method)) {
- return true;
- }
+ String method = p_method;
+ bool deep = true;
- top = top->get_parent_class();
- }
+ MonoException *exc = nullptr;
+ bool found = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_HasMethodUnknownParams
+ .invoke(script.ptr(), &method, deep, &exc);
+ UNHANDLED_EXCEPTION(exc);
- return false;
+ return found;
}
Variant CSharpInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
@@ -1971,36 +1931,16 @@ Variant CSharpInstance::callp(const StringName &p_method, const Variant **p_args
GD_MONO_SCOPE_THREAD_ATTACH;
- MonoObject *mono_object = get_mono_object();
-
- if (!mono_object) {
- r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
- ERR_FAIL_V(Variant());
- }
-
- GDMonoClass *top = script->script_class;
-
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(p_method, p_argcount);
-
- if (method) {
- MonoObject *return_value = method->invoke(mono_object, p_args);
-
- r_error.error = Callable::CallError::CALL_OK;
-
- if (return_value) {
- return GDMonoMarshal::mono_object_to_variant(return_value);
- } else {
- return Variant();
- }
- }
+ Variant ret;
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Call.invoke(
+ gchandle.get_intptr(), &p_method, p_args, p_argcount, &r_error, &ret, &exc);
- top = top->get_parent_class();
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
}
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
-
- return Variant();
+ return ret;
}
bool CSharpInstance::_reference_owner_unsafe() {
@@ -2046,48 +1986,32 @@ bool CSharpInstance::_unreference_owner_unsafe() {
return static_cast<RefCounted *>(owner)->unreference();
}
-MonoObject *CSharpInstance::_internal_new_managed() {
- // Search the constructor first, to fail with an error if it's not found before allocating anything else.
- GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
- ERR_FAIL_NULL_V_MSG(ctor, nullptr,
- "Cannot create script instance because the class does not define a parameterless constructor: '" + script->get_path() + "'.");
-
+bool CSharpInstance::_internal_new_managed() {
CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
- ERR_FAIL_NULL_V(owner, nullptr);
- ERR_FAIL_COND_V(script.is_null(), nullptr);
+ ERR_FAIL_NULL_V(owner, false);
+ ERR_FAIL_COND_V(script.is_null(), false);
- MonoObject *mono_object = mono_object_new(mono_domain_get(), script->script_class->get_mono_ptr());
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance
+ .invoke(script.ptr(), owner, nullptr, 0, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
- if (!mono_object) {
// Important to clear this before destroying the script instance here
script = Ref<CSharpScript>();
-
- bool die = _unreference_owner_unsafe();
- // Not ok for the owner to die here. If there is a situation where this can happen, it will be considered a bug.
- CRASH_COND(die);
-
owner = nullptr;
- ERR_FAIL_V_MSG(nullptr, "Failed to allocate memory for the object.");
- }
-
- // Tie managed to unmanaged
- gchandle = MonoGCHandleData::new_strong_handle(mono_object);
-
- if (base_ref_counted) {
- _reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
+ return false;
}
- CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, owner);
-
- // Construct
- ctor->invoke_raw(mono_object, nullptr);
+ CRASH_COND(gchandle.is_released());
- return mono_object;
+ return true;
}
-void CSharpInstance::mono_object_disposed(MonoObject *p_obj) {
+void CSharpInstance::mono_object_disposed() {
// Must make sure event signals are not left dangling
disconnect_event_signals();
@@ -2095,10 +2019,10 @@ void CSharpInstance::mono_object_disposed(MonoObject *p_obj) {
CRASH_COND(base_ref_counted);
CRASH_COND(gchandle.is_released());
#endif
- CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle);
+ CSharpLanguage::get_singleton()->release_script_gchandle(nullptr, gchandle);
}
-void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance) {
+void CSharpInstance::mono_object_disposed_baseref(bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance) {
#ifdef DEBUG_ENABLED
CRASH_COND(!base_ref_counted);
CRASH_COND(gchandle.is_released());
@@ -2114,7 +2038,7 @@ void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_f
r_delete_owner = true;
} else {
r_delete_owner = false;
- CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle);
+ CSharpLanguage::get_singleton()->release_script_gchandle(nullptr, gchandle);
if (!p_is_finalizer) {
// If the native instance is still alive and Dispose() was called
@@ -2126,27 +2050,20 @@ void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_f
// unreference and delete it, so we want to keep it.
// GC.ReRegisterForFinalize(this) is not safe because the objects referenced by 'this'
// could have already been collected. Instead we will create a new managed instance here.
- MonoObject *new_managed = _internal_new_managed();
- if (!new_managed) {
+ if (!_internal_new_managed()) {
r_remove_script_instance = true;
}
}
}
}
-void CSharpInstance::connect_event_signals() {
- for (const KeyValue<StringName, CSharpScript::EventSignal> &E : script->event_signals) {
- const CSharpScript::EventSignal &event_signal = E.value;
-
- StringName signal_name = event_signal.field->get_name();
-
- // TODO: Use pooling for ManagedCallable instances.
- EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, &event_signal));
+void CSharpInstance::connect_event_signal(const StringName &p_event_signal) {
+ // TODO: Use pooling for ManagedCallable instances.
+ EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, p_event_signal));
- Callable callable(event_signal_callable);
- connected_event_signals.push_back(callable);
- owner->connect(signal_name, callable);
- }
+ Callable callable(event_signal_callable);
+ connected_event_signals.push_back(callable);
+ owner->connect(p_event_signal, callable);
}
void CSharpInstance::disconnect_event_signals() {
@@ -2174,9 +2091,22 @@ void CSharpInstance::refcount_incremented() {
// so the owner must hold the managed side alive again to avoid it from being GCed.
// Release the current weak handle and replace it with a strong handle.
- MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(gchandle.get_target());
- gchandle.release();
- gchandle = strong_gchandle;
+
+ GCHandleIntPtr old_gchandle = gchandle.get_intptr();
+ gchandle.handle = GCHandleIntPtr(); // No longer owns the handle (released by swap function)
+
+ GCHandleIntPtr new_gchandle;
+ bool create_weak = false;
+ MonoException *exc = nullptr;
+ bool target_alive = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_SwapGCHandleForType
+ .invoke(old_gchandle, &new_gchandle, create_weak, &exc);
+ UNHANDLED_EXCEPTION(exc);
+
+ if (!target_alive) {
+ return; // Called after the managed side was collected, so nothing to do here
+ }
+
+ gchandle = MonoGCHandleData(new_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
}
}
@@ -2197,9 +2127,22 @@ bool CSharpInstance::refcount_decremented() {
// the managed instance takes responsibility of deleting the owner when GCed.
// Release the current strong handle and replace it with a weak handle.
- MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(gchandle.get_target());
- gchandle.release();
- gchandle = weak_gchandle;
+
+ GCHandleIntPtr old_gchandle = gchandle.get_intptr();
+ gchandle.handle = GCHandleIntPtr(); // No longer owns the handle (released by swap function)
+
+ GCHandleIntPtr new_gchandle;
+ bool create_weak = true;
+ MonoException *exc = nullptr;
+ bool target_alive = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_SwapGCHandleForType
+ .invoke(old_gchandle, &new_gchandle, create_weak, &exc);
+ UNHANDLED_EXCEPTION(exc);
+
+ if (!target_alive) {
+ return refcount == 0; // Called after the managed side was collected, so nothing to do here
+ }
+
+ gchandle = MonoGCHandleData(new_gchandle, gdmono::GCHandleType::WEAK_HANDLE);
return false;
}
@@ -2235,11 +2178,9 @@ void CSharpInstance::notification(int p_notification) {
_call_notification(p_notification);
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL(mono_object);
-
MonoException *exc = nullptr;
- GDMonoUtils::dispose(mono_object, &exc);
+ GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_CallDispose
+ .invoke(gchandle.get_intptr(), /* okIfNull */ false, &exc);
if (exc) {
GDMonoUtils::set_pending_exception(exc);
@@ -2254,43 +2195,31 @@ void CSharpInstance::notification(int p_notification) {
void CSharpInstance::_call_notification(int p_notification) {
GD_MONO_ASSERT_THREAD_ATTACHED;
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL(mono_object);
-
- // Custom version of _call_multilevel, optimized for _notification
+ Variant arg = p_notification;
+ const Variant *args[1] = { &arg };
+ StringName method_name = SNAME("_notification");
- int32_t arg = p_notification;
- void *args[1] = { &arg };
- StringName method_name = CACHED_STRING_NAME(_notification);
-
- GDMonoClass *top = script->script_class;
+ Callable::CallError call_error;
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(method_name, 1);
-
- if (method) {
- method->invoke_raw(mono_object, args);
- return;
- }
+ Variant ret;
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_Call.invoke(
+ gchandle.get_intptr(), &method_name, args, 1, &call_error, &ret, &exc);
- top = top->get_parent_class();
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
}
}
String CSharpInstance::to_string(bool *r_valid) {
GD_MONO_SCOPE_THREAD_ATTACH;
- MonoObject *mono_object = get_mono_object();
-
- if (mono_object == nullptr) {
- if (r_valid) {
- *r_valid = false;
- }
- return String();
- }
+ String res;
+ bool valid;
MonoException *exc = nullptr;
- MonoString *result = GDMonoUtils::object_to_string(mono_object, &exc);
+ GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_CallToString
+ .invoke(gchandle.get_intptr(), &res, &valid, &exc);
if (exc) {
GDMonoUtils::set_pending_exception(exc);
@@ -2300,14 +2229,11 @@ String CSharpInstance::to_string(bool *r_valid) {
return String();
}
- if (result == nullptr) {
- if (r_valid) {
- *r_valid = false;
- }
- return String();
+ if (r_valid) {
+ *r_valid = valid;
}
- return GDMonoMarshal::mono_string_to_godot(result);
+ return res;
}
Ref<Script> CSharpInstance::get_script() const {
@@ -2338,15 +2264,12 @@ CSharpInstance::~CSharpInstance() {
// we must call Dispose here, because Dispose calls owner->set_script_instance(nullptr)
// and that would mess up with the new script instance if called later.
- MonoObject *mono_object = gchandle.get_target();
-
- if (mono_object) {
- MonoException *exc = nullptr;
- GDMonoUtils::dispose(mono_object, &exc);
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_CallDispose
+ .invoke(gchandle.get_intptr(), /* okIfNull */ true, &exc);
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- }
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
}
}
@@ -2424,6 +2347,8 @@ void CSharpScript::_update_member_info_no_exports() {
member_info.clear();
+#warning TODO
+#if 0
GDMonoClass *top = script_class;
List<PropertyInfo> props;
@@ -2468,6 +2393,7 @@ void CSharpScript::_update_member_info_no_exports() {
top = top->get_parent_class();
}
+#endif
}
}
#endif
@@ -2489,6 +2415,8 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
if (exports_invalidated)
#endif
{
+#warning TODO
+#if 0
GD_MONO_SCOPE_THREAD_ATTACH;
changed = true;
@@ -2524,7 +2452,7 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
MonoException *ctor_exc = nullptr;
ctor->invoke(tmp_object, nullptr, &ctor_exc);
- tmp_native = GDMonoMarshal::unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(tmp_object));
+ tmp_native = GDMonoMarshal::unbox<Object *>(GDMonoCache::cached_data.field_GodotObject_ptr->get_value(tmp_object));
if (ctor_exc) {
// TODO: Should we free 'tmp_native' if the exception was thrown after its creation?
@@ -2649,6 +2577,8 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
}
}
#endif
+
+#endif // #if 0
}
#ifdef TOOLS_ENABLED
@@ -2675,111 +2605,8 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
return changed;
}
-void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class) {
- // no need to load the script's signals more than once
- if (!signals_invalidated) {
- return;
- }
-
- // make sure this classes signals are empty when loading for the first time
- _signals.clear();
- event_signals.clear();
-
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- GDMonoClass *top = p_class;
- while (top && top != p_native_class) {
- const Vector<GDMonoClass *> &delegates = top->get_all_delegates();
- for (int i = delegates.size() - 1; i >= 0; --i) {
- GDMonoClass *delegate = delegates[i];
-
- if (!delegate->has_attribute(CACHED_CLASS(SignalAttribute))) {
- continue;
- }
-
- // Arguments are accessibles as arguments of .Invoke method
- GDMonoMethod *invoke_method = delegate->get_method(mono_get_delegate_invoke(delegate->get_mono_ptr()));
-
- Vector<SignalParameter> parameters;
- if (_get_signal(top, invoke_method, parameters)) {
- _signals[delegate->get_name()] = parameters;
- }
- }
-
- List<StringName> found_event_signals;
-
- void *iter = nullptr;
- MonoEvent *raw_event = nullptr;
- while ((raw_event = mono_class_get_events(top->get_mono_ptr(), &iter)) != nullptr) {
- MonoCustomAttrInfo *event_attrs = mono_custom_attrs_from_event(top->get_mono_ptr(), raw_event);
- if (event_attrs) {
- if (mono_custom_attrs_has_attr(event_attrs, CACHED_CLASS(SignalAttribute)->get_mono_ptr())) {
- String event_name = String::utf8(mono_event_get_name(raw_event));
- found_event_signals.push_back(StringName(event_name));
- }
-
- mono_custom_attrs_free(event_attrs);
- }
- }
-
- const Vector<GDMonoField *> &fields = top->get_all_fields();
- for (int i = 0; i < fields.size(); i++) {
- GDMonoField *field = fields[i];
-
- GDMonoClass *field_class = field->get_type().type_class;
-
- if (!mono_class_is_delegate(field_class->get_mono_ptr())) {
- continue;
- }
-
- if (!found_event_signals.find(field->get_name())) {
- continue;
- }
-
- GDMonoMethod *invoke_method = field_class->get_method(mono_get_delegate_invoke(field_class->get_mono_ptr()));
-
- Vector<SignalParameter> parameters;
- if (_get_signal(top, invoke_method, parameters)) {
- event_signals[field->get_name()] = { field, invoke_method, parameters };
- }
- }
-
- top = top->get_parent_class();
- }
-
- signals_invalidated = false;
-}
-
-bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoMethod *p_delegate_invoke, Vector<SignalParameter> &params) {
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
- Vector<StringName> names;
- Vector<ManagedType> types;
- p_delegate_invoke->get_parameter_names(names);
- p_delegate_invoke->get_parameter_types(types);
-
- for (int i = 0; i < names.size(); ++i) {
- SignalParameter arg;
- arg.name = names[i];
-
- bool nil_is_variant = false;
- arg.type = GDMonoMarshal::managed_to_variant_type(types[i], &nil_is_variant);
-
- if (arg.type == Variant::NIL) {
- if (nil_is_variant) {
- arg.nil_is_variant = true;
- } else {
- ERR_PRINT("Unknown type of signal parameter: '" + arg.name + "' in '" + p_class->get_full_name() + "'.");
- return false;
- }
- }
-
- params.push_back(arg);
- }
-
- return true;
-}
-
+#warning TODO
+#if 0
/**
* Returns false if there was an error, otherwise true.
* If there was an error, r_prop_info and r_exported are not assigned any value.
@@ -2793,7 +2620,7 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
if (p_member->is_static()) {
#ifdef TOOLS_ENABLED
- if (p_member->has_attribute(CACHED_CLASS(ExportAttribute))) {
+ if (p_member->has_attribute(GDMonoCache::cached_data.class_ExportAttribute)) {
ERR_PRINT("Cannot export member because it is static: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
}
#endif
@@ -2814,7 +2641,7 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
CRASH_NOW();
}
- bool exported = p_member->has_attribute(CACHED_CLASS(ExportAttribute));
+ bool exported = p_member->has_attribute(GDMonoCache::cached_data.class_ExportAttribute);
if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) {
GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member);
@@ -2846,7 +2673,7 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
}
#ifdef TOOLS_ENABLED
- MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute));
+ MonoObject *attr = p_member->get_attribute(GDMonoCache::cached_data.class_ExportAttribute);
#endif
PropertyHint hint = PROPERTY_HINT_NONE;
@@ -2867,8 +2694,8 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
if (hint_res == 0) {
- hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
- hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
+ hint = PropertyHint(GDMonoCache::cached_data.field_ExportAttribute_hint->get_int_value(attr));
+ hint_string = GDMonoCache::cached_data.field_ExportAttribute_hintString->get_string_value(attr);
}
#endif
@@ -2950,7 +2777,7 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
// This may not be needed in the future if the editor is changed to not display values.
r_hint_string = name_only_hint_string;
}
- } else if (p_variant_type == Variant::OBJECT && CACHED_CLASS(GodotResource)->is_assignable_from(p_type.type_class)) {
+ } else if (p_variant_type == Variant::OBJECT && GDMonoCache::cached_data.class_GodotResource->is_assignable_from(p_type.type_class)) {
GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(p_type.type_class);
CRASH_COND(field_native_class == nullptr);
@@ -3007,41 +2834,7 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
return 1;
}
#endif
-
-Variant CSharpScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (unlikely(GDMono::get_singleton() == nullptr)) {
- // Probably not the best error but eh.
- r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
- return Variant();
- }
-
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- GDMonoClass *top = script_class;
-
- while (top && top != native) {
- GDMonoMethod *method = top->get_method(p_method, p_argcount);
-
- if (method && method->is_static()) {
- MonoObject *result = method->invoke(nullptr, p_args);
-
- if (result) {
- return GDMonoMarshal::mono_object_to_variant(result);
- } else {
- return Variant();
- }
- }
-
- top = top->get_parent_class();
- }
-
- // No static method found. Try regular instance calls
- return Script::callp(p_method, p_args, p_argcount, r_error);
-}
-
-void CSharpScript::_resource_path_changed() {
- _update_name();
-}
+#endif
bool CSharpScript::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == CSharpLanguage::singleton->string_names._script_source) {
@@ -3070,30 +2863,13 @@ void CSharpScript::_bind_methods() {
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &CSharpScript::_new, MethodInfo("new"));
}
-Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native) {
- // This method should not fail, only assertions allowed
-
- CRASH_COND(p_class == nullptr);
-
- // TODO OPTIMIZE: Cache the 'CSharpScript' associated with this 'p_class' instead of allocating a new one every time
- Ref<CSharpScript> script = memnew(CSharpScript);
-
- initialize_for_managed_type(script, p_class, p_native);
+void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script) {
+ // IMPORTANT:
+ // This method must be called only after the CSharpScript and its associated type
+ // have been added to the script bridge map in the ScriptManagerBridge C# class.
- return script;
-}
-
-void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native) {
// This method should not fail, only assertions allowed
- CRASH_COND(p_class == nullptr);
-
- p_script->name = p_class->get_name();
- p_script->script_class = p_class;
- p_script->native = p_native;
-
- CRASH_COND(p_script->native == nullptr);
-
p_script->valid = true;
p_script->reload_invalidated = false;
@@ -3106,71 +2882,21 @@ void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMon
// Extract information about the script using the mono class.
void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
- GDMonoClass *base = p_script->script_class->get_parent_class();
-
- // `base` should only be set if the script is a user defined type.
- if (base != p_script->native) {
- p_script->base = base;
- }
+ bool tool = false;
+ Dictionary rpc_functions_dict;
+ // Destructor won't be called from C#, and I don't want to include the GDNative header
+ // only for this, so need to call the destructor manually before passing this to C#.
+ rpc_functions_dict.~Dictionary();
- p_script->tool = p_script->script_class->has_attribute(CACHED_CLASS(ToolAttribute));
-
- if (!p_script->tool) {
- GDMonoClass *nesting_class = p_script->script_class->get_nesting_class();
- p_script->tool = nesting_class && nesting_class->has_attribute(CACHED_CLASS(ToolAttribute));
- }
-
-#ifdef TOOLS_ENABLED
- if (!p_script->tool) {
- p_script->tool = p_script->script_class->get_assembly() == GDMono::get_singleton()->get_tools_assembly();
- }
-#endif
-
-#ifdef DEBUG_ENABLED
- // For debug builds, we must fetch from all native base methods as well.
- // Native base methods must be fetched before the current class.
- // Not needed if the script class itself is a native class.
-
- if (p_script->script_class != p_script->native) {
- GDMonoClass *native_top = p_script->native;
- while (native_top) {
- native_top->fetch_methods_with_godot_api_checks(p_script->native);
-
- if (native_top == CACHED_CLASS(GodotObject)) {
- break;
- }
-
- native_top = native_top->get_parent_class();
- }
- }
-#endif
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_UpdateScriptClassInfo
+ .invoke(p_script.ptr(), &tool, &rpc_functions_dict, &exc);
+ UNHANDLED_EXCEPTION(exc);
- p_script->script_class->fetch_methods_with_godot_api_checks(p_script->native);
+ p_script->tool = tool;
p_script->rpc_config.clear();
-
- GDMonoClass *top = p_script->script_class;
- while (top && top != p_script->native) {
- // Fetch methods from base classes as well
- top->fetch_methods_with_godot_api_checks(p_script->native);
-
- // Update RPC info
- {
- Vector<GDMonoMethod *> methods = top->get_all_methods();
- for (int i = 0; i < methods.size(); i++) {
- if (!methods[i]->is_static()) {
- const Variant rpc_config = p_script->_member_get_rpc_config(methods[i]);
- if (rpc_config.get_type() != Variant::NIL) {
- p_script->rpc_config[methods[i]->get_name()] = rpc_config;
- }
- }
- }
- }
-
- top = top->get_parent_class();
- }
-
- p_script->load_script_signals(p_script->script_class, p_script->native);
+ p_script->rpc_config = rpc_functions_dict;
}
bool CSharpScript::can_instantiate() const {
@@ -3183,13 +2909,13 @@ bool CSharpScript::can_instantiate() const {
// FIXME Need to think this through better.
// For tool scripts, this will never fire if the class is not found. That's because we
// don't know if it's a tool script if we can't find the class to access the attributes.
- if (extra_cond && !script_class) {
+ if (extra_cond && !valid) {
if (GDMono::get_singleton()->get_project_assembly() == nullptr) {
// The project assembly is not loaded
ERR_FAIL_V_MSG(false, "Cannot instance script because the project assembly is not loaded. Script: '" + get_path() + "'.");
} else {
// The project assembly is loaded, but the class could not found
- ERR_FAIL_V_MSG(false, "Cannot instance script because the class '" + name + "' could not be found. Script: '" + get_path() + "'.");
+ ERR_FAIL_V_MSG(false, "Cannot instance script because the associated class could not be found. Script: '" + get_path() + "'.");
}
}
@@ -3197,11 +2923,12 @@ bool CSharpScript::can_instantiate() const {
}
StringName CSharpScript::get_instance_base_type() const {
- if (native) {
- return native->get_name();
- } else {
- return StringName();
- }
+ StringName native_name;
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_GetScriptNativeName
+ .invoke(this, &native_name, &exc);
+ UNHANDLED_EXCEPTION(exc);
+ return native_name;
}
CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) {
@@ -3209,17 +2936,6 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
/* STEP 1, CREATE */
- // Search the constructor first, to fail with an error if it's not found before allocating anything else.
- GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
- if (ctor == nullptr) {
- ERR_FAIL_COND_V_MSG(p_argcount == 0, nullptr,
- "Cannot create script instance. The class '" + script_class->get_full_name() +
- "' does not define a parameterless constructor." +
- (get_path().is_empty() ? String() : " Path: '" + get_path() + "'."));
-
- ERR_FAIL_V_MSG(nullptr, "Constructor not found.");
- }
-
Ref<RefCounted> ref;
if (p_is_ref_counted) {
// Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance.
@@ -3233,14 +2949,12 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited && !script_binding.gchandle.is_released()) {
- MonoObject *mono_object = script_binding.gchandle.get_target();
- if (mono_object) {
- MonoException *exc = nullptr;
- GDMonoUtils::dispose(mono_object, &exc);
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_CSharpInstanceBridge_CallDispose
+ .invoke(script_binding.gchandle.get_intptr(), /* okIfNull */ true, &exc);
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- }
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
}
script_binding.gchandle.release(); // Just in case
@@ -3255,38 +2969,22 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
/* STEP 2, INITIALIZE AND CONSTRUCT */
- MonoObject *mono_object = mono_object_new(mono_domain_get(), script_class->get_mono_ptr());
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance
+ .invoke(this, p_owner, p_args, p_argcount, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
- if (!mono_object) {
// Important to clear this before destroying the script instance here
instance->script = Ref<CSharpScript>();
instance->owner = nullptr;
-
- bool die = instance->_unreference_owner_unsafe();
- // Not ok for the owner to die here. If there is a situation where this can happen, it will be considered a bug.
- CRASH_COND(die);
-
p_owner->set_script_instance(nullptr);
- r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
- ERR_FAIL_V_MSG(nullptr, "Failed to allocate memory for the object.");
- }
-
- // Tie managed to unmanaged
- instance->gchandle = MonoGCHandleData::new_strong_handle(mono_object);
- if (instance->base_ref_counted) {
- instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
- }
-
- {
- MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
- instances.insert(instance->owner);
+ return nullptr;
}
- CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, instance->owner);
-
- // Construct
- ctor->invoke(mono_object, p_args);
+ CRASH_COND(instance->gchandle.is_released());
/* STEP 3, PARTY */
@@ -3302,11 +3000,17 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
r_error.error = Callable::CallError::CALL_OK;
- ERR_FAIL_NULL_V(native, Variant());
+ StringName native_name;
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_GetScriptNativeName
+ .invoke(this, &native_name, &exc);
+ UNHANDLED_EXCEPTION(exc);
+
+ ERR_FAIL_COND_V(native_name == StringName(), Variant());
GD_MONO_SCOPE_THREAD_ATTACH;
- Object *owner = ClassDB::instantiate(NATIVE_GDMONOCLASS_NAME(native));
+ Object *owner = ClassDB::instantiate(native_name);
Ref<RefCounted> ref;
RefCounted *r = Object::cast_to<RefCounted>(owner);
@@ -3336,16 +3040,21 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
GD_MONO_SCOPE_THREAD_ATTACH;
- if (native) {
- StringName native_name = NATIVE_GDMONOCLASS_NAME(native);
- if (!ClassDB::is_parent_class(p_this->get_class_name(), native_name)) {
- if (EngineDebugger::is_active()) {
- CSharpLanguage::get_singleton()->debug_break_parse(get_path(), 0,
- "Script inherits from native type '" + String(native_name) +
- "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'");
- }
- ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(native_name) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'.");
+ StringName native_name;
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_GetScriptNativeName
+ .invoke(this, &native_name, &exc);
+ UNHANDLED_EXCEPTION(exc);
+
+ ERR_FAIL_COND_V(native_name == StringName(), nullptr);
+
+ if (!ClassDB::is_parent_class(p_this->get_class_name(), native_name)) {
+ if (EngineDebugger::is_active()) {
+ CSharpLanguage::get_singleton()->debug_break_parse(get_path(), 0,
+ "Script inherits from native type '" + String(native_name) +
+ "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'");
}
+ ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(native_name) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'.");
}
Callable::CallError unchecked_error;
@@ -3387,12 +3096,14 @@ void CSharpScript::set_source_code(const String &p_code) {
}
void CSharpScript::get_script_method_list(List<MethodInfo> *p_list) const {
- if (!script_class) {
+ if (!valid) {
return;
}
GD_MONO_SCOPE_THREAD_ATTACH;
+#warning TODO
+#if 0
// TODO: We're filtering out constructors but there may be other methods unsuitable for explicit calls.
GDMonoClass *top = script_class;
@@ -3407,35 +3118,51 @@ void CSharpScript::get_script_method_list(List<MethodInfo> *p_list) const {
top = top->get_parent_class();
}
+#endif
}
bool CSharpScript::has_method(const StringName &p_method) const {
- if (!script_class) {
+ if (!valid) {
return false;
}
GD_MONO_SCOPE_THREAD_ATTACH;
- return script_class->has_fetched_method_unknown_params(p_method);
+ if (!GDMonoCache::cached_data.godot_api_cache_updated) {
+ return false;
+ }
+
+ String method = p_method;
+ bool deep = false;
+
+ MonoException *exc = nullptr;
+ bool found = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_HasMethodUnknownParams
+ .invoke(this, &method, deep, &exc);
+ UNHANDLED_EXCEPTION(exc);
+
+ return found;
}
MethodInfo CSharpScript::get_method_info(const StringName &p_method) const {
- if (!script_class) {
+ if (!valid) {
return MethodInfo();
}
GD_MONO_SCOPE_THREAD_ATTACH;
+#warning TODO
+#if 0
GDMonoClass *top = script_class;
while (top && top != native) {
- GDMonoMethod *params = top->get_fetched_method_unknown_params(p_method);
+ GDMonoMethod *params = top->get_method_unknown_params(p_method);
if (params) {
return params->get_method_info();
}
top = top->get_parent_class();
}
+#endif
return MethodInfo();
}
@@ -3451,28 +3178,18 @@ Error CSharpScript::reload(bool p_keep_state) {
GD_MONO_SCOPE_THREAD_ATTACH;
- const DotNetScriptLookupInfo *lookup_info =
- CSharpLanguage::get_singleton()->lookup_dotnet_script(get_path());
-
- if (lookup_info) {
- GDMonoClass *klass = lookup_info->script_class;
- if (klass) {
- ERR_FAIL_COND_V(!CACHED_CLASS(GodotObject)->is_assignable_from(klass), FAILED);
- script_class = klass;
- }
- }
+ String script_path = get_path();
- valid = script_class != nullptr;
+ MonoException *exc = nullptr;
+ valid = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_AddScriptBridge
+ .invoke(this, &script_path, &exc);
+ UNHANDLED_EXCEPTION(exc);
- if (script_class) {
+ if (valid) {
#ifdef DEBUG_ENABLED
- print_verbose("Found class " + script_class->get_full_name() + " for script " + get_path());
+ print_verbose("Found class for script " + get_path());
#endif
- native = GDMonoUtils::get_class_native_base(script_class);
-
- CRASH_COND(native == nullptr);
-
update_script_class_info(this);
_update_exports();
@@ -3509,43 +3226,59 @@ void CSharpScript::update_exports() {
}
bool CSharpScript::has_script_signal(const StringName &p_signal) const {
- return event_signals.has(p_signal) || _signals.has(p_signal);
+ if (!valid) {
+ return false;
+ }
+
+ if (!GDMonoCache::cached_data.godot_api_cache_updated) {
+ return false;
+ }
+
+ String signal = p_signal;
+
+ MonoException *exc = nullptr;
+ bool res = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_HasScriptSignal
+ .invoke(this, &signal, &exc);
+ UNHANDLED_EXCEPTION(exc);
+
+ return res;
}
void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
- for (const KeyValue<StringName, Vector<SignalParameter>> &E : _signals) {
- MethodInfo mi;
- mi.name = E.key;
+ if (!valid) {
+ return;
+ }
- const Vector<SignalParameter> &params = E.value;
- for (int i = 0; i < params.size(); i++) {
- const SignalParameter &param = params[i];
+ // Performance is not critical here as this will be replaced with source generators.
- PropertyInfo arg_info = PropertyInfo(param.type, param.name);
- if (param.type == Variant::NIL && param.nil_is_variant) {
- arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- }
+ if (!GDMonoCache::cached_data.godot_api_cache_updated) {
+ return;
+ }
- mi.arguments.push_back(arg_info);
- }
+ Dictionary signals_dict;
+ // Destructor won't be called from C#, and I don't want to include the GDNative header
+ // only for this, so need to call the destructor manually before passing this to C#.
+ signals_dict.~Dictionary();
- r_signals->push_back(mi);
- }
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_GetScriptSignalList
+ .invoke(this, &signals_dict, &exc);
+ UNHANDLED_EXCEPTION(exc);
- for (const KeyValue<StringName, EventSignal> &E : event_signals) {
+ for (const Variant *s = signals_dict.next(nullptr); s != nullptr; s = signals_dict.next(s)) {
MethodInfo mi;
- mi.name = E.key;
+ mi.name = *s;
+
+ Array params = signals_dict[*s];
- const EventSignal &event_signal = E.value;
- const Vector<SignalParameter> &params = event_signal.parameters;
for (int i = 0; i < params.size(); i++) {
- const SignalParameter &param = params[i];
+ Dictionary param = params[i];
- PropertyInfo arg_info = PropertyInfo(param.type, param.name);
- if (param.type == Variant::NIL && param.nil_is_variant) {
+ Variant::Type param_type = (Variant::Type)(int)param["type"];
+ PropertyInfo arg_info = PropertyInfo(param_type, (String)param["name"]);
+ if (param_type == Variant::NIL && (bool)param["nil_is_variant"]) {
arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
}
-
mi.arguments.push_back(arg_info);
}
@@ -3559,15 +3292,20 @@ bool CSharpScript::inherits_script(const Ref<Script> &p_script) const {
return false;
}
- if (script_class == nullptr || cs->script_class == nullptr) {
+ if (!valid || !cs->valid) {
return false;
}
- if (script_class == cs->script_class) {
- return true;
+ if (!GDMonoCache::cached_data.godot_api_cache_updated) {
+ return false;
}
- return cs->script_class->is_assignable_from(script_class);
+ MonoException *exc = nullptr;
+ bool res = GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_ScriptIsOrInherits
+ .invoke(this, cs.ptr(), &exc);
+ UNHANDLED_EXCEPTION(exc);
+
+ return res;
}
Ref<Script> CSharpScript::get_base_script() const {
@@ -3598,22 +3336,6 @@ int CSharpScript::get_member_line(const StringName &p_member) const {
return -1;
}
-Variant CSharpScript::_member_get_rpc_config(IMonoClassMember *p_member) const {
- Variant out;
-
- MonoObject *rpc_attribute = p_member->get_attribute(CACHED_CLASS(RPCAttribute));
- if (rpc_attribute != nullptr) {
- Dictionary rpc_config;
- rpc_config["rpc_mode"] = CACHED_PROPERTY(RPCAttribute, Mode)->get_int_value(rpc_attribute);
- rpc_config["call_local"] = CACHED_PROPERTY(RPCAttribute, CallLocal)->get_bool_value(rpc_attribute);
- rpc_config["transfer_mode"] = CACHED_PROPERTY(RPCAttribute, TransferMode)->get_int_value(rpc_attribute);
- rpc_config["channel"] = CACHED_PROPERTY(RPCAttribute, TransferChannel)->get_int_value(rpc_attribute);
- out = rpc_config;
- }
-
- return out;
-}
-
const Variant CSharpScript::get_rpc_config() const {
return rpc_config;
}
@@ -3634,29 +3356,15 @@ Error CSharpScript::load_source_code(const String &p_path) {
return OK;
}
-void CSharpScript::_update_name() {
- String path = get_path();
-
- if (!path.is_empty()) {
- name = get_path().get_file().get_basename();
- }
-}
-
void CSharpScript::_clear() {
tool = false;
valid = false;
reload_invalidated = true;
-
- base = nullptr;
- native = nullptr;
- script_class = nullptr;
}
CSharpScript::CSharpScript() {
_clear();
- _update_name();
-
#ifdef DEBUG_ENABLED
{
MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
@@ -3670,6 +3378,12 @@ CSharpScript::~CSharpScript() {
MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
CSharpLanguage::get_singleton()->script_list.remove(&this->script_list);
#endif
+
+ if (GDMonoCache::cached_data.godot_api_cache_updated) {
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_RemoveScriptBridge.invoke(this, &exc);
+ UNHANDLED_EXCEPTION(exc);
+ }
}
void CSharpScript::get_members(HashSet<StringName> *p_members) {
@@ -3771,16 +3485,9 @@ bool ResourceFormatSaverCSharpScript::recognize(const Ref<Resource> &p_resource)
}
CSharpLanguage::StringNameCache::StringNameCache() {
- _signal_callback = StaticCString::create("_signal_callback");
- _set = StaticCString::create("_set");
- _get = StaticCString::create("_get");
- _get_property_list = StaticCString::create("_get_property_list");
_property_can_revert = StaticCString::create("_property_can_revert");
_property_get_revert = StaticCString::create("_property_get_revert");
- _notification = StaticCString::create("_notification");
_script_source = StaticCString::create("script/source");
on_before_serialize = StaticCString::create("OnBeforeSerialize");
on_after_deserialize = StaticCString::create("OnAfterDeserialize");
- dotctor = StaticCString::create(".ctor");
- delegate_invoke_method_name = StaticCString::create("Invoke");
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index cf4f971b88..34b2e7f735 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -39,7 +39,6 @@
#include "mono_gc_handle.h"
#include "mono_gd/gd_mono.h"
-#include "mono_gd/gd_mono_header.h"
#include "mono_gd/gd_mono_internals.h"
#ifdef TOOLS_ENABLED
@@ -67,18 +66,6 @@ TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
#define CAST_CSHARP_INSTANCE(m_inst) (cast_script_instance<CSharpInstance, CSharpLanguage>(m_inst))
-struct DotNetScriptLookupInfo {
- String class_namespace;
- String class_name;
- GDMonoClass *script_class = nullptr;
-
- DotNetScriptLookupInfo() {} // Required by HashMap...
-
- DotNetScriptLookupInfo(const String &p_class_namespace, const String &p_class_name, GDMonoClass *p_script_class) :
- class_namespace(p_class_namespace), class_name(p_class_name), script_class(p_script_class) {
- }
-};
-
class CSharpScript : public Script {
GDCLASS(CSharpScript, Script);
@@ -89,25 +76,14 @@ public:
bool nil_is_variant = false;
};
- struct EventSignal {
- GDMonoField *field = nullptr;
- GDMonoMethod *invoke_method = nullptr;
- Vector<SignalParameter> parameters;
- };
-
private:
friend class CSharpInstance;
friend class CSharpLanguage;
- friend struct CSharpScriptDepSort;
bool tool = false;
bool valid = false;
bool reload_invalidated = false;
- GDMonoClass *base = nullptr;
- GDMonoClass *native = nullptr;
- GDMonoClass *script_class = nullptr;
-
Ref<CSharpScript> base_cache; // TODO what's this for?
HashSet<Object *> instances;
@@ -128,14 +104,9 @@ private:
#endif
String source;
- StringName name;
SelfList<CSharpScript> script_list = this;
- HashMap<StringName, Vector<SignalParameter>> _signals;
- HashMap<StringName, EventSignal> event_signals;
- bool signals_invalidated = true;
-
Dictionary rpc_config;
#ifdef TOOLS_ENABLED
@@ -158,34 +129,26 @@ private:
void _clear();
- void _update_name();
-
- void load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class);
- bool _get_signal(GDMonoClass *p_class, GDMonoMethod *p_delegate_invoke, Vector<SignalParameter> &params);
-
bool _update_exports(PlaceHolderScriptInstance *p_instance_to_update = nullptr);
+#warning TODO
+#if 0
bool _get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported);
#ifdef TOOLS_ENABLED
static int _try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string);
#endif
+#endif
CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error);
Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
// Do not use unless you know what you are doing
- friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
- static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native);
static void update_script_class_info(Ref<CSharpScript> p_script);
- static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native);
-
- Variant _member_get_rpc_config(IMonoClassMember *p_member) const;
+ static void initialize_for_managed_type(Ref<CSharpScript> p_script);
protected:
static void _bind_methods();
- Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
- void _resource_path_changed() override;
bool _get(const StringName &p_name, Variant &r_ret) const;
bool _set(const StringName &p_name, const Variant &p_value);
void _get_property_list(List<PropertyInfo> *p_properties) const;
@@ -270,22 +233,21 @@ class CSharpInstance : public ScriptInstance {
bool _unreference_owner_unsafe();
/*
- * If nullptr is returned, the caller must destroy the script instance by removing it from its owner.
+ * If false is returned, the caller must destroy the script instance by removing it from its owner.
*/
- MonoObject *_internal_new_managed();
+ bool _internal_new_managed();
// Do not use unless you know what you are doing
- friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
static CSharpInstance *create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle);
void get_properties_state_for_reloading(List<Pair<StringName, Variant>> &r_state);
void get_event_signals_state_for_reloading(List<Pair<StringName, Array>> &r_state);
public:
- MonoObject *get_mono_object() const;
-
_FORCE_INLINE_ bool is_destructing_script_instance() { return destructing_script_instance; }
+ _FORCE_INLINE_ GCHandleIntPtr get_gchandle_intptr() { return gchandle.get_intptr(); }
+
Object *get_owner() override;
bool set(const StringName &p_name, const Variant &p_value) override;
@@ -300,15 +262,15 @@ public:
bool has_method(const StringName &p_method) const override;
Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
- void mono_object_disposed(MonoObject *p_obj);
+ void mono_object_disposed();
/*
* If 'r_delete_owner' is set to true, the caller must memdelete the script instance's owner. Otherwise, if
* 'r_remove_script_instance' is set to true, the caller must destroy the script instance by removing it from its owner.
*/
- void mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance);
+ void mono_object_disposed_baseref(bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance);
- void connect_event_signals();
+ void connect_event_signal(const StringName &p_event_signal);
void disconnect_event_signals();
void refcount_incremented() override;
@@ -332,7 +294,6 @@ public:
struct CSharpScriptBinding {
bool inited = false;
StringName type_name;
- GDMonoClass *wrapper_class = nullptr;
MonoGCHandleData gchandle;
Object *owner = nullptr;
@@ -370,28 +331,17 @@ class CSharpLanguage : public ScriptLanguage {
ManagedCallableMiddleman *managed_callable_middleman = memnew(ManagedCallableMiddleman);
struct StringNameCache {
- StringName _signal_callback;
- StringName _set;
- StringName _get;
- StringName _get_property_list;
StringName _property_can_revert;
StringName _property_get_revert;
- StringName _notification;
StringName _script_source;
- StringName dotctor; // .ctor
StringName on_before_serialize; // OnBeforeSerialize
StringName on_after_deserialize; // OnAfterDeserialize
- StringName delegate_invoke_method_name;
StringNameCache();
};
int lang_idx = -1;
- HashMap<String, DotNetScriptLookupInfo> dotnet_script_lookup_map;
-
- void lookup_script_for_class(GDMonoClass *p_class);
-
// For debug_break and debug_break_parse
int _debug_parse_err_line = -1;
String _debug_parse_err_file;
@@ -421,6 +371,7 @@ public:
StringNameCache string_names;
const Mutex &get_language_bind_mutex() { return language_bind_mutex; }
+ const Mutex &get_script_instances_mutex() { return script_instances_mutex; }
_FORCE_INLINE_ int get_language_index() { return lang_idx; }
void set_language_index(int p_idx);
@@ -434,7 +385,7 @@ public:
#endif
static void release_script_gchandle(MonoGCHandleData &p_gchandle);
- static void release_script_gchandle(MonoObject *p_expected_obj, MonoGCHandleData &p_gchandle);
+ static void release_script_gchandle(void *p_expected_mono_obj_unused, MonoGCHandleData &p_gchandle);
bool debug_break(const String &p_error, bool p_allow_continue = true);
bool debug_break_parse(const String &p_file, int p_line, const String &p_error);
@@ -446,12 +397,6 @@ public:
_FORCE_INLINE_ ManagedCallableMiddleman *get_managed_callable_middleman() const { return managed_callable_middleman; }
- void lookup_scripts_in_assembly(GDMonoAssembly *p_assembly);
-
- const DotNetScriptLookupInfo *lookup_dotnet_script(const String &p_script_path) const {
- return dotnet_script_lookup_map.getptr(p_script_path);
- }
-
String get_name() const override;
/* LANGUAGE FUNCTIONS */
@@ -527,6 +472,10 @@ public:
RBMap<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding);
bool setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object);
+ static void tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, const StringName *p_native_name, bool p_ref_counted);
+ static void tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, CSharpScript *p_script, bool p_ref_counted);
+ static void tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged);
+
#ifdef DEBUG_ENABLED
Vector<StackInfo> stack_trace_get_info(MonoObject *p_stack_trace);
#endif
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
index 21bff70b15..33967ffa71 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
@@ -178,17 +178,6 @@ namespace GodotTools.Build
if (!File.Exists(buildInfo.Solution))
return true; // No solution to build
- // Make sure the API assemblies are up to date before building the project.
- // We may not have had the chance to update the release API assemblies, and the debug ones
- // may have been deleted by the user at some point after they were loaded by the Godot editor.
- string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(buildInfo.Configuration == "ExportRelease" ? "Release" : "Debug");
-
- if (!string.IsNullOrEmpty(apiAssembliesUpdateError))
- {
- ShowBuildErrorDialog("Failed to update the Godot API assemblies");
- return false;
- }
-
using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1))
{
pr.Step("Building project solution", 0);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index cca18a2a1f..ee3f5999cd 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -1,4 +1,5 @@
using Godot;
+using Godot.NativeInterop;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -100,7 +101,9 @@ namespace GodotTools.Export
return;
if (Path.GetExtension(path) != Internal.CSharpLanguageExtension)
- throw new ArgumentException($"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}", nameof(path));
+ throw new ArgumentException(
+ $"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}",
+ nameof(path));
// TODO What if the source file is not part of the game's C# project
@@ -194,7 +197,8 @@ namespace GodotTools.Export
{
string thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName + ".dll");
if (!File.Exists(thisWasmFrameworkAssemblyPath))
- throw new FileNotFoundException($"Assembly not found: '{thisWasmFrameworkAssemblyName}'", thisWasmFrameworkAssemblyPath);
+ throw new FileNotFoundException($"Assembly not found: '{thisWasmFrameworkAssemblyName}'",
+ thisWasmFrameworkAssemblyPath);
assemblies[thisWasmFrameworkAssemblyName] = thisWasmFrameworkAssemblyPath;
}
@@ -206,18 +210,21 @@ namespace GodotTools.Export
foreach (var thisWasmFrameworkAssemblyName in wasmFrameworkAssembliesOneOf)
{
- string thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName.newName + ".dll");
+ string thisWasmFrameworkAssemblyPath =
+ Path.Combine(bclDir, thisWasmFrameworkAssemblyName.newName + ".dll");
if (File.Exists(thisWasmFrameworkAssemblyPath))
{
assemblies[thisWasmFrameworkAssemblyName.newName] = thisWasmFrameworkAssemblyPath;
}
else
{
- thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName.oldName + ".dll");
+ thisWasmFrameworkAssemblyPath =
+ Path.Combine(bclDir, thisWasmFrameworkAssemblyName.oldName + ".dll");
if (!File.Exists(thisWasmFrameworkAssemblyPath))
{
- throw new FileNotFoundException("Expected one of the following assemblies but none were found: " +
- $"'{thisWasmFrameworkAssemblyName.newName}' / '{thisWasmFrameworkAssemblyName.oldName}'",
+ throw new FileNotFoundException(
+ "Expected one of the following assemblies but none were found: " +
+ $"'{thisWasmFrameworkAssemblyName.newName}' / '{thisWasmFrameworkAssemblyName.oldName}'",
thisWasmFrameworkAssemblyPath);
}
@@ -227,7 +234,12 @@ namespace GodotTools.Export
}
var initialAssemblies = assemblies.Duplicate();
- internal_GetExportedAssemblyDependencies(initialAssemblies, buildConfig, bclDir, assemblies);
+ godot_dictionary initialAssembliesAux = ((Godot.Collections.Dictionary)initialAssemblies).NativeValue;
+ using godot_string buildConfigAux = Marshaling.mono_string_to_godot(buildConfig);
+ using godot_string bclDirAux = Marshaling.mono_string_to_godot(bclDir);
+ godot_dictionary assembliesAux = ((Godot.Collections.Dictionary)assemblies).NativeValue;
+ internal_GetExportedAssemblyDependencies(initialAssembliesAux, buildConfigAux, bclDirAux,
+ ref assembliesAux);
AddI18NAssemblies(assemblies, bclDir);
@@ -237,9 +249,12 @@ namespace GodotTools.Export
outputDataDir = ExportDataDirectory(features, platform, isDebug, outputDir);
string apiConfig = isDebug ? "Debug" : "Release";
- string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, apiConfig);
+ // TODO
+ throw new NotImplementedException();
+ string resAssembliesDir = null; // Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, apiConfig);
- bool assembliesInsidePck = (bool)ProjectSettings.GetSetting("mono/export/export_assemblies_inside_pck") || outputDataDir == null;
+ bool assembliesInsidePck = (bool)ProjectSettings.GetSetting("mono/export/export_assemblies_inside_pck") ||
+ outputDataDir == null;
if (!assembliesInsidePck)
{
@@ -277,7 +292,8 @@ namespace GodotTools.Export
}
// AOT compilation
- bool aotEnabled = platform == OS.Platforms.iOS || (bool)ProjectSettings.GetSetting("mono/export/aot/enabled");
+ bool aotEnabled = platform == OS.Platforms.iOS ||
+ (bool)ProjectSettings.GetSetting("mono/export/aot/enabled");
if (aotEnabled)
{
@@ -296,14 +312,19 @@ namespace GodotTools.Export
LLVMOnly = false,
LLVMPath = "",
LLVMOutputPath = "",
- FullAot = platform == OS.Platforms.iOS || (bool)(ProjectSettings.GetSetting("mono/export/aot/full_aot") ?? false),
+ FullAot = platform == OS.Platforms.iOS ||
+ (bool)(ProjectSettings.GetSetting("mono/export/aot/full_aot") ?? false),
UseInterpreter = (bool)ProjectSettings.GetSetting("mono/export/aot/use_interpreter"),
- ExtraAotOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_aot_options") ?? Array.Empty<string>(),
- ExtraOptimizerOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_optimizer_options") ?? Array.Empty<string>(),
+ ExtraAotOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_aot_options") ??
+ Array.Empty<string>(),
+ ExtraOptimizerOptions =
+ (string[])ProjectSettings.GetSetting("mono/export/aot/extra_optimizer_options") ??
+ Array.Empty<string>(),
ToolchainPath = aotToolchainPath
};
- AotBuilder.CompileAssemblies(this, aotOpts, features, platform, isDebug, bclDir, outputDir, outputDataDir, assemblies);
+ AotBuilder.CompileAssemblies(this, aotOpts, features, platform, isDebug, bclDir, outputDir,
+ outputDataDir, assemblies);
}
}
@@ -316,8 +337,10 @@ namespace GodotTools.Export
if (Directory.Exists(aotTempDir))
Directory.Delete(aotTempDir, recursive: true);
- // TODO: Just a workaround until the export plugins can be made to abort with errors
- if (!string.IsNullOrEmpty(_maybeLastExportError)) // Check empty as well, because it's set to empty after hot-reloading
+ // TODO: The following is just a workaround until the export plugins can be made to abort with errors
+
+ // We check for empty as well, because it's set to empty after hot-reloading
+ if (!string.IsNullOrEmpty(_maybeLastExportError))
{
string lastExportError = _maybeLastExportError;
_maybeLastExportError = null;
@@ -381,7 +404,8 @@ namespace GodotTools.Export
private static bool PlatformHasTemplateDir(string platform)
{
// macOS export templates are contained in a zip, so we place our custom template inside it and let Godot do the rest.
- return !new[] { OS.Platforms.MacOS, OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }.Contains(platform);
+ return !new[] { OS.Platforms.MacOS, OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }
+ .Contains(platform);
}
private static bool DeterminePlatformFromFeatures(IEnumerable<string> features, out string platform)
@@ -476,7 +500,8 @@ namespace GodotTools.Export
}
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_GetExportedAssemblyDependencies(Godot.Collections.Dictionary<string, string> initialAssemblies,
- string buildConfig, string customBclDir, Godot.Collections.Dictionary<string, string> dependencyAssemblies);
+ private static extern void internal_GetExportedAssemblyDependencies(
+ in godot_dictionary initialAssemblies, in godot_string buildConfig,
+ in godot_string customBclDir, ref godot_dictionary dependencyAssemblies);
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index b39c3d1c0d..5167333716 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -53,7 +53,7 @@ namespace GodotTools
private bool CreateProjectSolution()
{
- using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 3))
+ using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 2))
{
pr.Step("Generating C# project...".TTR());
@@ -90,24 +90,6 @@ namespace GodotTools
return false;
}
- pr.Step("Updating Godot API assemblies...".TTR());
-
- string debugApiAssembliesError = Internal.UpdateApiAssembliesFromPrebuilt("Debug");
-
- if (!string.IsNullOrEmpty(debugApiAssembliesError))
- {
- ShowErrorDialog("Failed to update the Godot API assemblies: " + debugApiAssembliesError);
- return false;
- }
-
- string releaseApiAssembliesError = Internal.UpdateApiAssembliesFromPrebuilt("Release");
-
- if (!string.IsNullOrEmpty(releaseApiAssembliesError))
- {
- ShowErrorDialog("Failed to update the Godot API assemblies: " + releaseApiAssembliesError);
- return false;
- }
-
pr.Step("Done".TTR());
// Here, after all calls to progress_task_step
@@ -533,8 +515,9 @@ namespace GodotTools
public static GodotSharpEditor Instance { get; private set; }
[UsedImplicitly]
- private GodotSharpEditor()
+ private static IntPtr InternalCreateInstance()
{
+ return new GodotSharpEditor().NativeInstance;
}
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
index f1d45463c5..d44cd75155 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
@@ -2,12 +2,13 @@
<PropertyGroup>
<ProjectGuid>{27B00618-A6F2-4828-B922-05CAEB08C286}</ProjectGuid>
<TargetFramework>net472</TargetFramework>
- <LangVersion>7.2</LangVersion>
+ <LangVersion>8</LangVersion>
<!-- The Godot editor uses the Debug Godot API assemblies -->
<GodotApiConfiguration>Debug</GodotApiConfiguration>
<GodotSourceRootPath>$(SolutionDir)/../../../../</GodotSourceRootPath>
<GodotOutputDataDir>$(GodotSourceRootPath)/bin/GodotSharp</GodotOutputDataDir>
<GodotApiAssembliesDir>$(GodotOutputDataDir)/Api/$(GodotApiConfiguration)</GodotApiAssembliesDir>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" Exists('$(GodotApiAssembliesDir)/GodotSharp.dll') ">
<!-- The project is part of the Godot source tree -->
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs
index 70ba7c733a..b221ae7c5c 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs
@@ -1,6 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using Godot;
+using Godot.NativeInterop;
namespace GodotTools.Internals
{
@@ -9,18 +10,22 @@ namespace GodotTools.Internals
public string Task { get; }
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_Create(string task, string label, int amount, bool canCancel);
+ private static extern void internal_Create(in godot_string task, in godot_string label, int amount,
+ bool canCancel);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_Dispose(string task);
+ private static extern void internal_Dispose(in godot_string task);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_Step(string task, string state, int step, bool forceRefresh);
+ private static extern bool internal_Step(in godot_string task, in godot_string state, int step,
+ bool forceRefresh);
public EditorProgress(string task, string label, int amount, bool canCancel = false)
{
Task = task;
- internal_Create(task, label, amount, canCancel);
+ using godot_string taskIn = Marshaling.mono_string_to_godot(task);
+ using godot_string labelIn = Marshaling.mono_string_to_godot(label);
+ internal_Create(taskIn, labelIn, amount, canCancel);
}
~EditorProgress()
@@ -33,18 +38,23 @@ namespace GodotTools.Internals
public void Dispose()
{
- internal_Dispose(Task);
+ using godot_string taskIn = Marshaling.mono_string_to_godot(Task);
+ internal_Dispose(taskIn);
GC.SuppressFinalize(this);
}
public void Step(string state, int step = -1, bool forceRefresh = true)
{
- internal_Step(Task, state, step, forceRefresh);
+ using godot_string taskIn = Marshaling.mono_string_to_godot(Task);
+ using godot_string stateIn = Marshaling.mono_string_to_godot(state);
+ internal_Step(taskIn, stateIn, step, forceRefresh);
}
public bool TryStep(string state, int step = -1, bool forceRefresh = true)
{
- return internal_Step(Task, state, step, forceRefresh);
+ using godot_string taskIn = Marshaling.mono_string_to_godot(Task);
+ using godot_string stateIn = Marshaling.mono_string_to_godot(state);
+ return internal_Step(taskIn, stateIn, step, forceRefresh);
}
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
index 5c5ced8c29..d79821de3c 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
@@ -1,3 +1,4 @@
+using Godot.NativeInterop;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
@@ -7,17 +8,40 @@ namespace GodotTools.Internals
{
public static float EditorScale => internal_EditorScale();
- public static object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false) =>
- internal_GlobalDef(setting, defaultValue, restartIfChanged);
+ public static unsafe object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false)
+ {
+ using godot_string settingIn = Marshaling.mono_string_to_godot(setting);
+ using godot_variant defaultValueIn = Marshaling.mono_object_to_variant(defaultValue);
+ internal_GlobalDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
+ using (result)
+ return Marshaling.variant_to_mono_object(&result);
+ }
- public static object EditorDef(string setting, object defaultValue, bool restartIfChanged = false) =>
- internal_EditorDef(setting, defaultValue, restartIfChanged);
+ public static unsafe object EditorDef(string setting, object defaultValue, bool restartIfChanged = false)
+ {
+ using godot_string settingIn = Marshaling.mono_string_to_godot(setting);
+ using godot_variant defaultValueIn = Marshaling.mono_object_to_variant(defaultValue);
+ internal_EditorDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
+ using (result)
+ return Marshaling.variant_to_mono_object(&result);
+ }
- public static object EditorShortcut(string setting) =>
- internal_EditorShortcut(setting);
+ public static unsafe object EditorShortcut(string setting)
+ {
+ using godot_string settingIn = Marshaling.mono_string_to_godot(setting);
+ internal_EditorShortcut(settingIn, out godot_variant result);
+ using (result)
+ return Marshaling.variant_to_mono_object(&result);
+ }
[SuppressMessage("ReSharper", "InconsistentNaming")]
- public static string TTR(this string text) => internal_TTR(text);
+ public static string TTR(this string text)
+ {
+ using godot_string textIn = Marshaling.mono_string_to_godot(text);
+ internal_TTR(textIn, out godot_string dest);
+ using (dest)
+ return Marshaling.mono_string_from_godot(dest);
+ }
// Internal Calls
@@ -25,15 +49,17 @@ namespace GodotTools.Internals
private static extern float internal_EditorScale();
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern object internal_GlobalDef(string setting, object defaultValue, bool restartIfChanged);
+ private static extern void internal_GlobalDef(in godot_string setting, in godot_variant defaultValue,
+ bool restartIfChanged, out godot_variant result);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern object internal_EditorDef(string setting, object defaultValue, bool restartIfChanged);
+ private static extern void internal_EditorDef(in godot_string setting, in godot_variant defaultValue,
+ bool restartIfChanged, out godot_variant result);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern object internal_EditorShortcut(string setting);
+ private static extern void internal_EditorShortcut(in godot_string setting, out godot_variant result);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_TTR(string text);
+ private static extern void internal_TTR(in godot_string text, out godot_string dest);
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
index 5e70c399b2..b15ebc1ae2 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
@@ -1,102 +1,102 @@
using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
namespace GodotTools.Internals
{
public static class GodotSharpDirs
{
- public static string ResDataDir => internal_ResDataDir();
- public static string ResMetadataDir => internal_ResMetadataDir();
- public static string ResAssembliesBaseDir => internal_ResAssembliesBaseDir();
- public static string ResAssembliesDir => internal_ResAssembliesDir();
- public static string ResConfigDir => internal_ResConfigDir();
- public static string ResTempDir => internal_ResTempDir();
- public static string ResTempAssembliesBaseDir => internal_ResTempAssembliesBaseDir();
- public static string ResTempAssembliesDir => internal_ResTempAssembliesDir();
-
- public static string MonoUserDir => internal_MonoUserDir();
- public static string MonoLogsDir => internal_MonoLogsDir();
-
- #region Tools-only
- public static string MonoSolutionsDir => internal_MonoSolutionsDir();
- public static string BuildLogsDirs => internal_BuildLogsDirs();
-
- public static string ProjectSlnPath => internal_ProjectSlnPath();
- public static string ProjectCsProjPath => internal_ProjectCsProjPath();
-
- public static string DataEditorToolsDir => internal_DataEditorToolsDir();
- public static string DataEditorPrebuiltApiDir => internal_DataEditorPrebuiltApiDir();
- #endregion
-
- public static string DataMonoEtcDir => internal_DataMonoEtcDir();
- public static string DataMonoLibDir => internal_DataMonoLibDir();
-
- #region Windows-only
- public static string DataMonoBinDir => internal_DataMonoBinDir();
- #endregion
-
+ public static string ResMetadataDir
+ {
+ get
+ {
+ internal_ResMetadataDir(out godot_string dest);
+ using (dest)
+ return Marshaling.mono_string_from_godot(dest);
+ }
+ }
+
+ public static string ResTempAssembliesBaseDir
+ {
+ get
+ {
+ internal_ResTempAssembliesBaseDir(out godot_string dest);
+ using (dest)
+ return Marshaling.mono_string_from_godot(dest);
+ }
+ }
+
+ public static string MonoUserDir
+ {
+ get
+ {
+ internal_MonoUserDir(out godot_string dest);
+ using (dest)
+ return Marshaling.mono_string_from_godot(dest);
+ }
+ }
+
+ public static string BuildLogsDirs
+ {
+ get
+ {
+ internal_BuildLogsDirs(out godot_string dest);
+ using (dest)
+ return Marshaling.mono_string_from_godot(dest);
+ }
+ }
+
+ public static string ProjectSlnPath
+ {
+ get
+ {
+ internal_ProjectSlnPath(out godot_string dest);
+ using (dest)
+ return Marshaling.mono_string_from_godot(dest);
+ }
+ }
+
+ public static string ProjectCsProjPath
+ {
+ get
+ {
+ internal_ProjectCsProjPath(out godot_string dest);
+ using (dest)
+ return Marshaling.mono_string_from_godot(dest);
+ }
+ }
+
+ public static string DataEditorToolsDir
+ {
+ get
+ {
+ internal_DataEditorToolsDir(out godot_string dest);
+ using (dest)
+ return Marshaling.mono_string_from_godot(dest);
+ }
+ }
#region Internal
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResDataDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResMetadataDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResAssembliesBaseDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResAssembliesDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResConfigDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResTempDir();
+ private static extern void internal_ResMetadataDir(out godot_string r_dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResTempAssembliesBaseDir();
+ private static extern void internal_ResTempAssembliesBaseDir(out godot_string r_dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResTempAssembliesDir();
+ private static extern void internal_MonoUserDir(out godot_string r_dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_MonoUserDir();
+ private static extern void internal_BuildLogsDirs(out godot_string r_dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_MonoLogsDir();
+ private static extern void internal_ProjectSlnPath(out godot_string r_dest);
- #region Tools-only
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_MonoSolutionsDir();
+ private static extern void internal_ProjectCsProjPath(out godot_string r_dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_BuildLogsDirs();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ProjectSlnPath();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ProjectCsProjPath();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_DataEditorToolsDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_DataEditorPrebuiltApiDir();
- #endregion
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_DataMonoEtcDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_DataMonoLibDir();
-
- #region Windows-only
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_DataMonoBinDir();
- #endregion
+ private static extern void internal_DataEditorToolsDir(out godot_string r_dest);
#endregion
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
index 12c90178c9..7ba26939fa 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
@@ -1,5 +1,7 @@
+using System;
using System.Runtime.CompilerServices;
using Godot;
+using Godot.NativeInterop;
using GodotTools.IdeMessaging.Requests;
namespace GodotTools.Internals
@@ -9,15 +11,23 @@ namespace GodotTools.Internals
public const string CSharpLanguageType = "CSharpScript";
public const string CSharpLanguageExtension = ".cs";
- public static string UpdateApiAssembliesFromPrebuilt(string config) =>
- internal_UpdateApiAssembliesFromPrebuilt(config);
+ public static string FullExportTemplatesDir
+ {
+ get
+ {
+ internal_FullExportTemplatesDir(out godot_string dest);
+ using (dest)
+ return Marshaling.mono_string_from_godot(dest);
+ }
+ }
- public static string FullExportTemplatesDir =>
- internal_FullExportTemplatesDir();
+ public static string SimplifyGodotPath(this string path) => Godot.StringExtensions.SimplifyPath(path);
- public static string SimplifyGodotPath(this string path) => internal_SimplifyGodotPath(path);
-
- public static bool IsMacOSAppBundleInstalled(string bundleId) => internal_IsMacOSAppBundleInstalled(bundleId);
+ public static bool IsMacOSAppBundleInstalled(string bundleId)
+ {
+ using godot_string bundleIdIn = Marshaling.mono_string_to_godot(bundleId);
+ return internal_IsMacOSAppBundleInstalled(bundleIdIn);
+ }
public static bool GodotIs32Bits() => internal_GodotIs32Bits();
@@ -25,10 +35,6 @@ namespace GodotTools.Internals
public static void GodotMainIteration() => internal_GodotMainIteration();
- public static ulong GetCoreApiHash() => internal_GetCoreApiHash();
-
- public static ulong GetEditorApiHash() => internal_GetEditorApiHash();
-
public static bool IsAssembliesReloadingNeeded() => internal_IsAssembliesReloadingNeeded();
public static void ReloadAssemblies(bool softReload) => internal_ReloadAssemblies(softReload);
@@ -36,11 +42,19 @@ namespace GodotTools.Internals
public static void EditorDebuggerNodeReloadScripts() => internal_EditorDebuggerNodeReloadScripts();
public static bool ScriptEditorEdit(Resource resource, int line, int col, bool grabFocus = true) =>
- internal_ScriptEditorEdit(resource, line, col, grabFocus);
+ internal_ScriptEditorEdit(resource.NativeInstance, line, col, grabFocus);
public static void EditorNodeShowScriptScreen() => internal_EditorNodeShowScriptScreen();
- public static string MonoWindowsInstallRoot => internal_MonoWindowsInstallRoot();
+ public static string MonoWindowsInstallRoot
+ {
+ get
+ {
+ internal_MonoWindowsInstallRoot(out godot_string dest);
+ using (dest)
+ return Marshaling.mono_string_from_godot(dest);
+ }
+ }
public static void EditorRunPlay() => internal_EditorRunPlay();
@@ -48,22 +62,22 @@ namespace GodotTools.Internals
public static void ScriptEditorDebugger_ReloadScripts() => internal_ScriptEditorDebugger_ReloadScripts();
- public static string[] CodeCompletionRequest(CodeCompletionRequest.CompletionKind kind, string scriptFile) =>
- internal_CodeCompletionRequest((int)kind, scriptFile);
+ public static unsafe string[] CodeCompletionRequest(CodeCompletionRequest.CompletionKind kind,
+ string scriptFile)
+ {
+ using godot_string scriptFileIn = Marshaling.mono_string_to_godot(scriptFile);
+ internal_CodeCompletionRequest((int)kind, scriptFileIn, out godot_packed_string_array res);
+ using (res)
+ return Marshaling.PackedStringArray_to_mono_array(&res);
+ }
#region Internal
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_UpdateApiAssembliesFromPrebuilt(string config);
+ private static extern void internal_FullExportTemplatesDir(out godot_string dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_FullExportTemplatesDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_SimplifyGodotPath(this string path);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_IsMacOSAppBundleInstalled(string bundleId);
+ private static extern bool internal_IsMacOSAppBundleInstalled(in godot_string bundleId);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern bool internal_GodotIs32Bits();
@@ -75,12 +89,6 @@ namespace GodotTools.Internals
private static extern void internal_GodotMainIteration();
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern ulong internal_GetCoreApiHash();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern ulong internal_GetEditorApiHash();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
private static extern bool internal_IsAssembliesReloadingNeeded();
[MethodImpl(MethodImplOptions.InternalCall)]
@@ -90,13 +98,13 @@ namespace GodotTools.Internals
private static extern void internal_EditorDebuggerNodeReloadScripts();
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_ScriptEditorEdit(Resource resource, int line, int col, bool grabFocus);
+ private static extern bool internal_ScriptEditorEdit(IntPtr resource, int line, int col, bool grabFocus);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void internal_EditorNodeShowScriptScreen();
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_MonoWindowsInstallRoot();
+ private static extern void internal_MonoWindowsInstallRoot(out godot_string dest);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void internal_EditorRunPlay();
@@ -108,7 +116,8 @@ namespace GodotTools.Internals
private static extern void internal_ScriptEditorDebugger_ReloadScripts();
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string[] internal_CodeCompletionRequest(int kind, string scriptFile);
+ private static extern void internal_CodeCompletionRequest(int kind, in godot_string scriptFile,
+ out godot_packed_string_array res);
#endregion
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
index 5cef6e5c3c..aa100433c9 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -1,3 +1,4 @@
+using Godot.NativeInterop;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -13,10 +14,10 @@ namespace GodotTools.Utils
public static class OS
{
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string GetPlatformName();
+ private static extern void GetPlatformName(out godot_string dest);
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool UnixFileHasExecutableAccess(string filePath);
+ private static extern bool UnixFileHasExecutableAccess(in godot_string filePath);
public static class Names
{
@@ -63,14 +64,24 @@ namespace GodotTools.Utils
[Names.HTML5] = Platforms.HTML5
};
- private static bool IsOS(string name)
+ private static unsafe bool IsOS(string name)
{
- return name.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
+ GetPlatformName(out godot_string dest);
+ using (dest)
+ {
+ string platformName = Marshaling.mono_string_from_godot(dest);
+ return name.Equals(platformName, StringComparison.OrdinalIgnoreCase);
+ }
}
- private static bool IsAnyOS(IEnumerable<string> names)
+ private static unsafe bool IsAnyOS(IEnumerable<string> names)
{
- return names.Any(p => p.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase));
+ GetPlatformName(out godot_string dest);
+ using (dest)
+ {
+ string platformName = Marshaling.mono_string_from_godot(dest);
+ return names.Any(p => p.Equals(platformName, StringComparison.OrdinalIgnoreCase));
+ }
}
private static readonly IEnumerable<string> LinuxBSDPlatforms =
@@ -114,7 +125,8 @@ namespace GodotTools.Utils
private static string PathWhichWindows([NotNull] string name)
{
- string[] windowsExts = Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) ?? Array.Empty<string>();
+ string[] windowsExts =
+ Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) ?? Array.Empty<string>();
string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep);
char[] invalidPathChars = Path.GetInvalidPathChars();
@@ -141,10 +153,10 @@ namespace GodotTools.Utils
return searchDirs.Select(dir => Path.Combine(dir, name)).FirstOrDefault(File.Exists);
return (from dir in searchDirs
- select Path.Combine(dir, name)
+ select Path.Combine(dir, name)
into path
- from ext in windowsExts
- select path + ext).FirstOrDefault(File.Exists);
+ from ext in windowsExts
+ select path + ext).FirstOrDefault(File.Exists);
}
private static string PathWhichUnix([NotNull] string name)
@@ -168,7 +180,11 @@ namespace GodotTools.Utils
searchDirs.Add(System.IO.Directory.GetCurrentDirectory()); // last in the list
return searchDirs.Select(dir => Path.Combine(dir, name))
- .FirstOrDefault(path => File.Exists(path) && UnixFileHasExecutableAccess(path));
+ .FirstOrDefault(path =>
+ {
+ using godot_string pathIn = Marshaling.mono_string_to_godot(path);
+ return File.Exists(path) && UnixFileHasExecutableAccess(pathIn);
+ });
}
public static void RunProcess(string command, IEnumerable<string> arguments)
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 64fe82664d..f70155f4e8 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -96,9 +96,9 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) {
#define C_CLASS_NATIVE_FUNCS "NativeFuncs"
#define C_NS_MONOUTILS "InteropUtils"
-#define C_METHOD_TIE_MANAGED_TO_UNMANAGED "NativeInterop." C_NS_MONOUTILS ".TieManagedToUnmanaged"
+#define C_METHOD_TIE_MANAGED_TO_UNMANAGED C_NS_MONOUTILS ".TieManagedToUnmanaged"
#define C_METHOD_UNMANAGED_GET_MANAGED C_NS_MONOUTILS ".UnmanagedGetManaged"
-#define C_METHOD_ENGINE_GET_SINGLETON "NativeInterop." C_NS_MONOUTILS ".EngineGetSingleton"
+#define C_METHOD_ENGINE_GET_SINGLETON C_NS_MONOUTILS ".EngineGetSingleton"
#define C_NS_MONOMARSHAL "Marshaling"
#define C_METHOD_MANAGED_TO_VARIANT C_NS_MONOMARSHAL ".mono_object_to_variant"
@@ -1376,6 +1376,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.append("using System;\n"); // IntPtr
output.append("using System.Diagnostics;\n"); // DebuggerBrowsable
+ output.append("using Godot.NativeInterop;\n");
output.append("\n"
"#pragma warning disable CS1591 // Disable warning: "
@@ -1408,7 +1409,11 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
if (itype.is_singleton) {
output.append("static partial class ");
} else {
- output.append(itype.is_instantiable ? "partial class " : "abstract partial class ");
+ // Even if the class is not instantiable, we can't declare it abstract because
+ // the engine can still instantiate them and return them via the scripting API.
+ // Example: `SceneTreeTimer` returned from `SceneTree.create_timer`.
+ // See the reverted commit: ef5672d3f94a7321ed779c922088bb72adbb1521
+ output.append("partial class ");
}
output.append(itype.proxy_name);
@@ -1533,6 +1538,10 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// Add native name static field
+ if (is_derived_type) {
+ output << MEMBER_BEGIN "private static readonly System.Type _cachedType = typeof(" << itype.proxy_name << ");\n";
+ }
+
output.append(MEMBER_BEGIN "private static readonly StringName " BINDINGS_NATIVE_NAME_FIELD " = \"");
output.append(itype.name);
output.append("\";\n");
@@ -1540,27 +1549,19 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
if (itype.is_instantiable) {
// Add native constructor static field
- String get_constructor_method = ICALL_CLASSDB_GET_CONSTRUCTOR;
-
- if (itype.is_singleton) {
- // Singletons are static classes. They don't derive Godot.Object,
- // so we need to specify the type to call the static method.
- get_constructor_method = "Object." + get_constructor_method;
- }
-
output << MEMBER_BEGIN << "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n"
<< "#if NET\n"
<< INDENT2 "private static unsafe readonly delegate* unmanaged<IntPtr> "
- << CS_STATIC_FIELD_NATIVE_CTOR " = " << get_constructor_method
+ << CS_STATIC_FIELD_NATIVE_CTOR " = " ICALL_CLASSDB_GET_CONSTRUCTOR
<< "(" BINDINGS_NATIVE_NAME_FIELD ");\n"
<< "#else\n"
// Get rid of this one once we switch to .NET 5/6
<< INDENT2 "private static readonly IntPtr " CS_STATIC_FIELD_NATIVE_CTOR
- << " = " << get_constructor_method << "(" BINDINGS_NATIVE_NAME_FIELD ");\n"
+ << " = " ICALL_CLASSDB_GET_CONSTRUCTOR "(" BINDINGS_NATIVE_NAME_FIELD ");\n"
<< "#endif\n";
}
@@ -1589,8 +1590,12 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
<< "#endif\n"
- << INDENT4 C_METHOD_TIE_MANAGED_TO_UNMANAGED "(this, " BINDINGS_PTR_FIELD ");\n"
- << CLOSE_BLOCK_L3
+ << INDENT4 C_METHOD_TIE_MANAGED_TO_UNMANAGED "(this, " BINDINGS_PTR_FIELD ", "
+ << BINDINGS_NATIVE_NAME_FIELD << ", refCounted: " << (itype.is_ref_counted ? "true" : "false")
+ << ", ((object)this).GetType(), _cachedType);\n" CLOSE_BLOCK_L3
+ << INDENT3 "else\n" INDENT3 OPEN_BLOCK
+ << INDENT4 "InteropUtils.TieManagedToUnmanagedWithPreSetup(this, "
+ << BINDINGS_PTR_FIELD ", ((object)this).GetType(), _cachedType);\n" CLOSE_BLOCK_L3
<< INDENT3 "_InitializeGodotScriptInstanceInternals();\n" CLOSE_BLOCK_L2;
} else {
// Hide the constructor
@@ -1606,6 +1611,8 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
}
}
+ // Methods
+
int method_bind_count = 0;
for (const MethodInterface &imethod : itype.methods) {
Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output);
@@ -1613,12 +1620,89 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
"Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'.");
}
+ // Signals
+
for (const SignalInterface &isignal : itype.signals_) {
Error method_err = _generate_cs_signal(itype, isignal, output);
ERR_FAIL_COND_V_MSG(method_err != OK, method_err,
"Failed to generate signal '" + isignal.name + "' for class '" + itype.name + "'.");
}
+ // Script calls
+
+ if (!itype.is_singleton && (is_derived_type || itype.has_virtual_methods)) {
+ // TODO: string is ok for now. But should be replaced with StringName in the future for performance.
+
+ output << MEMBER_BEGIN "internal " << (is_derived_type ? "override" : "virtual")
+ << " unsafe bool InternalGodotScriptCall(string method, godot_variant** args, "
+ << "int argCount, out godot_variant ret)\n"
+ << INDENT2 "{\n";
+
+ for (const MethodInterface &imethod : itype.methods) {
+ if (!imethod.is_virtual) {
+ continue;
+ }
+
+ // TODO:
+ // Compare with cached StringName. We already have a cached StringName
+ // field for the proxy name. We need one for the original snake_case name.
+ output << INDENT3 "if ((method == nameof(" << imethod.proxy_name << ") || method == \"" << imethod.name
+ << "\") && argCount == " << itos(imethod.arguments.size()) << ")\n"
+ << INDENT3 "{\n";
+
+ if (imethod.return_type.cname != name_cache.type_void) {
+ output << INDENT4 "object retBoxed = ";
+ } else {
+ output << INDENT4;
+ }
+
+ output << imethod.proxy_name << "(";
+
+ for (int i = 0; i < imethod.arguments.size(); i++) {
+ const ArgumentInterface &iarg = imethod.arguments[i];
+
+ const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found
+
+ if (i != 0) {
+ output << ", ";
+ }
+
+ // TODO: static marshaling (no reflection, no runtime type checks)
+ if (arg_type->cname == name_cache.type_Array_generic || arg_type->cname == name_cache.type_Dictionary_generic) {
+ String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters);
+
+ output << "new " << arg_cs_type << "((" << arg_type->cs_type << ")Marshaling.variant_to_mono_object_of_type(args["
+ << itos(i) << "], typeof(" << arg_type->cs_type << ")))";
+ } else {
+ output << "(" << arg_type->cs_type << ")Marshaling.variant_to_mono_object_of_type(args["
+ << itos(i) << "], typeof(" << arg_type->cs_type << "))";
+ }
+ }
+
+ output << ");\n";
+
+ if (imethod.return_type.cname != name_cache.type_void) {
+ // TODO: static marshaling (no reflection, no runtime type checks)
+ output << INDENT4 "ret = Marshaling.mono_object_to_variant(retBoxed);\n";
+ output << INDENT4 "return true;\n";
+ } else {
+ output << INDENT4 "ret = default;\n";
+ output << INDENT4 "return true;\n";
+ }
+
+ output << INDENT3 "}\n";
+ }
+
+ if (is_derived_type) {
+ output << INDENT3 "return base.InternalGodotScriptCall(method, args, argCount, out ret);\n";
+ } else {
+ output << INDENT3 "return InternalGodotScriptCallViaReflection(method, args, argCount, out ret);\n";
+ }
+
+ output << INDENT2 "}\n";
+ }
+
output.append(INDENT1 CLOSE_BLOCK /* class */
CLOSE_BLOCK /* namespace */);
@@ -2726,6 +2810,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
if (method_info.flags & METHOD_FLAG_VIRTUAL) {
imethod.is_virtual = true;
+ itype.has_virtual_methods = true;
}
PropertyInfo return_info = method_info.return_val;
@@ -2865,7 +2950,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
ERR_FAIL_COND_V_MSG(itype.find_property_by_name(imethod.cname), false,
"Method name conflicts with property: '" + itype.name + "." + imethod.name + "'.");
- // Classes starting with an underscore are ignored unless they're used as a property setter or getter
+ // Methods starting with an underscore are ignored unless they're used as a property setter or getter
if (!imethod.is_virtual && imethod.name[0] == '_') {
for (const PropertyInterface &iprop : itype.properties) {
if (iprop.setter == imethod.name || iprop.getter == imethod.name) {
@@ -3335,7 +3420,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.proxy_name = "string";
itype.cs_type = itype.proxy_name;
itype.c_in = "%5using %0 %1_in = " C_METHOD_MONOSTR_TO_GODOT "(%1);\n";
- itype.c_out = "%5return " C_METHOD_MONOSTR_FROM_GODOT "(&%1);\n";
+ itype.c_out = "%5return " C_METHOD_MONOSTR_FROM_GODOT "(%1);\n";
itype.c_arg_in = "&%s_in";
itype.c_type = "godot_string";
itype.c_type_in = itype.cs_type;
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index 1e1e8be178..c9eb8e6317 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -380,6 +380,8 @@ class BindingsGenerator {
List<MethodInterface> methods;
List<SignalInterface> signals_;
+ bool has_virtual_methods = false;
+
const MethodInterface *find_method_by_name(const StringName &p_cname) const {
for (const MethodInterface &E : methods) {
if (E.cname == p_cname) {
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 102d27378f..dd0d94121d 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -47,177 +47,107 @@
#include "../csharp_script.h"
#include "../godotsharp_dirs.h"
-#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/macos_utils.h"
#include "code_completion.h"
#include "godotsharp_export.h"
-MonoString *godot_icall_GodotSharpDirs_ResDataDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_data_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResMetadataDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_metadata_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResAssembliesBaseDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_assemblies_base_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResAssembliesDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_assemblies_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResConfigDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_config_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResTempDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_temp_dir());
-}
+#include "../interop_types.h"
-MonoString *godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_temp_assemblies_base_dir());
+void godot_icall_GodotSharpDirs_ResMetadataDir(godot_string *r_dest) {
+ memnew_placement(r_dest, String(GodotSharpDirs::get_res_metadata_dir()));
}
-MonoString *godot_icall_GodotSharpDirs_ResTempAssembliesDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_temp_assemblies_dir());
+void godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir(godot_string *r_dest) {
+ memnew_placement(r_dest, String(GodotSharpDirs::get_res_temp_assemblies_base_dir()));
}
-MonoString *godot_icall_GodotSharpDirs_MonoUserDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_mono_user_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_MonoLogsDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_mono_logs_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_MonoSolutionsDir() {
-#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_mono_solutions_dir());
-#else
- return nullptr;
-#endif
-}
-
-MonoString *godot_icall_GodotSharpDirs_BuildLogsDirs() {
-#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_build_logs_dir());
-#else
- return nullptr;
-#endif
+void godot_icall_GodotSharpDirs_MonoUserDir(godot_string *r_dest) {
+ memnew_placement(r_dest, String(GodotSharpDirs::get_mono_user_dir()));
}
-MonoString *godot_icall_GodotSharpDirs_ProjectSlnPath() {
+void godot_icall_GodotSharpDirs_BuildLogsDirs(godot_string *r_dest) {
#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_project_sln_path());
+ memnew_placement(r_dest, String(GodotSharpDirs::get_build_logs_dir()));
#else
return nullptr;
#endif
}
-MonoString *godot_icall_GodotSharpDirs_ProjectCsProjPath() {
+void godot_icall_GodotSharpDirs_ProjectSlnPath(godot_string *r_dest) {
#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_project_csproj_path());
+ memnew_placement(r_dest, String(GodotSharpDirs::get_project_sln_path()));
#else
return nullptr;
#endif
}
-MonoString *godot_icall_GodotSharpDirs_DataEditorToolsDir() {
+void godot_icall_GodotSharpDirs_ProjectCsProjPath(godot_string *r_dest) {
#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_editor_tools_dir());
+ memnew_placement(r_dest, String(GodotSharpDirs::get_project_csproj_path()));
#else
return nullptr;
#endif
}
-MonoString *godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir() {
+void godot_icall_GodotSharpDirs_DataEditorToolsDir(godot_string *r_dest) {
#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_editor_prebuilt_api_dir());
-#else
- return nullptr;
-#endif
-}
-
-MonoString *godot_icall_GodotSharpDirs_DataMonoEtcDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_mono_etc_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_DataMonoLibDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_mono_lib_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_DataMonoBinDir() {
-#ifdef WINDOWS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_mono_bin_dir());
+ memnew_placement(r_dest, String(GodotSharpDirs::get_data_editor_tools_dir()));
#else
return nullptr;
#endif
}
-void godot_icall_EditorProgress_Create(MonoString *p_task, MonoString *p_label, int32_t p_amount, MonoBoolean p_can_cancel) {
- String task = GDMonoMarshal::mono_string_to_godot(p_task);
- String label = GDMonoMarshal::mono_string_to_godot(p_label);
+void godot_icall_EditorProgress_Create(const godot_string *p_task, const godot_string *p_label, int32_t p_amount, bool p_can_cancel) {
+ String task = *reinterpret_cast<const String *>(p_task);
+ String label = *reinterpret_cast<const String *>(p_label);
EditorNode::progress_add_task(task, label, p_amount, (bool)p_can_cancel);
}
-void godot_icall_EditorProgress_Dispose(MonoString *p_task) {
- String task = GDMonoMarshal::mono_string_to_godot(p_task);
+void godot_icall_EditorProgress_Dispose(const godot_string *p_task) {
+ String task = *reinterpret_cast<const String *>(p_task);
EditorNode::progress_end_task(task);
}
-MonoBoolean godot_icall_EditorProgress_Step(MonoString *p_task, MonoString *p_state, int32_t p_step, MonoBoolean p_force_refresh) {
- String task = GDMonoMarshal::mono_string_to_godot(p_task);
- String state = GDMonoMarshal::mono_string_to_godot(p_state);
+bool godot_icall_EditorProgress_Step(const godot_string *p_task, const godot_string *p_state, int32_t p_step, bool p_force_refresh) {
+ String task = *reinterpret_cast<const String *>(p_task);
+ String state = *reinterpret_cast<const String *>(p_state);
return EditorNode::progress_task_step(task, state, p_step, (bool)p_force_refresh);
}
-uint32_t godot_icall_ExportPlugin_GetExportedAssemblyDependencies(MonoObject *p_initial_assemblies,
- MonoString *p_build_config, MonoString *p_custom_bcl_dir, MonoObject *r_assembly_dependencies) {
- Dictionary initial_dependencies = GDMonoMarshal::mono_object_to_variant(p_initial_assemblies);
- String build_config = GDMonoMarshal::mono_string_to_godot(p_build_config);
- String custom_bcl_dir = GDMonoMarshal::mono_string_to_godot(p_custom_bcl_dir);
- Dictionary assembly_dependencies = GDMonoMarshal::mono_object_to_variant(r_assembly_dependencies);
+uint32_t godot_icall_ExportPlugin_GetExportedAssemblyDependencies(const godot_dictionary *p_initial_assemblies,
+ const godot_string *p_build_config, const godot_string *p_custom_bcl_dir, godot_dictionary *r_assembly_dependencies) {
+ Dictionary initial_dependencies = *reinterpret_cast<const Dictionary *>(p_initial_assemblies);
+ String build_config = *reinterpret_cast<const String *>(p_build_config);
+ String custom_bcl_dir = *reinterpret_cast<const String *>(p_custom_bcl_dir);
+ Dictionary assembly_dependencies = *reinterpret_cast<Dictionary *>(r_assembly_dependencies);
return GodotSharpExport::get_exported_assembly_dependencies(initial_dependencies, build_config, custom_bcl_dir, assembly_dependencies);
}
-MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt(MonoString *p_config) {
- String config = GDMonoMarshal::mono_string_to_godot(p_config);
- String error_str = GDMono::get_singleton()->update_api_assemblies_from_prebuilt(config);
- return GDMonoMarshal::mono_string_from_godot(error_str);
-}
-
-MonoString *godot_icall_Internal_FullExportTemplatesDir() {
+void godot_icall_Internal_FullExportTemplatesDir(godot_string *r_dest) {
String full_templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
- return GDMonoMarshal::mono_string_from_godot(full_templates_dir);
-}
-
-MonoString *godot_icall_Internal_SimplifyGodotPath(MonoString *p_path) {
- String path = GDMonoMarshal::mono_string_to_godot(p_path);
- return GDMonoMarshal::mono_string_from_godot(path.simplify_path());
+ memnew_placement(r_dest, String(full_templates_dir));
}
-MonoBoolean godot_icall_Internal_IsMacOSAppBundleInstalled(MonoString *p_bundle_id) {
+bool godot_icall_Internal_IsMacOSAppBundleInstalled(const godot_string *p_bundle_id) {
#ifdef MACOS_ENABLED
- String bundle_id = GDMonoMarshal::mono_string_to_godot(p_bundle_id);
- return (MonoBoolean)macos_is_app_bundle_installed(bundle_id);
+ String bundle_id = *reinterpret_cast<const String *>(p_bundle_id);
+ return (bool)macos_is_app_bundle_installed(bundle_id);
#else
(void)p_bundle_id; // UNUSED
- return (MonoBoolean) false;
+ return (bool)false;
#endif
}
-MonoBoolean godot_icall_Internal_GodotIs32Bits() {
+bool godot_icall_Internal_GodotIs32Bits() {
return sizeof(void *) == 4;
}
-MonoBoolean godot_icall_Internal_GodotIsRealTDouble() {
+bool godot_icall_Internal_GodotIsRealTDouble() {
#ifdef REAL_T_IS_DOUBLE
- return (MonoBoolean) true;
+ return (bool)true;
#else
- return (MonoBoolean) false;
+ return (bool)false;
#endif
}
@@ -225,23 +155,15 @@ void godot_icall_Internal_GodotMainIteration() {
Main::iteration();
}
-uint64_t godot_icall_Internal_GetCoreApiHash() {
- return ClassDB::get_api_hash(ClassDB::API_CORE);
-}
-
-uint64_t godot_icall_Internal_GetEditorApiHash() {
- return ClassDB::get_api_hash(ClassDB::API_EDITOR);
-}
-
-MonoBoolean godot_icall_Internal_IsAssembliesReloadingNeeded() {
+bool godot_icall_Internal_IsAssembliesReloadingNeeded() {
#ifdef GD_MONO_HOT_RELOAD
- return (MonoBoolean)CSharpLanguage::get_singleton()->is_assembly_reloading_needed();
+ return (bool)CSharpLanguage::get_singleton()->is_assembly_reloading_needed();
#else
- return (MonoBoolean) false;
+ return (bool)false;
#endif
}
-void godot_icall_Internal_ReloadAssemblies(MonoBoolean p_soft_reload) {
+void godot_icall_Internal_ReloadAssemblies(bool p_soft_reload) {
#ifdef GD_MONO_HOT_RELOAD
mono_bind::GodotSharp::get_singleton()->call_deferred(SNAME("_reload_assemblies"), (bool)p_soft_reload);
#endif
@@ -251,21 +173,22 @@ void godot_icall_Internal_EditorDebuggerNodeReloadScripts() {
EditorDebuggerNode::get_singleton()->reload_scripts();
}
-MonoBoolean godot_icall_Internal_ScriptEditorEdit(MonoObject *p_resource, int32_t p_line, int32_t p_col, MonoBoolean p_grab_focus) {
- Ref<Resource> resource = GDMonoMarshal::mono_object_to_variant(p_resource);
- return (MonoBoolean)ScriptEditor::get_singleton()->edit(resource, p_line, p_col, (bool)p_grab_focus);
+bool godot_icall_Internal_ScriptEditorEdit(Resource *p_resource, int32_t p_line, int32_t p_col, bool p_grab_focus) {
+ Ref<Resource> resource = p_resource;
+ return (bool)ScriptEditor::get_singleton()->edit(resource, p_line, p_col, (bool)p_grab_focus);
}
void godot_icall_Internal_EditorNodeShowScriptScreen() {
EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
}
-MonoString *godot_icall_Internal_MonoWindowsInstallRoot() {
+void godot_icall_Internal_MonoWindowsInstallRoot(godot_string *r_dest) {
#ifdef WINDOWS_ENABLED
String install_root_dir = GDMono::get_singleton()->get_mono_reg_info().install_root_dir;
- return GDMonoMarshal::mono_string_from_godot(install_root_dir);
+ memnew_placement(r_dest, String(install_root_dir));
#else
- return nullptr;
+ memnew_placement(r_dest, String);
+ return;
#endif
}
@@ -284,49 +207,49 @@ void godot_icall_Internal_ScriptEditorDebugger_ReloadScripts() {
}
}
-MonoArray *godot_icall_Internal_CodeCompletionRequest(int32_t p_kind, MonoString *p_script_file) {
- String script_file = GDMonoMarshal::mono_string_to_godot(p_script_file);
+void godot_icall_Internal_CodeCompletionRequest(int32_t p_kind, const godot_string *p_script_file, godot_packed_array *r_ret) {
+ String script_file = *reinterpret_cast<const String *>(p_script_file);
PackedStringArray suggestions = gdmono::get_code_completion((gdmono::CompletionKind)p_kind, script_file);
- return GDMonoMarshal::PackedStringArray_to_mono_array(suggestions);
+ memnew_placement(r_ret, PackedStringArray(suggestions));
}
float godot_icall_Globals_EditorScale() {
return EDSCALE;
}
-MonoObject *godot_icall_Globals_GlobalDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) {
- String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
- Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value);
+void godot_icall_Globals_GlobalDef(const godot_string *p_setting, const godot_variant *p_default_value, bool p_restart_if_changed, godot_variant *r_result) {
+ String setting = *reinterpret_cast<const String *>(p_setting);
+ Variant default_value = *reinterpret_cast<const Variant *>(p_default_value);
Variant result = _GLOBAL_DEF(setting, default_value, (bool)p_restart_if_changed);
- return GDMonoMarshal::variant_to_mono_object(result);
+ memnew_placement(r_result, Variant(result));
}
-MonoObject *godot_icall_Globals_EditorDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) {
- String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
- Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value);
+void godot_icall_Globals_EditorDef(const godot_string *p_setting, const godot_variant *p_default_value, bool p_restart_if_changed, godot_variant *r_result) {
+ String setting = *reinterpret_cast<const String *>(p_setting);
+ Variant default_value = *reinterpret_cast<const Variant *>(p_default_value);
Variant result = _EDITOR_DEF(setting, default_value, (bool)p_restart_if_changed);
- return GDMonoMarshal::variant_to_mono_object(result);
+ memnew_placement(r_result, Variant(result));
}
-MonoObject *godot_icall_Globals_EditorShortcut(MonoString *p_setting) {
- String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
+void godot_icall_Globals_EditorShortcut(const godot_string *p_setting, godot_variant *r_result) {
+ String setting = *reinterpret_cast<const String *>(p_setting);
Ref<Shortcut> result = ED_GET_SHORTCUT(setting);
- return GDMonoMarshal::variant_to_mono_object(result);
+ memnew_placement(r_result, Variant(result));
}
-MonoString *godot_icall_Globals_TTR(MonoString *p_text) {
- String text = GDMonoMarshal::mono_string_to_godot(p_text);
- return GDMonoMarshal::mono_string_from_godot(TTR(text));
+void godot_icall_Globals_TTR(const godot_string *p_text, godot_string *r_dest) {
+ String text = *reinterpret_cast<const String *>(p_text);
+ memnew_placement(r_dest, String(TTR(text)));
}
-MonoString *godot_icall_Utils_OS_GetPlatformName() {
+void godot_icall_Utils_OS_GetPlatformName(godot_string *r_dest) {
String os_name = OS::get_singleton()->get_name();
- return GDMonoMarshal::mono_string_from_godot(os_name);
+ memnew_placement(r_dest, String(os_name));
}
-MonoBoolean godot_icall_Utils_OS_UnixFileHasExecutableAccess(MonoString *p_file_path) {
+bool godot_icall_Utils_OS_UnixFileHasExecutableAccess(const godot_string *p_file_path) {
#ifdef UNIX_ENABLED
- String file_path = GDMonoMarshal::mono_string_to_godot(p_file_path);
+ String file_path = *reinterpret_cast<const String *>(p_file_path);
return access(file_path.utf8().get_data(), X_OK) == 0;
#else
ERR_FAIL_V(false);
@@ -335,25 +258,13 @@ MonoBoolean godot_icall_Utils_OS_UnixFileHasExecutableAccess(MonoString *p_file_
void register_editor_internal_calls() {
// GodotSharpDirs
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResDataDir", godot_icall_GodotSharpDirs_ResDataDir);
GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResMetadataDir", godot_icall_GodotSharpDirs_ResMetadataDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesBaseDir", godot_icall_GodotSharpDirs_ResAssembliesBaseDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesDir", godot_icall_GodotSharpDirs_ResAssembliesDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResConfigDir", godot_icall_GodotSharpDirs_ResConfigDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempDir", godot_icall_GodotSharpDirs_ResTempDir);
GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesBaseDir", godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesDir", godot_icall_GodotSharpDirs_ResTempAssembliesDir);
GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoUserDir", godot_icall_GodotSharpDirs_MonoUserDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoLogsDir", godot_icall_GodotSharpDirs_MonoLogsDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoSolutionsDir", godot_icall_GodotSharpDirs_MonoSolutionsDir);
GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_BuildLogsDirs", godot_icall_GodotSharpDirs_BuildLogsDirs);
GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectSlnPath", godot_icall_GodotSharpDirs_ProjectSlnPath);
GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectCsProjPath", godot_icall_GodotSharpDirs_ProjectCsProjPath);
GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorToolsDir", godot_icall_GodotSharpDirs_DataEditorToolsDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorPrebuiltApiDir", godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoEtcDir", godot_icall_GodotSharpDirs_DataMonoEtcDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoLibDir", godot_icall_GodotSharpDirs_DataMonoLibDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoBinDir", godot_icall_GodotSharpDirs_DataMonoBinDir);
// EditorProgress
GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Create", godot_icall_EditorProgress_Create);
@@ -364,15 +275,11 @@ void register_editor_internal_calls() {
GDMonoUtils::add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", godot_icall_ExportPlugin_GetExportedAssemblyDependencies);
// Internals
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_FullExportTemplatesDir", godot_icall_Internal_FullExportTemplatesDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", godot_icall_Internal_SimplifyGodotPath);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsMacOSAppBundleInstalled", godot_icall_Internal_IsMacOSAppBundleInstalled);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", godot_icall_Internal_GodotIs32Bits);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", godot_icall_Internal_GodotIsRealTDouble);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", godot_icall_Internal_GodotMainIteration);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetCoreApiHash", godot_icall_Internal_GetCoreApiHash);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetEditorApiHash", godot_icall_Internal_GetEditorApiHash);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsAssembliesReloadingNeeded", godot_icall_Internal_IsAssembliesReloadingNeeded);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ReloadAssemblies", godot_icall_Internal_ReloadAssemblies);
GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorDebuggerNodeReloadScripts", godot_icall_Internal_EditorDebuggerNodeReloadScripts);
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index f9ea403334..d065aa30e5 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -92,7 +92,7 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, MonoAssemblyName *re
mono_assembly_get_assemblyref(image, i, reusable_aname);
GDMonoAssembly *ref_assembly = nullptr;
- if (!GDMono::get_singleton()->load_assembly(ref_name, reusable_aname, &ref_assembly, /* refonly: */ true, p_search_dirs)) {
+ if (!GDMono::get_singleton()->load_assembly(ref_name, reusable_aname, &ref_assembly, p_search_dirs)) {
ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'.");
}
@@ -126,7 +126,7 @@ Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,
String assembly_path = p_initial_assemblies[*key];
GDMonoAssembly *assembly = nullptr;
- bool load_success = GDMono::get_singleton()->load_assembly_from(assembly_name, assembly_path, &assembly, /* refonly: */ true);
+ bool load_success = GDMono::get_singleton()->load_assembly_from(assembly_name, assembly_path, &assembly);
ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + assembly_name + "'.");
diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h
index 60620b5f4d..20d6f6fe73 100644
--- a/modules/mono/editor/godotsharp_export.h
+++ b/modules/mono/editor/godotsharp_export.h
@@ -35,12 +35,8 @@
#include "core/string/ustring.h"
#include "core/variant/dictionary.h"
-#include "../mono_gd/gd_mono_header.h"
-
namespace GodotSharpExport {
-Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies);
-
Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,
const String &p_build_config, const String &p_custom_lib_dir, Dictionary &r_assembly_dependencies);
} // namespace GodotSharpExport
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index 893ab81e5d..a2a97e0a3e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -14,7 +14,7 @@ namespace Godot.Collections
/// </summary>
public sealed class Array : IList, IDisposable
{
- internal godot_array NativeValue;
+ public godot_array NativeValue;
/// <summary>
/// Constructs a new empty <see cref="Array"/>.
@@ -307,7 +307,7 @@ namespace Godot.Collections
{
using godot_string str = default;
NativeFuncs.godotsharp_array_to_string(ref NativeValue, &str);
- return Marshaling.mono_string_from_godot(&str);
+ return Marshaling.mono_string_from_godot(str);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
index 2febf37f05..b7d633517a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
@@ -1,5 +1,7 @@
using System;
+#nullable enable
+
namespace Godot
{
/// <summary>
@@ -8,25 +10,28 @@ namespace Godot
[AttributeUsage(AttributeTargets.Assembly)]
public class AssemblyHasScriptsAttribute : Attribute
{
- private readonly bool requiresLookup;
- private readonly System.Type[] scriptTypes;
+ public bool RequiresLookup { get; }
+ public Type[]? ScriptTypes { get; }
/// <summary>
/// Constructs a new AssemblyHasScriptsAttribute instance.
/// </summary>
public AssemblyHasScriptsAttribute()
{
- requiresLookup = true;
+ RequiresLookup = true;
+ ScriptTypes = null;
}
/// <summary>
/// Constructs a new AssemblyHasScriptsAttribute instance.
/// </summary>
/// <param name="scriptTypes">The specified type(s) of scripts.</param>
- public AssemblyHasScriptsAttribute(System.Type[] scriptTypes)
+ public AssemblyHasScriptsAttribute(Type[] scriptTypes)
{
- requiresLookup = false;
- this.scriptTypes = scriptTypes;
+ RequiresLookup = false;
+ ScriptTypes = scriptTypes;
}
}
}
+
+#nullable restore
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
index 3ebb6612de..2c8a53ae1c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
@@ -8,7 +8,7 @@ namespace Godot
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ScriptPathAttribute : Attribute
{
- private string path;
+ public string Path { get; }
/// <summary>
/// Constructs a new ScriptPathAttribute instance.
@@ -16,7 +16,7 @@ namespace Godot
/// <param name="path">The file path to the script</param>
public ScriptPathAttribute(string path)
{
- this.path = path;
+ Path = path;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
new file mode 100644
index 0000000000..16fde2a900
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
+
+namespace Godot.Bridge
+{
+ internal static class CSharpInstanceBridge
+ {
+ private static unsafe void Call(IntPtr godotObjectGCHandle, godot_string_name* method,
+ godot_variant** args, int argCount, godot_variant_call_error* ref_callError, godot_variant* r_ret)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (godotObject == null)
+ {
+ *r_ret = default;
+ (*ref_callError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL;
+ return;
+ }
+
+ using godot_string dest = default;
+ NativeFuncs.godotsharp_string_name_as_string(&dest, method);
+ string methodStr = Marshaling.mono_string_from_godot(dest);
+
+ bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, args, argCount, out godot_variant outRet);
+
+ if (!methodInvoked)
+ {
+ *r_ret = default;
+ // This is important, as it tells Object::call that no method was called.
+ // Otherwise, it would prevent Object::call from calling native methods.
+ (*ref_callError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD;
+ return;
+ }
+
+ *r_ret = outRet;
+ }
+
+ private static unsafe bool Set(IntPtr godotObjectGCHandle, godot_string_name* name, godot_variant* value)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (godotObject == null)
+ throw new InvalidOperationException();
+
+ var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(name));
+
+ if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection(nameManaged.ToString(), value))
+ return true;
+
+ object valueManaged = Marshaling.variant_to_mono_object(value);
+
+ return godotObject._Set(nameManaged, valueManaged);
+ }
+
+ private static unsafe bool Get(IntPtr godotObjectGCHandle, godot_string_name* name, godot_variant* r_retValue)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (godotObject == null)
+ throw new InvalidOperationException();
+
+ var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(name));
+
+ if (godotObject.InternalGodotScriptGetFieldOrPropViaReflection(nameManaged.ToString(),
+ out godot_variant outRet))
+ {
+ *r_retValue = outRet;
+ return true;
+ }
+
+ object ret = godotObject._Get(nameManaged);
+
+ if (ret == null)
+ {
+ *r_retValue = default;
+ return false;
+ }
+
+ *r_retValue = Marshaling.mono_object_to_variant(ret);
+ return true;
+ }
+
+ private static void CallDispose(IntPtr godotObjectGCHandle, bool okIfNull)
+ {
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (okIfNull)
+ godotObject?.Dispose();
+ else
+ godotObject!.Dispose();
+ }
+
+ private static unsafe void CallToString(IntPtr godotObjectGCHandle, godot_string* r_res, bool* r_valid)
+ {
+ var self = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (self == null)
+ {
+ *r_res = default;
+ *r_valid = false;
+ return;
+ }
+
+ var resultStr = self.ToString();
+
+ if (resultStr == null)
+ {
+ *r_res = default;
+ *r_valid = false;
+ return;
+ }
+
+ *r_res = Marshaling.mono_string_to_godot(resultStr);
+ *r_valid = true;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs
new file mode 100644
index 0000000000..aa9e434b07
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot.Bridge
+{
+ internal static class GCHandleBridge
+ {
+ private static void FreeGCHandle(IntPtr gcHandlePtr)
+ => GCHandle.FromIntPtr(gcHandlePtr).Free();
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
new file mode 100644
index 0000000000..a39da68a02
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -0,0 +1,501 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using Godot.Collections;
+using Godot.NativeInterop;
+
+namespace Godot.Bridge
+{
+ internal static class ScriptManagerBridge
+ {
+ private static System.Collections.Generic.Dictionary<string, ScriptLookupInfo> _scriptLookupMap = new();
+ private static System.Collections.Generic.Dictionary<IntPtr, Type> _scriptBridgeMap = new();
+
+ private struct ScriptLookupInfo
+ {
+ public string ClassNamespace { get; private set; }
+ public string ClassName { get; private set; }
+ public Type ScriptType { get; private set; }
+
+ public ScriptLookupInfo(string classNamespace, string className, Type scriptType)
+ {
+ ClassNamespace = classNamespace;
+ ClassName = className;
+ ScriptType = scriptType;
+ }
+ };
+
+ internal static void FrameCallback()
+ {
+ Dispatcher.DefaultGodotTaskScheduler?.Activate();
+ }
+
+ internal static unsafe IntPtr CreateManagedForGodotObjectBinding(godot_string_name* nativeTypeName,
+ IntPtr godotObject)
+ {
+ Type nativeType = TypeGetProxyClass(nativeTypeName);
+ var obj = (Object)FormatterServices.GetUninitializedObject(nativeType);
+
+ obj.NativePtr = godotObject;
+
+ var ctor = nativeType.GetConstructor(
+ BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
+ null, Type.EmptyTypes, null);
+ _ = ctor!.Invoke(obj, null);
+
+ return GCHandle.ToIntPtr(GCHandle.Alloc(obj));
+ }
+
+ internal static unsafe void CreateManagedForGodotObjectScriptInstance(IntPtr scriptPtr, IntPtr godotObject,
+ godot_variant** args, int argCount)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ Type scriptType = _scriptBridgeMap[scriptPtr];
+ var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
+
+ obj.NativePtr = godotObject;
+
+ var ctor = scriptType
+ .GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
+ .Where(c => c.GetParameters().Length == argCount)
+ .FirstOrDefault();
+
+ if (ctor == null)
+ {
+ if (argCount == 0)
+ {
+ throw new MissingMemberException(
+ $"Cannot create script instance. The class '{scriptType.FullName}' does not define a parameterless constructor.");
+ }
+ else
+ {
+ throw new MissingMemberException(
+ $"The class '{scriptType.FullName}' does not define a constructor that takes x parameters.");
+ }
+ }
+
+ var parameters = ctor.GetParameters();
+ int paramCount = parameters.Length;
+
+ object[] invokeParams = new object[paramCount];
+
+ for (int i = 0; i < paramCount; i++)
+ {
+ invokeParams[i] = Marshaling.variant_to_mono_object_of_type(
+ args[i], parameters[i].ParameterType);
+ }
+
+ ctor.Invoke(obj, invokeParams);
+ }
+
+ private static unsafe void GetScriptNativeName(IntPtr scriptPtr, godot_string_name* r_res)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
+ {
+ *r_res = default;
+ return;
+ }
+
+ var native = Object.InternalGetClassNativeBase(scriptType);
+
+ var field = native?.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.Public | BindingFlags.NonPublic);
+
+ if (field == null)
+ {
+ *r_res = default;
+ return;
+ }
+
+ var nativeName = (StringName)field.GetValue(null);
+
+ *r_res = NativeFuncs.godotsharp_string_name_new_copy(nativeName.NativeValue);
+ }
+
+ private static void SetGodotObjectPtr(IntPtr gcHandlePtr, IntPtr newPtr)
+ {
+ var target = (Object)GCHandle.FromIntPtr(gcHandlePtr).Target;
+ if (target != null)
+ target.NativePtr = newPtr;
+ }
+
+ private static unsafe Type TypeGetProxyClass(godot_string_name* nativeTypeName)
+ {
+ // Performance is not critical here as this will be replaced with a generated dictionary.
+ using var stringName = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(nativeTypeName));
+ string nativeTypeNameStr = stringName.ToString();
+
+ if (nativeTypeNameStr[0] == '_')
+ nativeTypeNameStr = nativeTypeNameStr.Substring(1);
+
+ Type wrapperType = typeof(Object).Assembly.GetType("Godot." + nativeTypeNameStr);
+
+ if (wrapperType == null)
+ {
+ wrapperType = AppDomain.CurrentDomain.GetAssemblies()
+ .First(a => a.GetName().Name == "GodotSharpEditor")
+ .GetType("Godot." + nativeTypeNameStr);
+ }
+
+ static bool IsStatic(Type type) => type.IsAbstract && type.IsSealed;
+
+ if (wrapperType != null && IsStatic(wrapperType))
+ {
+ // A static class means this is a Godot singleton class. If an instance is needed we use Godot.Object.
+ return typeof(Object);
+ }
+
+ return wrapperType;
+ }
+
+ internal static void LookupScriptsInAssembly(Assembly assembly)
+ {
+ static void LookupScriptForClass(Type type)
+ {
+ var scriptPathAttr = type.GetCustomAttributes(inherit: false)
+ .OfType<ScriptPathAttribute>()
+ .FirstOrDefault();
+
+ if (scriptPathAttr == null)
+ return;
+
+ _scriptLookupMap[scriptPathAttr.Path] = new ScriptLookupInfo(type.Namespace, type.Name, type);
+ }
+
+ var assemblyHasScriptsAttr = assembly.GetCustomAttributes(inherit: false)
+ .OfType<AssemblyHasScriptsAttribute>()
+ .FirstOrDefault();
+
+ if (assemblyHasScriptsAttr == null)
+ return;
+
+ if (assemblyHasScriptsAttr.RequiresLookup)
+ {
+ // This is supported for scenarios where specifying all types would be cumbersome,
+ // such as when disabling C# source generators (for whatever reason) or when using a
+ // language other than C# that has nothing similar to source generators to automate it.
+
+ var typeOfGodotObject = typeof(Object);
+
+ foreach (var type in assembly.GetTypes())
+ {
+ if (type.IsNested)
+ continue;
+
+ if (!typeOfGodotObject.IsAssignableFrom(type))
+ continue;
+
+ LookupScriptForClass(type);
+ }
+ }
+ else
+ {
+ // This is the most likely scenario as we use C# source generators
+
+ var scriptTypes = assemblyHasScriptsAttr.ScriptTypes;
+
+ if (scriptTypes != null)
+ {
+ for (int i = 0; i < scriptTypes.Length; i++)
+ {
+ LookupScriptForClass(scriptTypes[i]);
+ }
+ }
+ }
+ }
+
+ internal static unsafe void RaiseEventSignal(IntPtr ownerGCHandlePtr,
+ godot_string_name* eventSignalName, godot_variant** args, int argCount, bool* r_ownerIsNull)
+ {
+ var owner = (Object)GCHandle.FromIntPtr(ownerGCHandlePtr).Target;
+
+ if (owner == null)
+ {
+ *r_ownerIsNull = true;
+ return;
+ }
+
+ *r_ownerIsNull = false;
+
+ owner.InternalRaiseEventSignal(eventSignalName, args, argCount);
+ }
+
+ internal static unsafe void GetScriptSignalList(IntPtr scriptPtr, godot_dictionary* r_retSignals)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ using var signals = new Dictionary();
+
+ Type top = _scriptBridgeMap[scriptPtr];
+ Type native = Object.InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ // Legacy signals
+
+ foreach (var signalDelegate in top
+ .GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
+ .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
+ .Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any()))
+ {
+ var invokeMethod = signalDelegate.GetMethod("Invoke");
+
+ if (invokeMethod == null)
+ throw new MissingMethodException(signalDelegate.FullName, "Invoke");
+
+ var signalParams = new Collections.Array();
+
+ foreach (var parameters in invokeMethod.GetParameters())
+ {
+ var paramType = Marshaling.managed_to_variant_type(
+ parameters.ParameterType, out bool nilIsVariant);
+ signalParams.Add(new Dictionary()
+ {
+ { "name", parameters.Name },
+ { "type", paramType },
+ { "nil_is_variant", nilIsVariant }
+ });
+ }
+
+ signals.Add(signalDelegate.Name, signalParams);
+ }
+
+ // Event signals
+
+ var foundEventSignals = top.GetEvents(
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public)
+ .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
+ .Select(ev => ev.Name);
+
+ var fields = top.GetFields(
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ foreach (var eventSignalField in fields
+ .Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
+ .Where(f => foundEventSignals.Contains(f.Name)))
+ {
+ var delegateType = eventSignalField.FieldType;
+ var invokeMethod = delegateType.GetMethod("Invoke");
+
+ if (invokeMethod == null)
+ throw new MissingMethodException(delegateType.FullName, "Invoke");
+
+ var signalParams = new Collections.Array();
+
+ foreach (var parameters in invokeMethod.GetParameters())
+ {
+ var paramType = Marshaling.managed_to_variant_type(
+ parameters.ParameterType, out bool nilIsVariant);
+ signalParams.Add(new Dictionary()
+ {
+ { "name", parameters.Name },
+ { "type", paramType },
+ { "nil_is_variant", nilIsVariant }
+ });
+ }
+
+ signals.Add(eventSignalField.Name, signalParams);
+ }
+
+ top = top.BaseType;
+ }
+
+ *r_retSignals = NativeFuncs.godotsharp_dictionary_new_copy(signals.NativeValue);
+ }
+
+ internal static unsafe bool HasScriptSignal(IntPtr scriptPtr, godot_string* signalName)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ using var signals = new Dictionary();
+
+ string signalNameStr = Marshaling.mono_string_from_godot(*signalName);
+
+ Type top = _scriptBridgeMap[scriptPtr];
+ Type native = Object.InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ // Legacy signals
+
+ if (top
+ .GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
+ .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
+ .Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any())
+ .Any(signalDelegate => signalDelegate.Name == signalNameStr)
+ )
+ {
+ return true;
+ }
+
+ // Event signals
+
+ if (top.GetEvents(
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public)
+ .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
+ .Any(eventSignal => eventSignal.Name == signalNameStr)
+ )
+ {
+ return true;
+ }
+
+ top = top.BaseType;
+ }
+
+ return false;
+ }
+
+ internal static unsafe bool HasMethodUnknownParams(IntPtr scriptPtr, godot_string* method, bool deep)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
+ return false;
+
+ string methodStr = Marshaling.mono_string_from_godot(*method);
+
+ if (deep)
+ {
+ Type top = scriptType;
+ Type native = Object.InternalGetClassNativeBase(scriptType);
+
+ while (top != null && top != native)
+ {
+ var methodInfo = top.GetMethod(methodStr,
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (methodInfo != null)
+ return true;
+
+ top = top.BaseType;
+ }
+
+ return false;
+ }
+ else
+ {
+ var methodInfo = scriptType.GetMethod(methodStr, BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public);
+ return methodInfo != null;
+ }
+ }
+
+ internal static bool ScriptIsOrInherits(IntPtr scriptPtr, IntPtr scriptPtrMaybeBase)
+ {
+ if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
+ return false;
+
+ if (!_scriptBridgeMap.TryGetValue(scriptPtrMaybeBase, out var maybeBaseType))
+ return false;
+
+ return scriptType == maybeBaseType || maybeBaseType.IsAssignableFrom(scriptType);
+ }
+
+ internal static unsafe bool AddScriptBridge(IntPtr scriptPtr, godot_string* scriptPath)
+ {
+ string scriptPathStr = Marshaling.mono_string_from_godot(*scriptPath);
+
+ if (!_scriptLookupMap.TryGetValue(scriptPathStr, out var lookupInfo))
+ return false;
+
+ _scriptBridgeMap.Add(scriptPtr, lookupInfo.ScriptType);
+
+ return true;
+ }
+
+ internal static void AddScriptBridgeWithType(IntPtr scriptPtr, Type scriptType)
+ => _scriptBridgeMap.Add(scriptPtr, scriptType);
+
+ internal static void RemoveScriptBridge(IntPtr scriptPtr)
+ => _scriptBridgeMap.Remove(scriptPtr);
+
+ internal static unsafe void UpdateScriptClassInfo(IntPtr scriptPtr, bool* r_tool,
+ godot_dictionary* r_rpcFunctionsDest)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ var scriptType = _scriptBridgeMap[scriptPtr];
+
+ *r_tool = scriptType.GetCustomAttributes(inherit: false)
+ .OfType<ToolAttribute>()
+ .Any();
+
+ if (!*r_tool && scriptType.IsNested)
+ {
+ *r_tool = scriptType.DeclaringType?.GetCustomAttributes(inherit: false)
+ .OfType<ToolAttribute>()
+ .Any() ?? false;
+ }
+
+ if (!*r_tool && scriptType.Assembly.GetName().Name == "GodotTools")
+ *r_tool = true;
+
+ // RPC functions
+
+ Dictionary<string, Dictionary> rpcFunctions = new();
+
+ Type top = _scriptBridgeMap[scriptPtr];
+ Type native = Object.InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ foreach (var method in top.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public))
+ {
+ if (method.IsStatic)
+ continue;
+
+ string methodName = method.Name;
+
+ if (rpcFunctions.ContainsKey(methodName))
+ continue;
+
+ var rpcAttr = method.GetCustomAttributes(inherit: false)
+ .OfType<RPCAttribute>().FirstOrDefault();
+
+ if (rpcAttr == null)
+ continue;
+
+ var rpcConfig = new Dictionary();
+
+ rpcConfig["rpc_mode"] = (long)rpcAttr.Mode;
+ rpcConfig["call_local"] = rpcAttr.CallLocal;
+ rpcConfig["transfer_mode"] = (long)rpcAttr.TransferMode;
+ rpcConfig["channel"] = rpcAttr.TransferChannel;
+
+ rpcFunctions.Add(methodName, rpcConfig);
+ }
+
+ top = top.BaseType;
+ }
+
+ *r_rpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new_copy(((Dictionary)rpcFunctions).NativeValue);
+ }
+
+ internal static unsafe bool SwapGCHandleForType(IntPtr oldGCHandlePtr, IntPtr* r_newGCHandlePtr,
+ bool createWeak)
+ {
+ var oldGCHandle = GCHandle.FromIntPtr(oldGCHandlePtr);
+
+ object target = oldGCHandle.Target;
+
+ if (target == null)
+ {
+ oldGCHandle.Free();
+ *r_newGCHandlePtr = IntPtr.Zero;
+ return false; // Called after the managed side was collected, so nothing to do here
+ }
+
+ // Release the current weak handle and replace it with a strong handle.
+ var newGCHandle = GCHandle.Alloc(target, createWeak ? GCHandleType.Weak : GCHandleType.Normal);
+
+ oldGCHandle.Free();
+ *r_newGCHandlePtr = GCHandle.ToIntPtr(newGCHandle);
+ return true;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index 187d910f9f..2a562d4d48 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -11,10 +11,6 @@ namespace Godot
{
internal static class DelegateUtils
{
- // TODO: Move somewhere else once we need to for things other than delegates
- internal static void FreeGCHandle(IntPtr delegateGCHandle)
- => GCHandle.FromIntPtr(delegateGCHandle).Free();
-
internal static bool DelegateEquals(IntPtr delegateGCHandleA, IntPtr delegateGCHandleB)
{
var @delegateA = (Delegate)GCHandle.FromIntPtr(delegateGCHandleA).Target;
@@ -22,14 +18,14 @@ namespace Godot
return @delegateA == @delegateB;
}
- internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, godot_variant** args, uint argc, godot_variant* ret)
+ internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, godot_variant** args, uint argc,
+ godot_variant* ret)
{
// TODO: Optimize
var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target;
var managedArgs = new object[argc];
var parameterInfos = @delegate.Method.GetParameters();
-
var paramsLength = parameterInfos.Length;
if (argc != paramsLength)
@@ -260,7 +256,8 @@ namespace Godot
}
}
- private static bool TryDeserializeDelegateWithGCHandle(Collections.Array serializedData, out IntPtr delegateGCHandle)
+ private static bool TryDeserializeDelegateWithGCHandle(Collections.Array serializedData,
+ out IntPtr delegateGCHandle)
{
bool res = TryDeserializeDelegate(serializedData, out Delegate @delegate);
delegateGCHandle = GCHandle.ToIntPtr(GCHandle.Alloc(@delegate));
@@ -368,7 +365,8 @@ namespace Godot
int valueBufferLength = reader.ReadInt32();
byte[] valueBuffer = reader.ReadBytes(valueBufferLength);
- FieldInfo fieldInfo = targetType.GetField(name, BindingFlags.Instance | BindingFlags.Public);
+ FieldInfo fieldInfo =
+ targetType.GetField(name, BindingFlags.Instance | BindingFlags.Public);
fieldInfo?.SetValue(recreatedTarget, GD.Bytes2Var(valueBuffer));
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index 932ee33fe3..8bc33837e6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -15,7 +15,7 @@ namespace Godot.Collections
IDictionary,
IDisposable
{
- internal godot_dictionary NativeValue;
+ public godot_dictionary NativeValue;
/// <summary>
/// Constructs a new empty <see cref="Dictionary"/>.
@@ -319,7 +319,7 @@ namespace Godot.Collections
{
using godot_string str = default;
NativeFuncs.godotsharp_dictionary_to_string(ref NativeValue, &str);
- return Marshaling.mono_string_from_godot(&str);
+ return Marshaling.mono_string_from_godot(str);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs
index 7922f38ac5..b939da8778 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs
@@ -1,4 +1,4 @@
-using System;
+using System.Reflection;
using System.Runtime.CompilerServices;
using Godot.Collections;
using Godot.NativeInterop;
@@ -11,14 +11,64 @@ namespace Godot
/// Returns a list of all nodes assigned to the given <paramref name="group"/>.
/// </summary>
/// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
- public Array<T> GetNodesInGroup<T>(StringName group) where T : class
+ public unsafe Array<T> GetNodesInGroup<T>(StringName group) where T : class
{
- godot_array array;
- godot_icall_SceneTree_get_nodes_in_group_Generic(GetPtr(this), ref group.NativeValue, typeof(T), out array);
- return Array<T>.CreateTakingOwnershipOfDisposableValue(array);
+ var array = GetNodesInGroup(group);
+
+ if (array.Count == 0)
+ return new Array<T>(array);
+
+ var typeOfT = typeof(T);
+ bool nativeBase = InternalIsClassNativeBase(typeOfT);
+
+ if (nativeBase)
+ {
+ // Native type
+ var field = typeOfT.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.Public | BindingFlags.NonPublic);
+
+ var nativeName = (StringName)field!.GetValue(null);
+ godot_string_name nativeNameAux = nativeName.NativeValue;
+ godot_array inputAux = array.NativeValue;
+ godot_array filteredArray;
+ godotsharp_array_filter_godot_objects_by_native(&nativeNameAux, &inputAux, &filteredArray);
+ return Array<T>.CreateTakingOwnershipOfDisposableValue(filteredArray);
+ }
+ else
+ {
+ // Custom derived type
+ godot_array inputAux = array.NativeValue;
+ godot_array filteredArray;
+ godotsharp_array_filter_godot_objects_by_non_native(&inputAux, &filteredArray);
+
+ var filteredArrayWrapped = Array.CreateTakingOwnershipOfDisposableValue(filteredArray);
+
+ // Re-use first array as its size is the same or greater than the filtered one
+ var resWrapped = new Array<T>(array);
+
+ int j = 0;
+ for (int i = 0; i < filteredArrayWrapped.Count; i++)
+ {
+ if (filteredArrayWrapped[i] is T t)
+ {
+ resWrapped[j] = t;
+ j++;
+ }
+ }
+
+ // Remove trailing elements, since this was re-used
+ resWrapped.Resize(j);
+
+ return resWrapped;
+ }
}
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_SceneTree_get_nodes_in_group_Generic(IntPtr obj, ref godot_string_name group, Type elemType, out godot_array dest);
+ internal extern unsafe void godotsharp_array_filter_godot_objects_by_native(godot_string_name* p_native_name,
+ godot_array* p_input, godot_array* r_output);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern unsafe void godotsharp_array_filter_godot_objects_by_non_native(godot_array* p_input,
+ godot_array* r_output);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
index 9d237b8d93..f428100ff7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -525,7 +525,7 @@ namespace Godot
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);
+ return Marshaling.mono_string_from_godot(ret);
}
/// <summary>
@@ -588,7 +588,7 @@ namespace Godot
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);
+ return Marshaling.mono_string_from_godot(ret);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs
index 9ccac1faaf..78a9d0fe9d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs
@@ -17,10 +17,7 @@ namespace Godot
public override void Fail(string message, string detailMessage)
{
GD.PrintErr("Assertion failed: ", message);
- if (detailMessage != null)
- {
- GD.PrintErr(" Details: ", detailMessage);
- }
+ GD.PrintErr(" Details: ", detailMessage);
try
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
index 865863cd3e..d8931f8348 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
@@ -13,7 +13,7 @@ namespace Godot.NativeInterop
{
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_bool
+ public struct godot_bool
{
public byte _value;
@@ -25,7 +25,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_ref : IDisposable
+ public struct godot_ref : IDisposable
{
internal IntPtr _reference;
@@ -41,7 +41,7 @@ namespace Godot.NativeInterop
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
- internal enum godot_variant_call_error_error
+ public enum godot_variant_call_error_error
{
GODOT_CALL_ERROR_CALL_OK = 0,
GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD,
@@ -53,16 +53,16 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_variant_call_error
+ public struct godot_variant_call_error
{
- godot_variant_call_error_error error;
- int argument;
- int expected;
+ public godot_variant_call_error_error error;
+ public int argument;
+ public int expected;
}
[StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
- internal struct godot_variant : IDisposable
+ public struct godot_variant : IDisposable
{
// Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits.
[FieldOffset(0)] private int _typeField;
@@ -162,7 +162,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_string : IDisposable
+ public struct godot_string : IDisposable
{
internal IntPtr _ptr;
@@ -180,7 +180,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_string_name : IDisposable
+ public struct godot_string_name : IDisposable
{
internal IntPtr _data;
@@ -201,7 +201,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_node_path : IDisposable
+ public struct godot_node_path : IDisposable
{
internal IntPtr _data;
@@ -222,7 +222,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
- internal struct godot_signal : IDisposable
+ public struct godot_signal : IDisposable
{
[FieldOffset(0)] public godot_string_name _name;
@@ -241,7 +241,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Explicit)]
// ReSharper disable once InconsistentNaming
- internal struct godot_callable : IDisposable
+ public struct godot_callable : IDisposable
{
[FieldOffset(0)] public godot_string_name _method;
@@ -265,7 +265,7 @@ namespace Godot.NativeInterop
// be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine).
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_array : IDisposable
+ public struct godot_array : IDisposable
{
internal unsafe ArrayPrivate* _p;
@@ -304,7 +304,7 @@ namespace Godot.NativeInterop
// be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine).
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_dictionary : IDisposable
+ public struct godot_dictionary : IDisposable
{
internal IntPtr _p;
@@ -319,7 +319,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_packed_byte_array : IDisposable
+ public struct godot_packed_byte_array : IDisposable
{
internal IntPtr _writeProxy;
internal unsafe byte* _ptr;
@@ -337,7 +337,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_packed_int32_array : IDisposable
+ public struct godot_packed_int32_array : IDisposable
{
internal IntPtr _writeProxy;
internal unsafe int* _ptr;
@@ -355,7 +355,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_packed_int64_array : IDisposable
+ public struct godot_packed_int64_array : IDisposable
{
internal IntPtr _writeProxy;
internal unsafe long* _ptr;
@@ -373,7 +373,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_packed_float32_array : IDisposable
+ public struct godot_packed_float32_array : IDisposable
{
internal IntPtr _writeProxy;
internal unsafe float* _ptr;
@@ -391,7 +391,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_packed_float64_array : IDisposable
+ public struct godot_packed_float64_array : IDisposable
{
internal IntPtr _writeProxy;
internal unsafe double* _ptr;
@@ -409,7 +409,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_packed_string_array : IDisposable
+ public struct godot_packed_string_array : IDisposable
{
internal IntPtr _writeProxy;
internal unsafe godot_string* _ptr;
@@ -427,7 +427,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_packed_vector2_array : IDisposable
+ public struct godot_packed_vector2_array : IDisposable
{
internal IntPtr _writeProxy;
internal unsafe Vector2* _ptr;
@@ -445,7 +445,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_packed_vector3_array : IDisposable
+ public struct godot_packed_vector3_array : IDisposable
{
internal IntPtr _writeProxy;
internal unsafe Vector3* _ptr;
@@ -463,7 +463,7 @@ namespace Godot.NativeInterop
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
- internal struct godot_packed_color_array : IDisposable
+ public struct godot_packed_color_array : IDisposable
{
internal IntPtr _writeProxy;
internal unsafe Color* _ptr;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
index 08d49bb937..5d53006140 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
@@ -1,5 +1,9 @@
using System;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Godot.Bridge;
+
+// ReSharper disable InconsistentNaming
namespace Godot.NativeInterop
{
@@ -7,21 +11,105 @@ namespace Godot.NativeInterop
{
public static Object UnmanagedGetManaged(IntPtr unmanaged)
{
- // TODO: Move to C#
- return internal_unmanaged_get_managed(unmanaged);
+ // The native pointer may be null
+ if (unmanaged == IntPtr.Zero)
+ return null;
+
+ IntPtr gcHandlePtr;
+ bool has_cs_script_instance = false;
+
+ // First try to get the tied managed instance from a CSharpInstance script instance
+
+ unsafe
+ {
+ gcHandlePtr = unmanaged_get_script_instance_managed(unmanaged, &has_cs_script_instance);
+ }
+
+ if (gcHandlePtr != IntPtr.Zero)
+ return (Object)GCHandle.FromIntPtr(gcHandlePtr).Target;
+
+ // Otherwise, if the object has a CSharpInstance script instance, return null
+
+ if (has_cs_script_instance)
+ return null;
+
+ // If it doesn't have a CSharpInstance script instance, try with native instance bindings
+
+ gcHandlePtr = unmanaged_get_instance_binding_managed(unmanaged);
+
+ object target = gcHandlePtr != IntPtr.Zero ? GCHandle.FromIntPtr(gcHandlePtr).Target : null;
+
+ if (target != null)
+ return (Object)target;
+
+ // If the native instance binding GC handle target was collected, create a new one
+
+ gcHandlePtr = unmanaged_instance_binding_create_managed(unmanaged, gcHandlePtr);
+
+ return gcHandlePtr != IntPtr.Zero ? (Object)GCHandle.FromIntPtr(gcHandlePtr).Target : null;
}
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern Object internal_unmanaged_get_managed(IntPtr unmanaged);
+ private static extern unsafe IntPtr unmanaged_get_script_instance_managed(IntPtr p_unmanaged,
+ bool* r_has_cs_script_instance);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern IntPtr unmanaged_get_instance_binding_managed(IntPtr p_unmanaged);
- public static void TieManagedToUnmanaged(Object managed, IntPtr unmanaged)
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern IntPtr unmanaged_instance_binding_create_managed(IntPtr p_unmanaged,
+ IntPtr oldGCHandlePtr);
+
+ public static void TieManagedToUnmanaged(Object managed, IntPtr unmanaged,
+ StringName nativeName, bool refCounted, Type type, Type nativeType)
{
- // TODO: Move to C#
- internal_tie_managed_to_unmanaged(managed, unmanaged);
+ var gcHandle = GCHandle.Alloc(managed, refCounted ? GCHandleType.Weak : GCHandleType.Normal);
+
+ if (type == nativeType)
+ {
+ unsafe
+ {
+ godot_string_name nativeNameAux = nativeName.NativeValue;
+ internal_tie_native_managed_to_unmanaged(GCHandle.ToIntPtr(gcHandle), unmanaged,
+ &nativeNameAux, refCounted);
+ }
+ }
+ else
+ {
+ IntPtr scriptPtr = internal_new_csharp_script();
+
+ ScriptManagerBridge.AddScriptBridgeWithType(scriptPtr, type);
+
+ // IMPORTANT: This must be called after AddScriptWithTypeBridge
+ internal_tie_user_managed_to_unmanaged(GCHandle.ToIntPtr(gcHandle), unmanaged,
+ scriptPtr, refCounted);
+ }
}
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_tie_managed_to_unmanaged(Object managed, IntPtr unmanaged);
+ private static extern unsafe void internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr,
+ IntPtr unmanaged, godot_string_name* nativeName, bool refCounted);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr,
+ IntPtr unmanaged, IntPtr scriptPtr, bool refCounted);
+
+ public static void TieManagedToUnmanagedWithPreSetup(Object managed, IntPtr unmanaged,
+ Type type, Type nativeType)
+ {
+ if (type == nativeType)
+ return;
+
+ var strongGCHandle = GCHandle.Alloc(managed, GCHandleType.Normal);
+ internal_tie_managed_to_unmanaged_with_pre_setup(GCHandle.ToIntPtr(strongGCHandle), unmanaged);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern void internal_tie_managed_to_unmanaged_with_pre_setup(
+ IntPtr gcHandleIntPtr, IntPtr unmanaged);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern IntPtr internal_new_csharp_script();
public static unsafe Object EngineGetSingleton(string name)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
index e0819b2857..eae644af85 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
@@ -10,14 +10,8 @@ namespace Godot.NativeInterop
{
// We want to use full name qualifiers here even if redundant for clarity
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
- internal static class Marshaling
+ public static class Marshaling
{
- public static unsafe void SetFieldValue(FieldInfo fieldInfo, object obj, godot_variant* value)
- {
- var valueObj = variant_to_mono_object_of_type(value, fieldInfo.FieldType);
- fieldInfo.SetValue(obj, valueObj);
- }
-
public static Variant.Type managed_to_variant_type(Type type, out bool r_nil_is_variant)
{
r_nil_is_variant = false;
@@ -242,10 +236,6 @@ namespace Godot.NativeInterop
return mono_object_to_variant_impl(p_obj);
}
- // TODO: Only called from C++. Remove once no longer needed.
- private static unsafe void mono_object_to_variant_out(object p_obj, bool p_fail_with_err, godot_variant* r_ret)
- => *r_ret = mono_object_to_variant_impl(p_obj, p_fail_with_err);
-
private static unsafe godot_variant mono_object_to_variant_impl(object p_obj, bool p_fail_with_err = true)
{
if (p_obj == null)
@@ -457,7 +447,7 @@ namespace Godot.NativeInterop
// TODO: Validate element type is compatible with Variant
#if NET
var nativeGodotArray =
- mono_array_to_Array(System.Runtime.InteropServices.CollectionsMarshal.AsSpan((dynamic)p_obj));
+ (godot_array)mono_array_to_Array(System.Runtime.InteropServices.CollectionsMarshal.AsSpan((dynamic)p_obj));
#else
// With .NET Standard we need a package reference for Microsoft.CSharp in order to
// use dynamic, so we have this workaround for now until we switch to .NET 5/6.
@@ -500,12 +490,12 @@ namespace Godot.NativeInterop
case Variant.Type.String:
{
// We avoid the internal call if the stored type is the same we want.
- return mono_string_from_godot(&(*p_var)._data._m_string);
+ return mono_string_from_godot((*p_var)._data._m_string);
}
default:
{
using godot_string godotString = NativeFuncs.godotsharp_variant_as_string(p_var);
- return mono_string_from_godot(&godotString);
+ return mono_string_from_godot(godotString);
}
}
}
@@ -877,7 +867,7 @@ namespace Godot.NativeInterop
#endif
}
case Variant.Type.String:
- return mono_string_from_godot(&(*p_var)._data._m_string);
+ return mono_string_from_godot((*p_var)._data._m_string);
case Variant.Type.Vector2:
return (*p_var)._data._m_vector2;
case Variant.Type.Vector2i:
@@ -1007,14 +997,14 @@ namespace Godot.NativeInterop
}
}
- public static unsafe string mono_string_from_godot(godot_string* p_string)
+ public static unsafe string mono_string_from_godot(in godot_string p_string)
{
- if ((*p_string)._ptr == IntPtr.Zero)
+ if (p_string._ptr == IntPtr.Zero)
return string.Empty;
const int sizeOfChar32 = 4;
- byte* bytes = (byte*)(*p_string)._ptr;
- int size = (*p_string).Size;
+ byte* bytes = (byte*)p_string._ptr;
+ int size = p_string.Size;
if (size == 0)
return string.Empty;
size -= 1; // zero at the end
@@ -1283,7 +1273,7 @@ namespace Godot.NativeInterop
int size = (*p_array).Size;
var array = new string[size];
for (int i = 0; i < size; i++)
- array[i] = mono_string_from_godot(&buffer[i]);
+ array[i] = mono_string_from_godot(buffer[i]);
return array;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
index adbf5eb9b6..73ac837fe1 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -10,7 +10,7 @@ namespace Godot.NativeInterop
// The attribute is not available with .NET Core and it's not needed there.
[System.Security.SuppressUnmanagedCodeSecurity]
#endif
- internal static unsafe partial class NativeFuncs
+ public static unsafe partial class NativeFuncs
{
private const string GodotDllName = "__Internal";
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
index 6001b3a0de..089883c7e8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
@@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
namespace Godot.NativeInterop
{
- internal static unsafe partial class NativeFuncs
+ public static unsafe partial class NativeFuncs
{
public static godot_string_name godotsharp_string_name_new_copy(godot_string_name* src)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
index 67f9e23893..91ba864687 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
@@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
namespace Godot.NativeInterop
{
- internal static class VariantUtils
+ public static class VariantUtils
{
public static godot_variant CreateFromRID(RID from)
=> new() {_type = Variant.Type.Rid, _data = {_m_rid = from}};
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
index 541364b281..824f29558f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
@@ -42,7 +42,7 @@ namespace Godot
/// </example>
public sealed class NodePath : IDisposable
{
- internal godot_node_path NativeValue;
+ public godot_node_path NativeValue;
~NodePath()
{
@@ -140,7 +140,7 @@ namespace Godot
godot_node_path src = NativeValue;
NativeFuncs.godotsharp_node_path_as_string(&dest, &src);
using (dest)
- return Marshaling.mono_string_from_godot(&dest);
+ return Marshaling.mono_string_from_godot(dest);
}
/// <summary>
@@ -179,7 +179,7 @@ namespace Godot
{
using godot_string names = default;
NativeFuncs.godotsharp_node_path_get_concatenated_names(ref NativeValue, &names);
- return Marshaling.mono_string_from_godot(&names);
+ return Marshaling.mono_string_from_godot(names);
}
/// <summary>
@@ -197,7 +197,7 @@ namespace Godot
{
using godot_string subNames = default;
NativeFuncs.godotsharp_node_path_get_concatenated_subnames(ref NativeValue, &subNames);
- return Marshaling.mono_string_from_godot(&subNames);
+ return Marshaling.mono_string_from_godot(subNames);
}
/// <summary>
@@ -217,7 +217,7 @@ namespace Godot
{
using godot_string name = default;
NativeFuncs.godotsharp_node_path_get_name(ref NativeValue, idx, &name);
- return Marshaling.mono_string_from_godot(&name);
+ return Marshaling.mono_string_from_godot(name);
}
/// <summary>
@@ -240,7 +240,7 @@ namespace Godot
{
using godot_string subName = default;
NativeFuncs.godotsharp_node_path_get_subname(ref NativeValue, idx, &subName);
- return Marshaling.mono_string_from_godot(&subName);
+ return Marshaling.mono_string_from_godot(subName);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index 7bbaef62fa..763483a11f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -1,4 +1,6 @@
using System;
+using System.Linq;
+using System.Reflection;
using System.Runtime.CompilerServices;
using Godot.NativeInterop;
@@ -7,6 +9,7 @@ namespace Godot
public partial class Object : IDisposable
{
private bool _disposed = false;
+ private Type _cachedType = typeof(Object);
internal IntPtr NativePtr;
internal bool MemoryOwn;
@@ -21,12 +24,18 @@ namespace Godot
#if NET
unsafe
{
- ptr = NativeCtor();
+ NativePtr = NativeCtor();
}
#else
NativePtr = _gd__invoke_class_constructor(NativeCtor);
#endif
- NativeInterop.InteropUtils.TieManagedToUnmanaged(this, NativePtr);
+ InteropUtils.TieManagedToUnmanaged(this, NativePtr,
+ NativeName, refCounted: false, GetType(), _cachedType);
+ }
+ else
+ {
+ InteropUtils.TieManagedToUnmanagedWithPreSetup(this, NativePtr,
+ GetType(), _cachedType);
}
_InitializeGodotScriptInstanceInternals();
@@ -34,12 +43,32 @@ namespace Godot
internal void _InitializeGodotScriptInstanceInternals()
{
- godot_icall_Object_ConnectEventSignals(NativePtr);
+ // Performance is not critical here as this will be replaced with source generators.
+ Type top = GetType();
+ Type native = InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ foreach (var eventSignal in top.GetEvents(
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public)
+ .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any()))
+ {
+ unsafe
+ {
+ using var eventSignalName = new StringName(eventSignal.Name);
+ godot_string_name eventSignalNameAux = eventSignalName.NativeValue;
+ godot_icall_Object_ConnectEventSignal(NativePtr, &eventSignalNameAux);
+ }
+ }
+
+ top = top.BaseType;
+ }
}
internal Object(bool memoryOwn)
{
- this.MemoryOwn = memoryOwn;
+ MemoryOwn = memoryOwn;
}
/// <summary>
@@ -85,11 +114,11 @@ namespace Godot
if (MemoryOwn)
{
MemoryOwn = false;
- godot_icall_RefCounted_Disposed(this, NativePtr, !disposing);
+ godot_icall_RefCounted_Disposed(NativePtr, !disposing);
}
else
{
- godot_icall_Object_Disposed(this, NativePtr);
+ godot_icall_Object_Disposed(NativePtr);
}
this.NativePtr = IntPtr.Zero;
@@ -106,7 +135,7 @@ namespace Godot
{
using godot_string str = default;
NativeFuncs.godotsharp_object_to_string(GetPtr(this), &str);
- return Marshaling.mono_string_from_godot(&str);
+ return Marshaling.mono_string_from_godot(str);
}
/// <summary>
@@ -141,13 +170,219 @@ namespace Godot
return new SignalAwaiter(source, signal, this);
}
+ internal static Type InternalGetClassNativeBase(Type t)
+ {
+ do
+ {
+ var assemblyName = t.Assembly.GetName();
+
+ if (assemblyName.Name == "GodotSharp")
+ return t;
+
+ if (assemblyName.Name == "GodotSharpEditor")
+ return t;
+ } while ((t = t.BaseType) != null);
+
+ return null;
+ }
+
+ internal static bool InternalIsClassNativeBase(Type t)
+ {
+ var assemblyName = t.Assembly.GetName();
+ return assemblyName.Name == "GodotSharp" || assemblyName.Name == "GodotSharpEditor";
+ }
+
+ internal unsafe bool InternalGodotScriptCallViaReflection(string method, godot_variant** args, int argCount,
+ out godot_variant ret)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ Type top = GetType();
+ Type native = InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ var methodInfo = top.GetMethod(method,
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (methodInfo != null)
+ {
+ var parameters = methodInfo.GetParameters();
+ int paramCount = parameters.Length;
+
+ if (argCount == paramCount)
+ {
+ object[] invokeParams = new object[paramCount];
+
+ for (int i = 0; i < paramCount; i++)
+ {
+ invokeParams[i] = Marshaling.variant_to_mono_object_of_type(
+ args[i], parameters[i].ParameterType);
+ }
+
+ object retObj = methodInfo.Invoke(this, invokeParams);
+
+ ret = Marshaling.mono_object_to_variant(retObj);
+ return true;
+ }
+ }
+
+ top = top.BaseType;
+ }
+
+ ret = default;
+ return false;
+ }
+
+ internal unsafe bool InternalGodotScriptSetFieldOrPropViaReflection(string name, godot_variant* value)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ Type top = GetType();
+ Type native = InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ var fieldInfo = top.GetField(name,
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (fieldInfo != null)
+ {
+ object valueManaged = Marshaling.variant_to_mono_object_of_type(value, fieldInfo.FieldType);
+ fieldInfo.SetValue(this, valueManaged);
+
+ return true;
+ }
+
+ var propertyInfo = top.GetProperty(name,
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (propertyInfo != null)
+ {
+ object valueManaged = Marshaling.variant_to_mono_object_of_type(value, propertyInfo.PropertyType);
+ propertyInfo.SetValue(this, valueManaged);
+
+ return true;
+ }
+
+ top = top.BaseType;
+ }
+
+ return false;
+ }
+
+ internal bool InternalGodotScriptGetFieldOrPropViaReflection(string name, out godot_variant value)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ Type top = GetType();
+ Type native = InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ var fieldInfo = top.GetField(name,
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (fieldInfo != null)
+ {
+ object valueManaged = fieldInfo.GetValue(this);
+ value = Marshaling.mono_object_to_variant(valueManaged);
+ return true;
+ }
+
+ var propertyInfo = top.GetProperty(name,
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (propertyInfo != null)
+ {
+ object valueManaged = propertyInfo.GetValue(this);
+ value = Marshaling.mono_object_to_variant(valueManaged);
+ return true;
+ }
+
+ top = top.BaseType;
+ }
+
+ value = default;
+ return false;
+ }
+
+ internal unsafe void InternalRaiseEventSignal(godot_string_name* eventSignalName, godot_variant** args,
+ int argc)
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+
+ using var stringName = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(eventSignalName));
+ string eventSignalNameStr = stringName.ToString();
+
+ Type top = GetType();
+ Type native = InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ var foundEventSignals = top.GetEvents(
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public)
+ .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
+ .Select(ev => ev.Name);
+
+ var fields = top.GetFields(
+ BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ var eventSignalField = fields
+ .Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
+ .Where(f => foundEventSignals.Contains(f.Name))
+ .FirstOrDefault(f => f.Name == eventSignalNameStr);
+
+ if (eventSignalField != null)
+ {
+ var @delegate = (Delegate)eventSignalField.GetValue(this);
+
+ if (@delegate == null)
+ continue;
+
+ var delegateType = eventSignalField.FieldType;
+
+ var invokeMethod = delegateType.GetMethod("Invoke");
+
+ if (invokeMethod == null)
+ throw new MissingMethodException(delegateType.FullName, "Invoke");
+
+ var parameterInfos = invokeMethod.GetParameters();
+ var paramsLength = parameterInfos.Length;
+
+ if (argc != paramsLength)
+ {
+ throw new InvalidOperationException(
+ $"The event delegate expects {paramsLength} arguments, but received {argc}.");
+ }
+
+ var managedArgs = new object[argc];
+
+ for (uint i = 0; i < argc; i++)
+ {
+ managedArgs[i] = Marshaling.variant_to_mono_object_of_type(
+ args[i], parameterInfos[i].ParameterType);
+ }
+
+ invokeMethod.Invoke(@delegate, managedArgs);
+ return;
+ }
+
+ top = top.BaseType;
+ }
+ }
+
internal static unsafe IntPtr ClassDB_get_method(StringName type, string method)
{
IntPtr methodBind;
fixed (char* methodChars = method)
{
- methodBind = NativeInterop.NativeFuncs
- .godotsharp_method_bind_get_method(ref type.NativeValue, methodChars);
+ methodBind = NativeFuncs.godotsharp_method_bind_get_method(ref type.NativeValue, methodChars);
}
if (methodBind == IntPtr.Zero)
@@ -157,11 +392,10 @@ namespace Godot
}
#if NET
- internal static unsafe delegate* unmanaged<IntPtr> _gd__ClassDB_get_constructor(StringName type)
+ internal static unsafe delegate* unmanaged<IntPtr> ClassDB_get_constructor(StringName type)
{
// for some reason the '??' operator doesn't support 'delegate*'
- var nativeConstructor = NativeInterop.NativeFuncs
- .godotsharp_get_class_constructor(ref type.NativeValue);
+ var nativeConstructor = NativeFuncs.godotsharp_get_class_constructor(ref type.NativeValue);
if (nativeConstructor == null)
throw new NativeConstructorNotFoundException(type);
@@ -172,8 +406,7 @@ namespace Godot
internal static IntPtr ClassDB_get_constructor(StringName type)
{
// for some reason the '??' operator doesn't support 'delegate*'
- var nativeConstructor = NativeInterop.NativeFuncs
- .godotsharp_get_class_constructor(ref type.NativeValue);
+ var nativeConstructor = NativeFuncs.godotsharp_get_class_constructor(ref type.NativeValue);
if (nativeConstructor == IntPtr.Zero)
throw new NativeConstructorNotFoundException(type);
@@ -182,16 +415,17 @@ namespace Godot
}
internal static IntPtr _gd__invoke_class_constructor(IntPtr ctorFuncPtr)
- => NativeInterop.NativeFuncs.godotsharp_invoke_class_constructor(ctorFuncPtr);
+ => NativeFuncs.godotsharp_invoke_class_constructor(ctorFuncPtr);
#endif
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Object_Disposed(Object obj, IntPtr ptr);
+ internal static extern void godot_icall_Object_Disposed(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_RefCounted_Disposed(Object obj, IntPtr ptr, bool isFinalizer);
+ internal static extern void godot_icall_RefCounted_Disposed(IntPtr ptr, bool isFinalizer);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Object_ConnectEventSignals(IntPtr obj);
+ internal static extern unsafe void godot_icall_Object_ConnectEventSignal(IntPtr obj,
+ godot_string_name* eventSignal);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/ScriptManager.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/ScriptManager.cs
deleted file mode 100644
index e92688f5bb..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/ScriptManager.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace Godot
-{
- internal class ScriptManager
- {
- internal static void FrameCallback()
- {
- Dispatcher.DefaultGodotTaskScheduler?.Activate();
- }
- }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
index e485207fb4..fd6636e410 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using Godot.NativeInterop;
namespace Godot
@@ -12,11 +13,13 @@ namespace Godot
public SignalAwaiter(Object source, StringName signal, Object target)
{
- godot_icall_SignalAwaiter_connect(Object.GetPtr(source), ref signal.NativeValue, Object.GetPtr(target), this);
+ godot_icall_SignalAwaiter_connect(Object.GetPtr(source), ref signal.NativeValue,
+ Object.GetPtr(target), GCHandle.ToIntPtr(GCHandle.Alloc(this)));
}
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern Error godot_icall_SignalAwaiter_connect(IntPtr source, ref godot_string_name signal, IntPtr target, SignalAwaiter awaiter);
+ internal static extern Error godot_icall_SignalAwaiter_connect(IntPtr source, ref godot_string_name signal,
+ IntPtr target, IntPtr awaiterHandlePtr);
public bool IsCompleted => _completed;
@@ -29,11 +32,30 @@ namespace Godot
public IAwaiter<object[]> GetAwaiter() => this;
- internal void SignalCallback(object[] args)
+ internal static unsafe void SignalCallback(IntPtr awaiterGCHandlePtr,
+ godot_variant** args, int argCount,
+ bool* r_awaiterIsNull)
{
- _completed = true;
- _result = args;
- _action?.Invoke();
+ var awaiter = (SignalAwaiter)GCHandle.FromIntPtr(awaiterGCHandlePtr).Target;
+
+ if (awaiter == null)
+ {
+ *r_awaiterIsNull = true;
+ return;
+ }
+
+ *r_awaiterIsNull = false;
+
+ awaiter._completed = true;
+
+ object[] signalArgs = new object[argCount];
+
+ for (int i = 0; i < argCount; i++)
+ signalArgs[i] = Marshaling.variant_to_mono_object(args[i]);
+
+ awaiter._result = signalArgs;
+
+ awaiter._action?.Invoke();
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index 6c3d673fdc..dfdef81f9e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -1096,7 +1096,7 @@ namespace Godot
using godot_string instanceStr = Marshaling.mono_string_to_godot(instance);
using godot_string md5Text = default;
NativeFuncs.godotsharp_string_md5_text(&instanceStr, &md5Text);
- return Marshaling.mono_string_from_godot(&md5Text);
+ return Marshaling.mono_string_from_godot(md5Text);
}
/// <summary>
@@ -1345,7 +1345,7 @@ namespace Godot
using godot_string instanceStr = Marshaling.mono_string_to_godot(instance);
using godot_string sha256Text = default;
NativeFuncs.godotsharp_string_sha256_text(&instanceStr, &sha256Text);
- return Marshaling.mono_string_from_godot(&sha256Text);
+ return Marshaling.mono_string_from_godot(sha256Text);
}
/// <summary>
@@ -1401,7 +1401,7 @@ namespace Godot
using godot_string instanceStr = Marshaling.mono_string_to_godot(instance);
using godot_string simplifiedPath = default;
NativeFuncs.godotsharp_string_simplify_path(&instanceStr, &simplifiedPath);
- return Marshaling.mono_string_from_godot(&simplifiedPath);
+ return Marshaling.mono_string_from_godot(simplifiedPath);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
index 40d282eab4..84b0ab623c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
@@ -13,7 +13,7 @@ namespace Godot
/// </summary>
public sealed class StringName : IDisposable
{
- internal godot_string_name NativeValue;
+ public godot_string_name NativeValue;
~StringName()
{
@@ -86,7 +86,7 @@ namespace Godot
godot_string_name src = NativeValue;
NativeFuncs.godotsharp_string_name_as_string(&dest, &src);
using (dest)
- return Marshaling.mono_string_from_godot(&dest);
+ return Marshaling.mono_string_from_godot(dest);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 36faf92144..6a529de99b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -32,6 +32,9 @@
<Compile Include="Core\Attributes\SignalAttribute.cs" />
<Compile Include="Core\Attributes\ToolAttribute.cs" />
<Compile Include="Core\Basis.cs" />
+ <Compile Include="Core\Bridge\CSharpInstanceBridge.cs" />
+ <Compile Include="Core\Bridge\GCHandleBridge.cs" />
+ <Compile Include="Core\Bridge\ScriptManagerBridge.cs" />
<Compile Include="Core\Callable.cs" />
<Compile Include="Core\Color.cs" />
<Compile Include="Core\Colors.cs" />
@@ -71,7 +74,6 @@
<Compile Include="Core\NativeInterop\NativeFuncs.cs" />
<Compile Include="Core\NativeInterop\InteropStructs.cs" />
<Compile Include="Core\NativeInterop\Marshaling.cs" />
- <Compile Include="Core\ScriptManager.cs" />
<Compile Include="Core\SignalInfo.cs" />
<Compile Include="Core\SignalAwaiter.cs" />
<Compile Include="Core\StringExtensions.cs" />
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index d56b70e739..dbf2ae84aa 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -34,13 +34,11 @@
#include "../csharp_script.h"
#include "../mono_gd/gd_mono_cache.h"
-#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_internals.h"
-#include "../mono_gd/gd_mono_marshal.h"
#include "../mono_gd/gd_mono_utils.h"
#include "../signal_awaiter_utils.h"
-void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
+void godot_icall_Object_Disposed(Object *p_ptr) {
#ifdef DEBUG_ENABLED
CRASH_COND(p_ptr == nullptr);
#endif
@@ -49,7 +47,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
if (cs_instance) {
if (!cs_instance->is_destructing_script_instance()) {
- cs_instance->mono_object_disposed(p_obj);
+ cs_instance->mono_object_disposed();
p_ptr->set_script_instance(nullptr);
}
return;
@@ -63,13 +61,14 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
if (script_binding.inited) {
MonoGCHandleData &gchandle = script_binding.gchandle;
if (!gchandle.is_released()) {
- CSharpLanguage::release_script_gchandle(p_obj, gchandle);
+ CSharpLanguage::release_script_gchandle(nullptr, gchandle);
+ script_binding.inited = false;
}
}
}
}
-void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) {
+void godot_icall_RefCounted_Disposed(Object *p_ptr, MonoBoolean p_is_finalizer) {
#ifdef DEBUG_ENABLED
CRASH_COND(p_ptr == nullptr);
// This is only called with RefCounted derived classes
@@ -85,7 +84,7 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole
bool delete_owner;
bool remove_script_instance;
- cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, delete_owner, remove_script_instance);
+ cs_instance->mono_object_disposed_baseref(p_is_finalizer, delete_owner, remove_script_instance);
if (delete_owner) {
memdelete(rc);
@@ -110,28 +109,29 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole
if (script_binding.inited) {
MonoGCHandleData &gchandle = script_binding.gchandle;
if (!gchandle.is_released()) {
- CSharpLanguage::release_script_gchandle(p_obj, gchandle);
+ CSharpLanguage::release_script_gchandle(nullptr, gchandle);
+ script_binding.inited = false;
}
}
}
}
}
-void godot_icall_Object_ConnectEventSignals(Object *p_ptr) {
+void godot_icall_Object_ConnectEventSignal(Object *p_ptr, const StringName *p_event_signal) {
CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
if (csharp_instance) {
- csharp_instance->connect_event_signals();
+ csharp_instance->connect_event_signal(*p_event_signal);
}
}
-int32_t godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter) {
+int32_t godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr) {
StringName signal = p_signal ? *p_signal : StringName();
- return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
+ return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter_handle_ptr);
}
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_ConnectEventSignal", godot_icall_Object_ConnectEventSignal);
GDMonoUtils::add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", godot_icall_SignalAwaiter_connect);
}
diff --git a/modules/mono/glue/placeholder_glue.cpp b/modules/mono/glue/placeholder_glue.cpp
index edac231bb4..0dd904373e 100644
--- a/modules/mono/glue/placeholder_glue.cpp
+++ b/modules/mono/glue/placeholder_glue.cpp
@@ -33,24 +33,169 @@
#include "core/object/object.h"
+#include "../csharp_script.h"
+#include "../mono_gd/gd_mono_cache.h"
#include "../mono_gd/gd_mono_internals.h"
#include "../mono_gd/gd_mono_utils.h"
-MonoObject *godot_icall_InteropUtils_unmanaged_get_managed(Object *unmanaged) {
- return GDMonoUtils::unmanaged_get_managed(unmanaged);
+GCHandleIntPtr unmanaged_get_script_instance_managed(Object *p_unmanaged, bool *r_has_cs_script_instance) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+ CRASH_COND(!r_has_cs_script_instance);
+#endif
+
+ if (p_unmanaged->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_unmanaged->get_script_instance());
+
+ if (cs_instance) {
+ *r_has_cs_script_instance = true;
+ return cs_instance->get_gchandle_intptr();
+ }
+ }
+
+ *r_has_cs_script_instance = false;
+ return GCHandleIntPtr();
}
-void godot_icall_InteropUtils_tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
- GDMonoInternals::tie_managed_to_unmanaged(managed, unmanaged);
+GCHandleIntPtr unmanaged_get_instance_binding_managed(Object *p_unmanaged) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+#endif
+
+ void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
+ ERR_FAIL_NULL_V(data, GCHandleIntPtr());
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
+ ERR_FAIL_COND_V(!script_binding.inited, GCHandleIntPtr());
+
+ return script_binding.gchandle.get_intptr();
+}
+
+GCHandleIntPtr unmanaged_instance_binding_create_managed(Object *p_unmanaged, GCHandleIntPtr p_old_gchandle) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+#endif
+
+ void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
+ ERR_FAIL_NULL_V(data, GCHandleIntPtr());
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
+ ERR_FAIL_COND_V(!script_binding.inited, GCHandleIntPtr());
+
+ MonoGCHandleData &gchandle = script_binding.gchandle;
+
+ // TODO: Possible data race?
+ CRASH_COND(gchandle.get_intptr().value != p_old_gchandle.value);
+
+ CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
+ script_binding.inited = false;
+
+ // Create a new one
+
+#ifdef DEBUG_ENABLED
+ CRASH_COND(script_binding.type_name == StringName());
+#endif
+
+ bool parent_is_object_class = ClassDB::is_parent_class(p_unmanaged->get_class_name(), script_binding.type_name);
+ ERR_FAIL_COND_V_MSG(!parent_is_object_class, GCHandleIntPtr(),
+ "Type inherits from native type '" + script_binding.type_name + "', so it can't be instantiated in object of type: '" + p_unmanaged->get_class() + "'.");
+
+ MonoException *exc = nullptr;
+ GCHandleIntPtr strong_gchandle =
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectBinding
+ .invoke(&script_binding.type_name, p_unmanaged, &exc);
+
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ return GCHandleIntPtr();
+ }
+
+ ERR_FAIL_NULL_V(strong_gchandle.value, GCHandleIntPtr());
+
+ gchandle = MonoGCHandleData(strong_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
+ script_binding.inited = true;
+
+ // Tie managed to unmanaged
+ RefCounted *rc = Object::cast_to<RefCounted>(p_unmanaged);
+
+ if (rc) {
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
+ rc->reference();
+ CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
+ }
+
+ return gchandle.get_intptr();
+}
+
+void godot_icall_InteropUtils_tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, const StringName *p_native_name, bool p_ref_counted) {
+ CSharpLanguage::tie_native_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_native_name, p_ref_counted);
+}
+
+void godot_icall_InteropUtils_tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, CSharpScript *p_script, bool p_ref_counted) {
+ CSharpLanguage::tie_user_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_script, p_ref_counted);
+}
+
+void godot_icall_InteropUtils_tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged) {
+ CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(p_gchandle_intptr, p_unmanaged);
+}
+
+CSharpScript *godot_icall_InteropUtils_internal_new_csharp_script() {
+ CSharpScript *script = memnew(CSharpScript);
+ CRASH_COND(!script);
+ return script;
+}
+
+void godotsharp_array_filter_godot_objects_by_native(StringName *p_native_name, const Array *p_input, Array *r_output) {
+ memnew_placement(r_output, Array);
+
+ for (int i = 0; i < p_input->size(); ++i) {
+ if (ClassDB::is_parent_class(((Object *)(*p_input)[i])->get_class(), *p_native_name)) {
+ r_output->push_back(p_input[i]);
+ }
+ }
+}
+
+void godotsharp_array_filter_godot_objects_by_non_native(const Array *p_input, Array *r_output) {
+ memnew_placement(r_output, Array);
+
+ for (int i = 0; i < p_input->size(); ++i) {
+ CSharpInstance *si = CAST_CSHARP_INSTANCE(((Object *)(*p_input)[i])->get_script_instance());
+
+ if (si != nullptr) {
+ r_output->push_back(p_input[i]);
+ }
+ }
}
void godot_register_placeholder_icalls() {
GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.InteropUtils::internal_unmanaged_get_managed",
- godot_icall_InteropUtils_unmanaged_get_managed);
+ "Godot.NativeInterop.InteropUtils::unmanaged_get_script_instance_managed",
+ unmanaged_get_script_instance_managed);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::unmanaged_get_instance_binding_managed",
+ unmanaged_get_instance_binding_managed);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::unmanaged_instance_binding_create_managed",
+ unmanaged_instance_binding_create_managed);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::internal_tie_native_managed_to_unmanaged",
+ godot_icall_InteropUtils_tie_native_managed_to_unmanaged);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::internal_tie_user_managed_to_unmanaged",
+ godot_icall_InteropUtils_tie_user_managed_to_unmanaged);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::internal_tie_managed_to_unmanaged_with_pre_setup",
+ godot_icall_InteropUtils_tie_managed_to_unmanaged_with_pre_setup);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.InteropUtils::internal_new_csharp_script",
+ godot_icall_InteropUtils_internal_new_csharp_script);
+ GDMonoUtils::add_internal_call(
+ "Godot.NativeInterop.SceneTree::godotsharp_array_filter_godot_objects_by_native",
+ godotsharp_array_filter_godot_objects_by_native);
GDMonoUtils::add_internal_call(
- "Godot.NativeInterop.InteropUtils::internal_tie_managed_to_unmanaged",
- godot_icall_InteropUtils_tie_managed_to_unmanaged);
+ "Godot.NativeInterop.SceneTree::godotsharp_array_filter_godot_objects_by_non_native",
+ godotsharp_array_filter_godot_objects_by_non_native);
}
#endif // GLUE_HEADER_H
diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp
index 2860386127..29d373e885 100644
--- a/modules/mono/glue/runtime_interop.cpp
+++ b/modules/mono/glue/runtime_interop.cpp
@@ -187,14 +187,14 @@ GD_PINVOKE_EXPORT void godotsharp_packed_string_array_add(PackedStringArray *r_d
r_dest->append(*p_element);
}
-GD_PINVOKE_EXPORT void godotsharp_callable_new_with_delegate(void *p_delegate_handle, Callable *r_callable) {
+GD_PINVOKE_EXPORT void godotsharp_callable_new_with_delegate(GCHandleIntPtr p_delegate_handle, Callable *r_callable) {
// TODO: Use pooling for ManagedCallable instances.
CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle));
memnew_placement(r_callable, Callable(managed_callable));
}
GD_PINVOKE_EXPORT bool godotsharp_callable_get_data_for_marshalling(const Callable *p_callable,
- void **r_delegate_handle, Object **r_object, StringName *r_name) {
+ GCHandleIntPtr *r_delegate_handle, Object **r_object, StringName *r_name) {
if (p_callable->is_custom()) {
CallableCustom *custom = p_callable->get_custom();
CallableCustom::CompareEqualFunc compare_equal_func = custom->get_compare_equal_func();
@@ -207,25 +207,25 @@ GD_PINVOKE_EXPORT bool godotsharp_callable_get_data_for_marshalling(const Callab
return true;
} else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) {
SignalAwaiterCallable *signal_awaiter_callable = static_cast<SignalAwaiterCallable *>(custom);
- *r_delegate_handle = nullptr;
+ *r_delegate_handle = GCHandleIntPtr();
*r_object = ObjectDB::get_instance(signal_awaiter_callable->get_object());
memnew_placement(r_name, StringName(signal_awaiter_callable->get_signal()));
return true;
} else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) {
EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom);
- *r_delegate_handle = nullptr;
+ *r_delegate_handle = GCHandleIntPtr();
*r_object = ObjectDB::get_instance(event_signal_callable->get_object());
memnew_placement(r_name, StringName(event_signal_callable->get_signal()));
return true;
}
// Some other CallableCustom. We only support ManagedCallable.
- *r_delegate_handle = nullptr;
+ *r_delegate_handle = GCHandleIntPtr();
*r_object = nullptr;
memnew_placement(r_name, StringName());
return false;
} else {
- *r_delegate_handle = nullptr;
+ *r_delegate_handle = GCHandleIntPtr();
*r_object = ObjectDB::get_instance(p_callable->get_object_id());
memnew_placement(r_name, StringName(p_callable->get_method()));
return true;
diff --git a/modules/mono/glue/scene_tree_glue.cpp b/modules/mono/glue/scene_tree_glue.cpp
deleted file mode 100644
index 55a46ad368..0000000000
--- a/modules/mono/glue/scene_tree_glue.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*************************************************************************/
-/* scene_tree_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/object/class_db.h"
-#include "core/string/string_name.h"
-#include "core/variant/array.h"
-#include "scene/main/node.h"
-#include "scene/main/scene_tree.h"
-
-#include "../csharp_script.h"
-#include "../mono_gd/gd_mono_marshal.h"
-#include "../mono_gd/gd_mono_utils.h"
-
-void godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringName *group, MonoReflectionType *refltype, Array *r_dest) {
- memnew_placement(r_dest, Array);
-
- List<Node *> nodes;
-
- // Retrieve all the nodes in the group
- ptr->get_nodes_in_group(*group, &nodes);
-
- // No need to bother if the group is empty
- if (!nodes.is_empty()) {
- MonoType *elem_type = mono_reflection_type_get_type(refltype);
- MonoClass *mono_class = mono_class_from_mono_type(elem_type);
- GDMonoClass *klass = GDMono::get_singleton()->get_class(mono_class);
-
- if (klass == GDMonoUtils::get_class_native_base(klass)) {
- // If we're trying to get native objects, just check the inheritance list
- StringName native_class_name = GDMonoUtils::get_native_godot_class_name(klass);
- for (int i = 0; i < nodes.size(); ++i) {
- if (ClassDB::is_parent_class(nodes[i]->get_class(), native_class_name)) {
- r_dest->push_back(nodes[i]);
- }
- }
- } else {
- // If we're trying to get csharpscript instances, get the mono object and compare the classes
- for (int i = 0; i < nodes.size(); ++i) {
- CSharpInstance *si = CAST_CSHARP_INSTANCE(nodes[i]->get_script_instance());
-
- if (si != nullptr) {
- MonoObject *obj = si->get_mono_object();
- if (obj != nullptr && mono_object_get_class(obj) == mono_class) {
- r_dest->push_back(nodes[i]);
- }
- }
- }
- }
- }
-}
-
-void godot_register_scene_tree_icalls() {
- GDMonoUtils::add_internal_call("Godot.SceneTree::godot_icall_SceneTree_get_nodes_in_group_Generic", godot_icall_SceneTree_get_nodes_in_group_Generic);
-}
diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h
index a637e0be9b..872c875cbe 100644
--- a/modules/mono/godotsharp_defs.h
+++ b/modules/mono/godotsharp_defs.h
@@ -33,6 +33,7 @@
#define BINDINGS_NAMESPACE "Godot"
#define BINDINGS_NAMESPACE_COLLECTIONS BINDINGS_NAMESPACE ".Collections"
+#define BINDINGS_NAMESPACE_BRIDGE BINDINGS_NAMESPACE ".Bridge"
#define BINDINGS_GLOBAL_SCOPE_CLASS "GD"
#define BINDINGS_PTR_FIELD "NativePtr"
#define BINDINGS_NATIVE_NAME_FIELD "NativeName"
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index f17b24e399..26ae7246ad 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -96,8 +96,6 @@ class _GodotSharpDirs {
public:
String res_data_dir;
String res_metadata_dir;
- String res_assemblies_base_dir;
- String res_assemblies_dir;
String res_config_dir;
String res_temp_dir;
String res_temp_assemblies_base_dir;
@@ -105,6 +103,9 @@ public:
String mono_user_dir;
String mono_logs_dir;
+ String api_assemblies_base_dir;
+ String api_assemblies_dir;
+
#ifdef TOOLS_ENABLED
String mono_solutions_dir;
String build_logs_dir;
@@ -113,7 +114,6 @@ public:
String csproj_filepath;
String data_editor_tools_dir;
- String data_editor_prebuilt_api_dir;
#else
// Equivalent of res_assemblies_dir, but in the data directory rather than in 'res://'.
// Only defined on export templates. Used when exporting assemblies outside of PCKs.
@@ -131,8 +131,6 @@ private:
_GodotSharpDirs() {
res_data_dir = ProjectSettings::get_singleton()->get_project_data_path().plus_file("mono");
res_metadata_dir = res_data_dir.plus_file("metadata");
- res_assemblies_base_dir = res_data_dir.plus_file("assemblies");
- res_assemblies_dir = res_assemblies_base_dir.plus_file(GDMono::get_expected_api_build_config());
res_config_dir = res_data_dir.plus_file("etc").plus_file("mono");
// TODO use paths from csproj
@@ -140,6 +138,8 @@ private:
res_temp_assemblies_base_dir = res_temp_dir.plus_file("bin");
res_temp_assemblies_dir = res_temp_assemblies_base_dir.plus_file(_get_expected_build_config());
+ api_assemblies_base_dir = res_data_dir.plus_file("assemblies");
+
#ifdef JAVASCRIPT_ENABLED
mono_user_dir = "user://";
#else
@@ -169,7 +169,7 @@ private:
String data_dir_root = exe_dir.plus_file("GodotSharp");
data_editor_tools_dir = data_dir_root.plus_file("Tools");
- data_editor_prebuilt_api_dir = data_dir_root.plus_file("Api");
+ api_assemblies_base_dir = data_dir_root.plus_file("Api");
String data_mono_root_dir = data_dir_root.plus_file("Mono");
data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
@@ -189,8 +189,8 @@ private:
data_editor_tools_dir = exe_dir.plus_file("../Resources/GodotSharp/Tools");
}
- if (!DirAccess::exists(data_editor_prebuilt_api_dir)) {
- data_editor_prebuilt_api_dir = exe_dir.plus_file("../Resources/GodotSharp/Api");
+ if (!DirAccess::exists(api_assemblies_base_dir)) {
+ api_assemblies_base_dir = exe_dir.plus_file("../Resources/GodotSharp/Api");
}
if (!DirAccess::exists(data_mono_root_dir)) {
@@ -234,6 +234,8 @@ private:
#endif
#endif
+
+ api_assemblies_dir = api_assemblies_base_dir.plus_file(GDMono::get_expected_api_build_config());
}
public:
@@ -251,14 +253,6 @@ String get_res_metadata_dir() {
return _GodotSharpDirs::get_singleton().res_metadata_dir;
}
-String get_res_assemblies_base_dir() {
- return _GodotSharpDirs::get_singleton().res_assemblies_base_dir;
-}
-
-String get_res_assemblies_dir() {
- return _GodotSharpDirs::get_singleton().res_assemblies_dir;
-}
-
String get_res_config_dir() {
return _GodotSharpDirs::get_singleton().res_config_dir;
}
@@ -275,6 +269,14 @@ String get_res_temp_assemblies_dir() {
return _GodotSharpDirs::get_singleton().res_temp_assemblies_dir;
}
+String get_api_assemblies_dir() {
+ return _GodotSharpDirs::get_singleton().api_assemblies_dir;
+}
+
+String get_api_assemblies_base_dir() {
+ return _GodotSharpDirs::get_singleton().api_assemblies_base_dir;
+}
+
String get_mono_user_dir() {
return _GodotSharpDirs::get_singleton().mono_user_dir;
}
@@ -303,10 +305,6 @@ String get_project_csproj_path() {
String get_data_editor_tools_dir() {
return _GodotSharpDirs::get_singleton().data_editor_tools_dir;
}
-
-String get_data_editor_prebuilt_api_dir() {
- return _GodotSharpDirs::get_singleton().data_editor_prebuilt_api_dir;
-}
#else
String get_data_game_assemblies_dir() {
return _GodotSharpDirs::get_singleton().data_game_assemblies_dir;
diff --git a/modules/mono/godotsharp_dirs.h b/modules/mono/godotsharp_dirs.h
index da25e0778f..869991bb35 100644
--- a/modules/mono/godotsharp_dirs.h
+++ b/modules/mono/godotsharp_dirs.h
@@ -37,13 +37,14 @@ namespace GodotSharpDirs {
String get_res_data_dir();
String get_res_metadata_dir();
-String get_res_assemblies_base_dir();
-String get_res_assemblies_dir();
String get_res_config_dir();
String get_res_temp_dir();
String get_res_temp_assemblies_base_dir();
String get_res_temp_assemblies_dir();
+String get_api_assemblies_dir();
+String get_api_assemblies_base_dir();
+
String get_mono_user_dir();
String get_mono_logs_dir();
@@ -55,7 +56,6 @@ String get_project_sln_path();
String get_project_csproj_path();
String get_data_editor_tools_dir();
-String get_data_editor_prebuilt_api_dir();
#else
String get_data_game_assemblies_dir();
#endif
diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp
index 72b353d8c1..e01d0c6e18 100644
--- a/modules/mono/managed_callable.cpp
+++ b/modules/mono/managed_callable.cpp
@@ -32,7 +32,6 @@
#include "csharp_script.h"
#include "mono_gd/gd_mono_cache.h"
-#include "mono_gd/gd_mono_marshal.h"
#include "mono_gd/gd_mono_utils.h"
#ifdef GD_MONO_HOT_RELOAD
@@ -45,8 +44,8 @@ bool ManagedCallable::compare_equal(const CallableCustom *p_a, const CallableCus
const ManagedCallable *a = static_cast<const ManagedCallable *>(p_a);
const ManagedCallable *b = static_cast<const ManagedCallable *>(p_b);
- if (!a->delegate_handle || !b->delegate_handle) {
- if (!a->delegate_handle && !b->delegate_handle) {
+ if (!a->delegate_handle.value || !b->delegate_handle.value) {
+ if (!a->delegate_handle.value && !b->delegate_handle.value) {
return true;
}
return false;
@@ -54,7 +53,7 @@ bool ManagedCallable::compare_equal(const CallableCustom *p_a, const CallableCus
// Call Delegate's 'Equals'
MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(DelegateUtils, DelegateEquals)
+ MonoBoolean res = GDMonoCache::cached_data.methodthunk_DelegateUtils_DelegateEquals
.invoke(a->delegate_handle,
b->delegate_handle, &exc);
UNHANDLED_EXCEPTION(exc);
@@ -69,7 +68,7 @@ bool ManagedCallable::compare_less(const CallableCustom *p_a, const CallableCust
}
uint32_t ManagedCallable::hash() const {
- return hash_murmur3_one_64((uint64_t)delegate_handle);
+ return hash_murmur3_one_64((uint64_t)delegate_handle.value);
}
String ManagedCallable::get_as_text() const {
@@ -94,7 +93,7 @@ void ManagedCallable::call(const Variant **p_arguments, int p_argcount, Variant
r_return_value = Variant();
MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(DelegateUtils, InvokeWithVariantArgs)
+ GDMonoCache::cached_data.methodthunk_DelegateUtils_InvokeWithVariantArgs
.invoke(delegate_handle, p_arguments,
p_argcount, &r_return_value, &exc);
@@ -106,21 +105,21 @@ void ManagedCallable::call(const Variant **p_arguments, int p_argcount, Variant
}
void ManagedCallable::release_delegate_handle() {
- if (delegate_handle) {
+ if (delegate_handle.value) {
MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(DelegateUtils, FreeGCHandle).invoke(delegate_handle, &exc);
+ GDMonoCache::cached_data.methodthunk_GCHandleBridge_FreeGCHandle.invoke(delegate_handle, &exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
}
- delegate_handle = nullptr;
+ delegate_handle = GCHandleIntPtr();
}
}
// Why you do this clang-format...
/* clang-format off */
-ManagedCallable::ManagedCallable(void *p_delegate_handle) : delegate_handle(p_delegate_handle) {
+ManagedCallable::ManagedCallable(GCHandleIntPtr p_delegate_handle) : delegate_handle(p_delegate_handle) {
#ifdef GD_MONO_HOT_RELOAD
{
MutexLock lock(instances_mutex);
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
index 56c11e7e45..d0f6362d42 100644
--- a/modules/mono/managed_callable.h
+++ b/modules/mono/managed_callable.h
@@ -38,11 +38,10 @@
#include "core/variant/callable.h"
#include "mono_gc_handle.h"
-#include "mono_gd/gd_mono_method.h"
class ManagedCallable : public CallableCustom {
friend class CSharpLanguage;
- void *delegate_handle = nullptr;
+ GCHandleIntPtr delegate_handle;
#ifdef GD_MONO_HOT_RELOAD
SelfList<ManagedCallable> self_instance = this;
@@ -59,7 +58,7 @@ public:
ObjectID get_object() const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
- _FORCE_INLINE_ void *get_delegate() const { return delegate_handle; }
+ _FORCE_INLINE_ GCHandleIntPtr get_delegate() const { return delegate_handle; }
static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
@@ -69,7 +68,7 @@ public:
void release_delegate_handle();
- ManagedCallable(void *p_delegate_handle);
+ ManagedCallable(GCHandleIntPtr p_delegate_handle);
~ManagedCallable();
};
diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp
index f3dafa6ecf..f0a48483f6 100644
--- a/modules/mono/mono_gc_handle.cpp
+++ b/modules/mono/mono_gc_handle.cpp
@@ -31,34 +31,24 @@
#include "mono_gc_handle.h"
#include "mono_gd/gd_mono.h"
+#include "mono_gd/gd_mono_cache.h"
void MonoGCHandleData::release() {
#ifdef DEBUG_ENABLED
- CRASH_COND(handle && GDMono::get_singleton() == nullptr);
+ CRASH_COND(handle.value && GDMono::get_singleton() == nullptr);
#endif
- if (handle && GDMono::get_singleton()->is_runtime_initialized()) {
- GDMonoUtils::free_gchandle(handle);
- handle = 0;
+ if (handle.value && !GDMonoCache::cached_data.methodthunk_GCHandleBridge_FreeGCHandle.is_null() &&
+ GDMono::get_singleton()->is_runtime_initialized()) {
+ free_gchandle(handle);
+ handle.value = nullptr;
}
}
-
-MonoGCHandleData MonoGCHandleData::new_strong_handle(MonoObject *p_object) {
- return MonoGCHandleData(GDMonoUtils::new_strong_gchandle(p_object), gdmono::GCHandleType::STRONG_HANDLE);
-}
-
-MonoGCHandleData MonoGCHandleData::new_strong_handle_pinned(MonoObject *p_object) {
- return MonoGCHandleData(GDMonoUtils::new_strong_gchandle_pinned(p_object), gdmono::GCHandleType::STRONG_HANDLE);
-}
-
-MonoGCHandleData MonoGCHandleData::new_weak_handle(MonoObject *p_object) {
- return MonoGCHandleData(GDMonoUtils::new_weak_gchandle(p_object), gdmono::GCHandleType::WEAK_HANDLE);
-}
-
-Ref<MonoGCHandleRef> MonoGCHandleRef::create_strong(MonoObject *p_object) {
- return memnew(MonoGCHandleRef(MonoGCHandleData::new_strong_handle(p_object)));
-}
-
-Ref<MonoGCHandleRef> MonoGCHandleRef::create_weak(MonoObject *p_object) {
- return memnew(MonoGCHandleRef(MonoGCHandleData::new_weak_handle(p_object)));
+void MonoGCHandleData::free_gchandle(GCHandleIntPtr p_gchandle) {
+ CRASH_COND(GDMonoCache::cached_data.methodthunk_GCHandleBridge_FreeGCHandle.is_null());
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_GCHandleBridge_FreeGCHandle.invoke(p_gchandle, &exc);
+ if (exc) {
+ GDMonoUtils::debug_unhandled_exception(exc);
+ }
}
diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h
index e2aff1d19d..96553cf4f4 100644
--- a/modules/mono/mono_gc_handle.h
+++ b/modules/mono/mono_gc_handle.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -31,8 +31,6 @@
#ifndef MONO_GC_HANDLE_H
#define MONO_GC_HANDLE_H
-#include <mono/jit/jit.h>
-
#include "core/object/ref_counted.h"
namespace gdmono {
@@ -44,18 +42,25 @@ enum class GCHandleType : char {
};
}
+struct GCHandleIntPtr {
+ void *value = nullptr;
+};
+
+static_assert(sizeof(GCHandleIntPtr) == sizeof(void *));
+
// Manual release of the GC handle must be done when using this struct
struct MonoGCHandleData {
- uint32_t handle = 0;
+ GCHandleIntPtr handle;
gdmono::GCHandleType type = gdmono::GCHandleType::NIL;
- _FORCE_INLINE_ bool is_released() const { return !handle; }
+ _FORCE_INLINE_ bool is_released() const { return !handle.value; }
_FORCE_INLINE_ bool is_weak() const { return type == gdmono::GCHandleType::WEAK_HANDLE; }
-
- _FORCE_INLINE_ MonoObject *get_target() const { return handle ? mono_gchandle_get_target(handle) : nullptr; }
+ _FORCE_INLINE_ GCHandleIntPtr get_intptr() const { return handle; }
void release();
+ static void free_gchandle(GCHandleIntPtr p_gchandle);
+
void operator=(const MonoGCHandleData &p_other) {
#ifdef DEBUG_ENABLED
CRASH_COND(!is_released());
@@ -68,40 +73,10 @@ struct MonoGCHandleData {
MonoGCHandleData() {}
- MonoGCHandleData(uint32_t p_handle, gdmono::GCHandleType p_type) :
+ MonoGCHandleData(GCHandleIntPtr p_handle, gdmono::GCHandleType p_type) :
handle(p_handle),
type(p_type) {
}
-
- static MonoGCHandleData new_strong_handle(MonoObject *p_object);
- static MonoGCHandleData new_strong_handle_pinned(MonoObject *p_object);
- static MonoGCHandleData new_weak_handle(MonoObject *p_object);
-};
-
-class MonoGCHandleRef : public RefCounted {
- GDCLASS(MonoGCHandleRef, RefCounted);
-
- MonoGCHandleData data;
-
-public:
- static Ref<MonoGCHandleRef> create_strong(MonoObject *p_object);
- static Ref<MonoGCHandleRef> create_weak(MonoObject *p_object);
-
- _FORCE_INLINE_ bool is_released() const { return data.is_released(); }
- _FORCE_INLINE_ bool is_weak() const { return data.is_weak(); }
-
- _FORCE_INLINE_ MonoObject *get_target() const { return data.get_target(); }
-
- void release() { data.release(); }
-
- _FORCE_INLINE_ void set_handle(uint32_t p_handle, gdmono::GCHandleType p_handle_type) {
- data = MonoGCHandleData(p_handle, p_handle_type);
- }
-
- MonoGCHandleRef(const MonoGCHandleData &p_gc_handle_data) :
- data(p_gc_handle_data) {
- }
- ~MonoGCHandleRef() { release(); }
};
#endif // MONO_GC_HANDLE_H
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index bf387be4c8..ce4fc0c5a0 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -48,8 +48,6 @@
#include "../godotsharp_dirs.h"
#include "../utils/path_utils.h"
#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
#include "gd_mono_utils.h"
#ifdef ANDROID_ENABLED
@@ -411,7 +409,9 @@ void GDMono::initialize_load_assemblies() {
// Load assemblies. The API and tools assemblies are required,
// the application is aborted if these assemblies cannot be loaded.
- _load_api_assemblies();
+ if (!_try_load_api_assemblies()) {
+ CRASH_NOW_MSG("Failed to load one of the API assemblies.");
+ }
#if defined(TOOLS_ENABLED)
bool tool_assemblies_loaded = _load_tools_assemblies();
@@ -432,24 +432,12 @@ void GDMono::initialize_load_assemblies() {
}
}
-bool GDMono::_are_api_assemblies_out_of_sync() {
- bool out_of_sync = core_api_assembly.assembly && (core_api_assembly.out_of_sync || !GDMonoCache::cached_data.godot_api_cache_updated);
-#ifdef TOOLS_ENABLED
- if (!out_of_sync) {
- out_of_sync = editor_api_assembly.assembly && editor_api_assembly.out_of_sync;
- }
-#endif
- return out_of_sync;
-}
-
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_object_icalls();
- godot_register_scene_tree_icalls();
godot_register_placeholder_icalls();
}
@@ -490,35 +478,35 @@ GDMonoAssembly *GDMono::get_loaded_assembly(const String &p_name) {
return result ? *result : nullptr;
}
-bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) {
+bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly) {
#ifdef DEBUG_ENABLED
CRASH_COND(!r_assembly);
#endif
MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
- bool result = load_assembly(p_name, aname, r_assembly, p_refonly);
+ bool result = load_assembly(p_name, aname, r_assembly);
mono_assembly_name_free(aname);
mono_free(aname);
return result;
}
-bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) {
+bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly) {
#ifdef DEBUG_ENABLED
CRASH_COND(!r_assembly);
#endif
- return load_assembly(p_name, p_aname, r_assembly, p_refonly, GDMonoAssembly::get_default_search_dirs());
+ return load_assembly(p_name, p_aname, r_assembly, GDMonoAssembly::get_default_search_dirs());
}
-bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly, const Vector<String> &p_search_dirs) {
+bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, const Vector<String> &p_search_dirs) {
#ifdef DEBUG_ENABLED
CRASH_COND(!r_assembly);
#endif
- print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...");
+ print_verbose("Mono: Loading assembly " + p_name + "...");
- GDMonoAssembly *assembly = GDMonoAssembly::load(p_name, p_aname, p_refonly, p_search_dirs);
+ GDMonoAssembly *assembly = GDMonoAssembly::load(p_name, p_aname, /* refonly: */ false, p_search_dirs);
if (!assembly) {
return false;
@@ -526,17 +514,17 @@ bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMo
*r_assembly = assembly;
- print_verbose("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path());
+ print_verbose("Mono: Assembly " + p_name + " loaded from path: " + (*r_assembly)->get_path());
return true;
}
-bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly, bool p_refonly) {
+bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly) {
CRASH_COND(!r_assembly);
- print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...");
+ print_verbose("Mono: Loading assembly " + p_name + "...");
- GDMonoAssembly *assembly = GDMonoAssembly::load_from(p_name, p_path, p_refonly);
+ GDMonoAssembly *assembly = GDMonoAssembly::load_from(p_name, p_path, /* refonly: */ false);
if (!assembly) {
return false;
@@ -544,279 +532,41 @@ bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMo
*r_assembly = assembly;
- print_verbose("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path());
+ print_verbose("Mono: Assembly " + p_name + " loaded from path: " + (*r_assembly)->get_path());
return true;
}
-ApiAssemblyInfo::Version ApiAssemblyInfo::Version::get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, ApiAssemblyInfo::Type p_api_type) {
- ApiAssemblyInfo::Version api_assembly_version;
-
- const char *nativecalls_name = p_api_type == ApiAssemblyInfo::API_CORE
- ? BINDINGS_CLASS_NATIVECALLS
- : BINDINGS_CLASS_NATIVECALLS_EDITOR;
-
- GDMonoClass *nativecalls_klass = p_api_assembly->get_class(BINDINGS_NAMESPACE, nativecalls_name);
-
- if (nativecalls_klass) {
- GDMonoField *api_hash_field = nativecalls_klass->get_field("godot_api_hash");
- if (api_hash_field) {
- api_assembly_version.godot_api_hash = GDMonoMarshal::unbox<uint64_t>(api_hash_field->get_value(nullptr));
- }
- }
-
- return api_assembly_version;
-}
-
-String ApiAssemblyInfo::to_string(ApiAssemblyInfo::Type p_type) {
- return p_type == ApiAssemblyInfo::API_CORE ? "API_CORE" : "API_EDITOR";
-}
-
bool GDMono::_load_corlib_assembly() {
if (corlib_assembly) {
return true;
}
- bool success = load_assembly("mscorlib", &corlib_assembly);
-
- if (success) {
- GDMonoCache::update_corlib_cache();
- }
-
- return success;
-}
-
-#ifdef TOOLS_ENABLED
-bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config) {
- String src_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
- String dst_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config);
-
- String assembly_name = p_api_type == ApiAssemblyInfo::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
-
- // Create destination directory if needed
- if (!DirAccess::exists(dst_dir)) {
- Ref<DirAccess> da = DirAccess::create_for_path(dst_dir);
- Error err = da->make_dir_recursive(dst_dir);
-
- if (err != OK) {
- ERR_PRINT("Failed to create destination directory for the API assemblies. Error: " + itos(err) + ".");
- return false;
- }
- }
-
- Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
-
- String xml_file = assembly_name + ".xml";
- if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK) {
- WARN_PRINT("Failed to copy '" + xml_file + "'.");
- }
-
- String pdb_file = assembly_name + ".pdb";
- if (da->copy(src_dir.plus_file(pdb_file), dst_dir.plus_file(pdb_file)) != OK) {
- WARN_PRINT("Failed to copy '" + pdb_file + "'.");
- }
-
- String assembly_file = assembly_name + ".dll";
- if (da->copy(src_dir.plus_file(assembly_file), dst_dir.plus_file(assembly_file)) != OK) {
- ERR_PRINT("Failed to copy '" + assembly_file + "'.");
- return false;
- }
-
- return true;
-}
-
-static bool try_get_cached_api_hash_for(const String &p_api_assemblies_dir, bool &r_out_of_sync) {
- String core_api_assembly_path = p_api_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
- String editor_api_assembly_path = p_api_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
-
- if (!FileAccess::exists(core_api_assembly_path) || !FileAccess::exists(editor_api_assembly_path)) {
- return false;
- }
-
- String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg");
-
- if (!FileAccess::exists(cached_api_hash_path)) {
- return false;
- }
-
- Ref<ConfigFile> cfg;
- cfg.instantiate();
- Error cfg_err = cfg->load(cached_api_hash_path);
- ERR_FAIL_COND_V(cfg_err != OK, false);
-
- // Checking the modified time is good enough
- if (FileAccess::get_modified_time(core_api_assembly_path) != (uint64_t)cfg->get_value("core", "modified_time") ||
- FileAccess::get_modified_time(editor_api_assembly_path) != (uint64_t)cfg->get_value("editor", "modified_time")) {
- return false;
- }
-
- r_out_of_sync = GDMono::get_singleton()->get_api_core_hash() != (uint64_t)cfg->get_value("core", "api_hash") ||
- GDMono::get_singleton()->get_api_editor_hash() != (uint64_t)cfg->get_value("editor", "api_hash");
-
- return true;
-}
-
-static void create_cached_api_hash_for(const String &p_api_assemblies_dir) {
- String core_api_assembly_path = p_api_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
- String editor_api_assembly_path = p_api_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
- String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg");
-
- Ref<ConfigFile> cfg;
- cfg.instantiate();
-
- cfg->set_value("core", "modified_time", FileAccess::get_modified_time(core_api_assembly_path));
- cfg->set_value("editor", "modified_time", FileAccess::get_modified_time(editor_api_assembly_path));
-
- // This assumes the prebuilt api assemblies we copied to the project are not out of sync
- cfg->set_value("core", "api_hash", GDMono::get_singleton()->get_api_core_hash());
- cfg->set_value("editor", "api_hash", GDMono::get_singleton()->get_api_editor_hash());
-
- Error err = cfg->save(cached_api_hash_path);
- ERR_FAIL_COND(err != OK);
-}
-
-bool GDMono::_temp_domain_load_are_assemblies_out_of_sync(const String &p_config) {
- MonoDomain *temp_domain = GDMonoUtils::create_domain("GodotEngine.Domain.CheckApiAssemblies");
- ERR_FAIL_NULL_V(temp_domain, "Failed to create temporary domain to check API assemblies");
- _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(temp_domain);
-
- _GDMONO_SCOPE_DOMAIN_(temp_domain);
-
- GDMono::LoadedApiAssembly temp_core_api_assembly;
- GDMono::LoadedApiAssembly temp_editor_api_assembly;
-
- if (!_try_load_api_assemblies(temp_core_api_assembly, temp_editor_api_assembly,
- p_config, /* refonly: */ true, /* loaded_callback: */ nullptr)) {
- return temp_core_api_assembly.out_of_sync || temp_editor_api_assembly.out_of_sync;
- }
-
- return true; // Failed to load, assume they're outdated assemblies
-}
-
-String GDMono::update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync, const bool *p_editor_api_out_of_sync) {
-#define FAIL_REASON(m_out_of_sync, m_prebuilt_exists) \
- ( \
- (m_out_of_sync ? String("The assembly is invalidated ") : String("The assembly was not found ")) + \
- (m_prebuilt_exists ? String("and the prebuilt assemblies are missing.") : String("and we failed to copy the prebuilt assemblies.")))
-
- String dst_assemblies_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config);
-
- String core_assembly_path = dst_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
- String editor_assembly_path = dst_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
-
- bool api_assemblies_out_of_sync = false;
-
- if (p_core_api_out_of_sync && p_editor_api_out_of_sync) {
- api_assemblies_out_of_sync = *p_core_api_out_of_sync || *p_editor_api_out_of_sync;
- } else if (FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) {
- // Determine if they're out of sync
- if (!try_get_cached_api_hash_for(dst_assemblies_dir, api_assemblies_out_of_sync)) {
- api_assemblies_out_of_sync = _temp_domain_load_are_assemblies_out_of_sync(p_config);
- }
- }
-
- // Note: Even if only one of the assemblies if missing or out of sync, we update both
-
- if (!api_assemblies_out_of_sync && FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) {
- return String(); // No update needed
- }
-
- print_verbose("Updating '" + p_config + "' API assemblies");
-
- String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
- String prebuilt_core_dll_path = prebuilt_api_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
- String prebuilt_editor_dll_path = prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
-
- if (!FileAccess::exists(prebuilt_core_dll_path) || !FileAccess::exists(prebuilt_editor_dll_path)) {
- return FAIL_REASON(api_assemblies_out_of_sync, /* prebuilt_exists: */ false);
- }
-
- // Copy the prebuilt Api
- if (!copy_prebuilt_api_assembly(ApiAssemblyInfo::API_CORE, p_config) ||
- !copy_prebuilt_api_assembly(ApiAssemblyInfo::API_EDITOR, p_config)) {
- return FAIL_REASON(api_assemblies_out_of_sync, /* prebuilt_exists: */ true);
- }
-
- // Cache the api hash of the assemblies we just copied
- create_cached_api_hash_for(dst_assemblies_dir);
-
- return String(); // Updated successfully
-
-#undef FAIL_REASON
+ return load_assembly("mscorlib", &corlib_assembly);
}
-#endif
-bool GDMono::_load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly) {
- if (r_loaded_api_assembly.assembly) {
+bool GDMono::_load_core_api_assembly(GDMonoAssembly **r_loaded_api_assembly, const String &p_config) {
+ if (*r_loaded_api_assembly) {
return true;
}
-#ifdef TOOLS_ENABLED
- // For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date
-
- // If running the project manager, load it from the prebuilt API directory
- String assembly_dir = !Engine::get_singleton()->is_project_manager_hint()
- ? GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config)
- : GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
-
- String assembly_path = assembly_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
-
- bool success = FileAccess::exists(assembly_path) &&
- load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &r_loaded_api_assembly.assembly, p_refonly);
-#else
- bool success = load_assembly(CORE_API_ASSEMBLY_NAME, &r_loaded_api_assembly.assembly, p_refonly);
-#endif
-
-#ifdef DEBUG_METHODS_ENABLED
- if (success) {
- ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_CORE);
- r_loaded_api_assembly.out_of_sync = get_api_core_hash() != api_assembly_ver.godot_api_hash;
- } else {
- r_loaded_api_assembly.out_of_sync = false;
- }
-#else
- r_loaded_api_assembly.out_of_sync = false;
-#endif
-
- return success;
+ return load_assembly(CORE_API_ASSEMBLY_NAME, r_loaded_api_assembly);
}
#ifdef TOOLS_ENABLED
-bool GDMono::_load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly) {
- if (r_loaded_api_assembly.assembly) {
+bool GDMono::_load_editor_api_assembly(GDMonoAssembly **r_loaded_api_assembly, const String &p_config) {
+ if (*r_loaded_api_assembly) {
return true;
}
- // For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date
-
- // If running the project manager, load it from the prebuilt API directory
- String assembly_dir = !Engine::get_singleton()->is_project_manager_hint()
- ? GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config)
- : GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
-
- String assembly_path = assembly_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
-
- bool success = FileAccess::exists(assembly_path) &&
- load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &r_loaded_api_assembly.assembly, p_refonly);
-
-#ifdef DEBUG_METHODS_ENABLED
- if (success) {
- ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_EDITOR);
- r_loaded_api_assembly.out_of_sync = get_api_editor_hash() != api_assembly_ver.godot_api_hash;
- } else {
- r_loaded_api_assembly.out_of_sync = false;
- }
-#else
- r_loaded_api_assembly.out_of_sync = false;
-#endif
-
- return success;
+ return load_assembly(EDITOR_API_ASSEMBLY_NAME, r_loaded_api_assembly);
}
#endif
-bool GDMono::_try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, LoadedApiAssembly &r_editor_api_assembly,
- const String &p_config, bool p_refonly, CoreApiAssemblyLoadedCallback p_callback) {
- if (!_load_core_api_assembly(r_core_api_assembly, p_config, p_refonly)) {
+bool GDMono::_try_load_api_assemblies() {
+ String config = get_expected_api_build_config();
+
+ if (!_load_core_api_assembly(&core_api_assembly, config)) {
if (OS::get_singleton()->is_stdout_verbose()) {
print_error("Mono: Failed to load Core API assembly");
}
@@ -824,30 +574,15 @@ bool GDMono::_try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, Lo
}
#ifdef TOOLS_ENABLED
- if (!_load_editor_api_assembly(r_editor_api_assembly, p_config, p_refonly)) {
+ if (!_load_editor_api_assembly(&editor_api_assembly, config)) {
if (OS::get_singleton()->is_stdout_verbose()) {
print_error("Mono: Failed to load Editor API assembly");
}
return false;
}
-
- if (r_editor_api_assembly.out_of_sync) {
- return false;
- }
#endif
- // Check if the core API assembly is out of sync only after trying to load the
- // editor API assembly. Otherwise, if both assemblies are out of sync, we would
- // only update the former as we won't know the latter also needs to be updated.
- if (r_core_api_assembly.out_of_sync) {
- return false;
- }
-
- if (p_callback) {
- return p_callback();
- }
-
- return true;
+ return _on_core_api_assembly_loaded();
}
bool GDMono::_on_core_api_assembly_loaded() {
@@ -862,72 +597,14 @@ bool GDMono::_on_core_api_assembly_loaded() {
return true;
}
-bool GDMono::_try_load_api_assemblies_preset() {
- return _try_load_api_assemblies(core_api_assembly, editor_api_assembly,
- get_expected_api_build_config(), /* refonly: */ false, _on_core_api_assembly_loaded);
-}
-
-void GDMono::_load_api_assemblies() {
- bool api_assemblies_loaded = _try_load_api_assemblies_preset();
-
-#if defined(TOOLS_ENABLED) && !defined(GD_MONO_SINGLE_APPDOMAIN)
- if (!api_assemblies_loaded) {
- // The API assemblies are out of sync or some other error happened. Fine, try one more time, but
- // this time update them from the prebuilt assemblies directory before trying to load them again.
-
- // Shouldn't happen. The project manager loads the prebuilt API assemblies
- CRASH_COND_MSG(Engine::get_singleton()->is_project_manager_hint(), "Failed to load one of the prebuilt API assemblies.");
-
- // 1. Unload the scripts domain
- Error domain_unload_err = _unload_scripts_domain();
- CRASH_COND_MSG(domain_unload_err != OK, "Mono: Failed to unload scripts domain.");
-
- // 2. Update the API assemblies
- String update_error = update_api_assemblies_from_prebuilt("Debug", &core_api_assembly.out_of_sync, &editor_api_assembly.out_of_sync);
- CRASH_COND_MSG(!update_error.is_empty(), update_error);
-
- // 3. Load the scripts domain again
- Error domain_load_err = _load_scripts_domain();
- CRASH_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
-
- // 4. Try loading the updated assemblies
- api_assemblies_loaded = _try_load_api_assemblies_preset();
- }
-#endif
-
- if (!api_assemblies_loaded) {
- // welp... too bad
-
- if (_are_api_assemblies_out_of_sync()) {
- if (core_api_assembly.out_of_sync) {
- ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync.");
- } else if (!GDMonoCache::cached_data.godot_api_cache_updated) {
- ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed.");
- }
-
-#ifdef TOOLS_ENABLED
- if (editor_api_assembly.out_of_sync) {
- ERR_PRINT("The assembly '" EDITOR_API_ASSEMBLY_NAME "' is out of sync.");
- }
-#endif
-
- CRASH_NOW();
- } else {
- CRASH_NOW_MSG("Failed to load one of the API assemblies.");
- }
- }
-}
-
#ifdef TOOLS_ENABLED
bool GDMono::_load_tools_assemblies() {
if (tools_assembly && tools_project_editor_assembly) {
return true;
}
- bool success = load_assembly(TOOLS_ASM_NAME, &tools_assembly) &&
- load_assembly(TOOLS_PROJECT_EDITOR_ASM_NAME, &tools_project_editor_assembly);
-
- return success;
+ return load_assembly(TOOLS_ASM_NAME, &tools_assembly) &&
+ load_assembly(TOOLS_PROJECT_EDITOR_ASM_NAME, &tools_project_editor_assembly);
}
#endif
@@ -946,7 +623,12 @@ bool GDMono::_load_project_assembly() {
if (success) {
mono_assembly_set_main(project_assembly->get_assembly());
- CSharpLanguage::get_singleton()->lookup_scripts_in_assembly(project_assembly);
+ MonoException *exc = nullptr;
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_LookupScriptsInAssembly.invoke(
+ mono_assembly_get_object(mono_domain_get(), project_assembly->get_assembly()), &exc);
+ if (exc) {
+ GDMonoUtils::debug_print_unhandled_exception(exc);
+ }
}
return success;
@@ -955,11 +637,8 @@ bool GDMono::_load_project_assembly() {
void GDMono::_install_trace_listener() {
#ifdef DEBUG_ENABLED
// Install the trace listener now before the project assembly is loaded
- GDMonoClass *debug_utils = get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, "DebuggingUtils");
- GDMonoMethod *install_func = debug_utils->get_method("InstallTraceListener");
-
MonoException *exc = nullptr;
- install_func->invoke_raw(nullptr, nullptr, &exc);
+ GDMonoCache::cached_data.methodthunk_DebuggingUtils_InstallTraceListener.invoke(&exc);
if (exc) {
GDMonoUtils::debug_print_unhandled_exception(exc);
ERR_PRINT("Failed to install 'System.Diagnostics.Trace' listener.");
@@ -1007,9 +686,9 @@ Error GDMono::_unload_scripts_domain() {
_domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
- core_api_assembly.assembly = nullptr;
+ core_api_assembly = nullptr;
#ifdef TOOLS_ENABLED
- editor_api_assembly.assembly = nullptr;
+ editor_api_assembly = nullptr;
#endif
project_assembly = nullptr;
@@ -1051,7 +730,9 @@ Error GDMono::reload_scripts_domain() {
// Load assemblies. The API and tools assemblies are required,
// the application is aborted if these assemblies cannot be loaded.
- _load_api_assemblies();
+ if (!_try_load_api_assemblies()) {
+ CRASH_NOW_MSG("Failed to load one of the API assemblies.");
+ }
#if defined(TOOLS_ENABLED)
bool tools_assemblies_loaded = _load_tools_assemblies();
@@ -1104,49 +785,6 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
}
#endif
-GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
- MonoImage *image = mono_class_get_image(p_raw_class);
-
- if (image == corlib_assembly->get_image()) {
- return corlib_assembly->get_class(p_raw_class);
- }
-
- int32_t domain_id = mono_domain_get_id(mono_domain_get());
- HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
-
- for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
- GDMonoAssembly *assembly = E.value;
- if (assembly->get_image() == image) {
- GDMonoClass *klass = assembly->get_class(p_raw_class);
- if (klass) {
- return klass;
- }
- }
- }
-
- return nullptr;
-}
-
-GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &p_name) {
- GDMonoClass *klass = corlib_assembly->get_class(p_namespace, p_name);
- if (klass) {
- return klass;
- }
-
- int32_t domain_id = mono_domain_get_id(mono_domain_get());
- HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
-
- for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
- GDMonoAssembly *assembly = E.value;
- klass = assembly->get_class(p_namespace, p_name);
- if (klass) {
- return klass;
- }
- }
-
- return nullptr;
-}
-
void GDMono::_domain_assemblies_cleanup(int32_t p_domain_id) {
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id];
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index bc871fe750..ac99aecabd 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -41,31 +41,6 @@
#include "../utils/mono_reg_utils.h"
#endif
-namespace ApiAssemblyInfo {
-enum Type {
- API_CORE,
- API_EDITOR
-};
-
-struct Version {
- uint64_t godot_api_hash = 0;
-
- bool operator==(const Version &p_other) const {
- return godot_api_hash == p_other.godot_api_hash;
- }
-
- Version() {}
-
- Version(uint64_t p_godot_api_hash) :
- godot_api_hash(p_godot_api_hash) {
- }
-
- static Version get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, Type p_api_type);
-};
-
-String to_string(Type p_type);
-} // namespace ApiAssemblyInfo
-
class GDMono {
public:
enum UnhandledExceptionPolicy {
@@ -73,13 +48,6 @@ public:
POLICY_LOG_ERROR
};
- struct LoadedApiAssembly {
- GDMonoAssembly *assembly = nullptr;
- bool out_of_sync = false;
-
- LoadedApiAssembly() {}
- };
-
private:
bool runtime_initialized;
bool finalizing_scripts_domain;
@@ -98,17 +66,12 @@ private:
GDMonoAssembly *tools_project_editor_assembly = nullptr;
#endif
- LoadedApiAssembly core_api_assembly;
- LoadedApiAssembly editor_api_assembly;
-
- typedef bool (*CoreApiAssemblyLoadedCallback)();
+ GDMonoAssembly *core_api_assembly;
+ GDMonoAssembly *editor_api_assembly;
- bool _are_api_assemblies_out_of_sync();
- bool _temp_domain_load_are_assemblies_out_of_sync(const String &p_config);
-
- bool _load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly);
+ bool _load_core_api_assembly(GDMonoAssembly **r_loaded_api_assembly, const String &p_config);
#ifdef TOOLS_ENABLED
- bool _load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly);
+ bool _load_editor_api_assembly(GDMonoAssembly **r_loaded_api_assembly, const String &p_config);
#endif
static bool _on_core_api_assembly_loaded();
@@ -119,10 +82,7 @@ private:
#endif
bool _load_project_assembly();
- bool _try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, LoadedApiAssembly &r_editor_api_assembly,
- const String &p_config, bool p_refonly, CoreApiAssemblyLoadedCallback p_callback);
- bool _try_load_api_assemblies_preset();
- void _load_api_assemblies();
+ bool _try_load_api_assemblies();
void _install_trace_listener();
@@ -184,11 +144,6 @@ public:
#endif
}
-#ifdef TOOLS_ENABLED
- bool copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config);
- String update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync = nullptr, const bool *p_editor_api_out_of_sync = nullptr);
-#endif
-
static GDMono *get_singleton() { return singleton; }
[[noreturn]] static void unhandled_exception_hook(MonoObject *p_exc, void *p_user_data);
@@ -206,29 +161,24 @@ public:
_FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; }
_FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; }
- _FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly.assembly; }
+ _FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly; }
_FORCE_INLINE_ GDMonoAssembly *get_project_assembly() const { return project_assembly; }
#ifdef TOOLS_ENABLED
- _FORCE_INLINE_ GDMonoAssembly *get_editor_api_assembly() const { return editor_api_assembly.assembly; }
_FORCE_INLINE_ GDMonoAssembly *get_tools_assembly() const { return tools_assembly; }
- _FORCE_INLINE_ GDMonoAssembly *get_tools_project_editor_assembly() const { return tools_project_editor_assembly; }
#endif
#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
const MonoRegInfo &get_mono_reg_info() { return mono_reg_info; }
#endif
- GDMonoClass *get_class(MonoClass *p_raw_class);
- GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_name);
-
#ifdef GD_MONO_HOT_RELOAD
Error reload_scripts_domain();
#endif
- bool load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly = false);
- bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false);
- bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly, const Vector<String> &p_search_dirs);
- bool load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly, bool p_refonly = false);
+ bool load_assembly(const String &p_name, GDMonoAssembly **r_assembly);
+ bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly);
+ bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, const Vector<String> &p_search_dirs);
+ bool load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly);
Error finalize_and_unload_domain(MonoDomain *p_domain);
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 42c6b6305f..605216d331 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -40,8 +40,8 @@
#include "core/templates/list.h"
#include "../godotsharp_dirs.h"
+#include "gd_mono.h"
#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
Vector<String> GDMonoAssembly::search_dirs;
@@ -73,21 +73,18 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin
}
if (p_custom_config.is_empty()) {
- r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
+ r_search_dirs.push_back(GodotSharpDirs::get_api_assemblies_dir());
} else {
String api_config = p_custom_config == "ExportRelease" ? "Release" : "Debug";
- r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_base_dir().plus_file(api_config));
+ r_search_dirs.push_back(GodotSharpDirs::get_api_assemblies_base_dir().plus_file(api_config));
}
- r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_base_dir());
+ r_search_dirs.push_back(GodotSharpDirs::get_api_assemblies_base_dir());
r_search_dirs.push_back(OS::get_singleton()->get_resource_dir());
r_search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir());
#ifdef TOOLS_ENABLED
r_search_dirs.push_back(GodotSharpDirs::get_data_editor_tools_dir());
-
- // For GodotTools to find the api assemblies
- r_search_dirs.push_back(GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug"));
#endif
}
@@ -330,13 +327,6 @@ no_pdb:
void GDMonoAssembly::unload() {
ERR_FAIL_NULL(image); // Should not be called if already unloaded
- for (const KeyValue<MonoClass *, GDMonoClass *> &E : cached_raw) {
- memdelete(E.value);
- }
-
- cached_classes.clear();
- cached_raw.clear();
-
assembly = nullptr;
image = nullptr;
}
@@ -345,90 +335,6 @@ String GDMonoAssembly::get_path() const {
return String::utf8(mono_image_get_filename(image));
}
-bool GDMonoAssembly::has_attribute(GDMonoClass *p_attr_class) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_NULL_V(p_attr_class, false);
-#endif
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return false;
- }
-
- return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-MonoObject *GDMonoAssembly::get_attribute(GDMonoClass *p_attr_class) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_NULL_V(p_attr_class, nullptr);
-#endif
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return nullptr;
- }
-
- return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-void GDMonoAssembly::fetch_attributes() {
- ERR_FAIL_COND(attributes != nullptr);
-
- attributes = mono_custom_attrs_from_assembly(assembly);
- attrs_fetched = true;
-}
-
-GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const StringName &p_name) {
- ERR_FAIL_NULL_V(image, nullptr);
-
- ClassKey key(p_namespace, p_name);
-
- GDMonoClass **match = cached_classes.getptr(key);
-
- if (match) {
- return *match;
- }
-
- MonoClass *mono_class = mono_class_from_name(image, String(p_namespace).utf8(), String(p_name).utf8());
-
- if (!mono_class) {
- return nullptr;
- }
-
- GDMonoClass *wrapped_class = memnew(GDMonoClass(p_namespace, p_name, mono_class, this));
-
- cached_classes[key] = wrapped_class;
- cached_raw[mono_class] = wrapped_class;
-
- return wrapped_class;
-}
-
-GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) {
- ERR_FAIL_NULL_V(image, nullptr);
-
- HashMap<MonoClass *, GDMonoClass *>::Iterator match = cached_raw.find(p_mono_class);
-
- if (match) {
- return match->value;
- }
-
- StringName namespace_name = String::utf8(mono_class_get_namespace(p_mono_class));
- StringName class_name = String::utf8(mono_class_get_name(p_mono_class));
-
- GDMonoClass *wrapped_class = memnew(GDMonoClass(namespace_name, class_name, p_mono_class, this));
-
- cached_classes[ClassKey(namespace_name, class_name)] = wrapped_class;
- cached_raw[p_mono_class] = wrapped_class;
-
- return wrapped_class;
-}
-
GDMonoAssembly *GDMonoAssembly::load(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs) {
if (GDMono::get_singleton()->get_corlib_assembly() && (p_name == "mscorlib" || p_name == "mscorlib.dll")) {
return GDMono::get_singleton()->get_corlib_assembly();
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 0a3ae6c4fe..f67a3e0f25 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -40,47 +40,14 @@
#include "gd_mono_utils.h"
class GDMonoAssembly {
- struct ClassKey {
- struct Hasher {
- static _FORCE_INLINE_ uint32_t hash(const ClassKey &p_key) {
- uint32_t hash = 0;
-
- GDMonoUtils::hash_combine(hash, p_key.namespace_name.hash());
- GDMonoUtils::hash_combine(hash, p_key.class_name.hash());
-
- return hash;
- }
- };
-
- _FORCE_INLINE_ bool operator==(const ClassKey &p_a) const {
- return p_a.class_name == class_name && p_a.namespace_name == namespace_name;
- }
-
- ClassKey() {}
-
- ClassKey(const StringName &p_namespace_name, const StringName &p_class_name) {
- namespace_name = p_namespace_name;
- class_name = p_class_name;
- }
-
- StringName namespace_name;
- StringName class_name;
- };
-
String name;
MonoImage *image = nullptr;
MonoAssembly *assembly = nullptr;
- bool attrs_fetched = false;
- MonoCustomAttrInfo *attributes = nullptr;
-
#ifdef GD_MONO_HOT_RELOAD
uint64_t modified_time = 0;
#endif
- HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes;
- HashMap<MonoClass *, GDMonoClass *> cached_raw;
-
static Vector<String> search_dirs;
static void assembly_load_hook(MonoAssembly *assembly, void *user_data);
@@ -111,14 +78,6 @@ public:
String get_path() const;
- bool has_attribute(GDMonoClass *p_attr_class);
- MonoObject *get_attribute(GDMonoClass *p_attr_class);
-
- void fetch_attributes();
-
- GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_name);
- GDMonoClass *get_class(MonoClass *p_mono_class);
-
static String find_assembly(const String &p_name);
static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String(), const String &p_custom_bcl_dir = String());
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index 54e49cf5f5..37c8e7d021 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -31,210 +31,76 @@
#include "gd_mono_cache.h"
#include "gd_mono.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_method.h"
#include "gd_mono_utils.h"
namespace GDMonoCache {
CachedData cached_data;
-#define CACHE_AND_CHECK(m_var, m_val) \
- { \
- CRASH_COND(m_var != nullptr); \
- m_var = m_val; \
- ERR_FAIL_COND_MSG(m_var == nullptr, "Mono Cache: Member " #m_var " is null."); \
- }
+static MonoMethod *get_mono_method(MonoClass *p_mono_class, const char *p_method_name, int p_param_count) {
+ ERR_FAIL_NULL_V(p_mono_class, nullptr);
+ return mono_class_get_method_from_name(p_mono_class, p_method_name, p_param_count);
+}
+
+static MonoClass *get_mono_class(GDMonoAssembly *p_assembly, const char *p_namespace, const char *p_name) {
+ ERR_FAIL_NULL_V(p_assembly->get_image(), nullptr);
+ return mono_class_from_name(p_assembly->get_image(), p_namespace, p_name);
+}
-#define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_class, m_val)
-#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(cached_data.field_##m_class##_##m_field, m_val)
-#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(cached_data.method_##m_class##_##m_method, m_val)
-#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(cached_data.property_##m_class##_##m_property, m_val)
-
-#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \
- { \
- CRASH_COND(!m_var.is_null()); \
- ERR_FAIL_COND_MSG(m_val == nullptr, "Mono Cache: Method for member " #m_var " is null."); \
- m_var.set_from_method(m_val); \
- ERR_FAIL_COND_MSG(m_var.is_null(), "Mono Cache: Member " #m_var " is null."); \
+void update_godot_api_cache() {
+#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \
+ { \
+ CRASH_COND(!m_var.is_null()); \
+ val = m_val; \
+ ERR_FAIL_COND_MSG(val == nullptr, "Mono Cache: Method for member " #m_var " is null."); \
+ m_var.set_from_method(val); \
+ ERR_FAIL_COND_MSG(m_var.is_null(), "Mono Cache: Member " #m_var " is null."); \
}
#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_METHOD_THUNK_AND_CHECK_IMPL(cached_data.methodthunk_##m_class##_##m_method, m_val)
-void CachedData::clear_corlib_cache() {
- corlib_cache_updated = false;
+#define GODOT_API_CLASS(m_class) (get_mono_class(GDMono::get_singleton()->get_core_api_assembly(), BINDINGS_NAMESPACE, #m_class))
+#define GODOT_API_BRIDGE_CLASS(m_class) (get_mono_class(GDMono::get_singleton()->get_core_api_assembly(), BINDINGS_NAMESPACE_BRIDGE, #m_class))
- class_MonoObject = nullptr;
- class_String = nullptr;
+ MonoMethod *val = nullptr;
-#ifdef DEBUG_ENABLED
- class_System_Diagnostics_StackTrace = nullptr;
- methodthunk_System_Diagnostics_StackTrace_GetFrames.nullify();
- method_System_Diagnostics_StackTrace_ctor_bool = nullptr;
- method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr;
-#endif
+ CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, get_mono_method(GODOT_API_CLASS(SignalAwaiter), "SignalCallback", 4));
- class_KeyNotFoundException = nullptr;
-}
+ CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, InvokeWithVariantArgs, get_mono_method(GODOT_API_CLASS(DelegateUtils), "InvokeWithVariantArgs", 4));
+ CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, DelegateEquals, get_mono_method(GODOT_API_CLASS(DelegateUtils), "DelegateEquals", 2));
-void CachedData::clear_godot_api_cache() {
- godot_api_cache_updated = false;
-
- class_GodotObject = nullptr;
- class_GodotResource = nullptr;
- class_Node = nullptr;
- class_Control = nullptr;
- class_Callable = nullptr;
- class_SignalInfo = nullptr;
- class_ISerializationListener = nullptr;
-
-#ifdef DEBUG_ENABLED
- class_DebuggingUtils = nullptr;
- methodthunk_DebuggingUtils_GetStackFrameInfo.nullify();
-#endif
-
- class_ExportAttribute = nullptr;
- field_ExportAttribute_hint = nullptr;
- field_ExportAttribute_hintString = nullptr;
- class_SignalAttribute = nullptr;
- class_ToolAttribute = nullptr;
- class_RPCAttribute = nullptr;
- property_RPCAttribute_Mode = nullptr;
- property_RPCAttribute_CallLocal = nullptr;
- property_RPCAttribute_TransferMode = nullptr;
- property_RPCAttribute_TransferChannel = nullptr;
- class_GodotMethodAttribute = nullptr;
- field_GodotMethodAttribute_methodName = nullptr;
- class_ScriptPathAttribute = nullptr;
- field_ScriptPathAttribute_path = nullptr;
- class_AssemblyHasScriptsAttribute = nullptr;
- field_AssemblyHasScriptsAttribute_requiresLookup = nullptr;
- field_AssemblyHasScriptsAttribute_scriptTypes = nullptr;
-
- field_GodotObject_ptr = nullptr;
-
- methodthunk_GodotObject_Dispose.nullify();
- methodthunk_SignalAwaiter_SignalCallback.nullify();
-
- methodthunk_Delegate_Equals.nullify();
-
- methodthunk_DelegateUtils_TrySerializeDelegateWithGCHandle.nullify();
- methodthunk_DelegateUtils_TryDeserializeDelegateWithGCHandle.nullify();
- methodthunk_DelegateUtils_TrySerializeDelegate.nullify();
- methodthunk_DelegateUtils_TryDeserializeDelegate.nullify();
- methodthunk_DelegateUtils_InvokeWithVariantArgs.nullify();
- methodthunk_DelegateUtils_DelegateEquals.nullify();
- methodthunk_DelegateUtils_FreeGCHandle.nullify();
-
- methodthunk_Marshaling_managed_to_variant_type.nullify();
- methodthunk_Marshaling_try_get_array_element_type.nullify();
- methodthunk_Marshaling_variant_to_mono_object_of_type.nullify();
- methodthunk_Marshaling_variant_to_mono_object.nullify();
- methodthunk_Marshaling_mono_object_to_variant_out.nullify();
-
- methodthunk_Marshaling_SetFieldValue.nullify();
-
- methodthunk_MarshalUtils_TypeHasFlagsAttribute.nullify();
-}
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, FrameCallback, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "FrameCallback", 0));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, CreateManagedForGodotObjectBinding, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "CreateManagedForGodotObjectBinding", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, CreateManagedForGodotObjectScriptInstance, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "CreateManagedForGodotObjectScriptInstance", 4));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, GetScriptNativeName, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "GetScriptNativeName", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, LookupScriptsInAssembly, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "LookupScriptsInAssembly", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, SetGodotObjectPtr, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "SetGodotObjectPtr", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, RaiseEventSignal, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "RaiseEventSignal", 5));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, GetScriptSignalList, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "GetScriptSignalList", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, HasScriptSignal, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "HasScriptSignal", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, HasMethodUnknownParams, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "HasMethodUnknownParams", 3));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, ScriptIsOrInherits, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "ScriptIsOrInherits", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, AddScriptBridge, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "AddScriptBridge", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, RemoveScriptBridge, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "RemoveScriptBridge", 1));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, UpdateScriptClassInfo, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "UpdateScriptClassInfo", 3));
+ CACHE_METHOD_THUNK_AND_CHECK(ScriptManagerBridge, SwapGCHandleForType, get_mono_method(GODOT_API_BRIDGE_CLASS(ScriptManagerBridge), "SwapGCHandleForType", 3));
-#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
+ CACHE_METHOD_THUNK_AND_CHECK(CSharpInstanceBridge, Call, get_mono_method(GODOT_API_BRIDGE_CLASS(CSharpInstanceBridge), "Call", 6));
+ CACHE_METHOD_THUNK_AND_CHECK(CSharpInstanceBridge, Set, get_mono_method(GODOT_API_BRIDGE_CLASS(CSharpInstanceBridge), "Set", 3));
+ CACHE_METHOD_THUNK_AND_CHECK(CSharpInstanceBridge, Get, get_mono_method(GODOT_API_BRIDGE_CLASS(CSharpInstanceBridge), "Get", 3));
+ CACHE_METHOD_THUNK_AND_CHECK(CSharpInstanceBridge, CallDispose, get_mono_method(GODOT_API_BRIDGE_CLASS(CSharpInstanceBridge), "CallDispose", 2));
+ CACHE_METHOD_THUNK_AND_CHECK(CSharpInstanceBridge, CallToString, get_mono_method(GODOT_API_BRIDGE_CLASS(CSharpInstanceBridge), "CallToString", 3));
-void update_corlib_cache() {
- CACHE_CLASS_AND_CHECK(MonoObject, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_object_class()));
- CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class()));
+ CACHE_METHOD_THUNK_AND_CHECK(GCHandleBridge, FreeGCHandle, get_mono_method(GODOT_API_BRIDGE_CLASS(GCHandleBridge), "FreeGCHandle", 1));
-#ifdef DEBUG_ENABLED
- CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace"));
- CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method("GetFrames"));
- CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(bool)", true));
- CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true));
-#endif
-
- CACHE_METHOD_THUNK_AND_CHECK(Delegate, Equals, GDMono::get_singleton()->get_corlib_assembly()->get_class("System", "Delegate")->get_method_with_desc("System.Delegate:Equals(object)", true));
-
- CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException"));
-
- cached_data.corlib_cache_updated = true;
-}
-
-void update_godot_api_cache() {
- CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object));
- CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource));
- CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node));
- CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
- CACHE_CLASS_AND_CHECK(Callable, GODOT_API_CLASS(Callable));
- CACHE_CLASS_AND_CHECK(SignalInfo, GODOT_API_CLASS(SignalInfo));
- CACHE_CLASS_AND_CHECK(ISerializationListener, GODOT_API_CLASS(ISerializationListener));
-
-#ifdef DEBUG_ENABLED
- CACHE_CLASS_AND_CHECK(DebuggingUtils, GODOT_API_CLASS(DebuggingUtils));
-#endif
-
- // Attributes
- CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute));
- CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint"));
- CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString"));
- CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute));
- CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
- CACHE_CLASS_AND_CHECK(RPCAttribute, GODOT_API_CLASS(RPCAttribute));
- CACHE_PROPERTY_AND_CHECK(RPCAttribute, Mode, CACHED_CLASS(RPCAttribute)->get_property("Mode"));
- CACHE_PROPERTY_AND_CHECK(RPCAttribute, CallLocal, CACHED_CLASS(RPCAttribute)->get_property("CallLocal"));
- CACHE_PROPERTY_AND_CHECK(RPCAttribute, TransferMode, CACHED_CLASS(RPCAttribute)->get_property("TransferMode"));
- CACHE_PROPERTY_AND_CHECK(RPCAttribute, TransferChannel, CACHED_CLASS(RPCAttribute)->get_property("TransferChannel"));
- CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
- CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
- CACHE_CLASS_AND_CHECK(ScriptPathAttribute, GODOT_API_CLASS(ScriptPathAttribute));
- CACHE_FIELD_AND_CHECK(ScriptPathAttribute, path, CACHED_CLASS(ScriptPathAttribute)->get_field("path"));
- CACHE_CLASS_AND_CHECK(AssemblyHasScriptsAttribute, GODOT_API_CLASS(AssemblyHasScriptsAttribute));
- CACHE_FIELD_AND_CHECK(AssemblyHasScriptsAttribute, requiresLookup, CACHED_CLASS(AssemblyHasScriptsAttribute)->get_field("requiresLookup"));
- CACHE_FIELD_AND_CHECK(AssemblyHasScriptsAttribute, scriptTypes, CACHED_CLASS(AssemblyHasScriptsAttribute)->get_field("scriptTypes"));
-
- CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD));
-
- 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(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));
- CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TrySerializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TrySerializeDelegate", 2));
- CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TryDeserializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TryDeserializeDelegate", 2));
- CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, InvokeWithVariantArgs, GODOT_API_CLASS(DelegateUtils)->get_method("InvokeWithVariantArgs", 4));
- CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, DelegateEquals, GODOT_API_CLASS(DelegateUtils)->get_method("DelegateEquals", 2));
- CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, FreeGCHandle, GODOT_API_CLASS(DelegateUtils)->get_method("FreeGCHandle", 1));
-
- GDMonoClass *gd_mono_marshal_class = GDMono::get_singleton()->get_core_api_assembly()->get_class(
- "Godot.NativeInterop", "Marshaling");
-
- ERR_FAIL_COND_MSG(gd_mono_marshal_class == nullptr,
- "Mono Cache: Class `Godot.NativeInterop.Marshaling` not found.");
-
- CACHE_METHOD_THUNK_AND_CHECK(Marshaling, managed_to_variant_type,
- gd_mono_marshal_class->get_method("managed_to_variant_type", 2));
- CACHE_METHOD_THUNK_AND_CHECK(Marshaling, try_get_array_element_type,
- gd_mono_marshal_class->get_method("try_get_array_element_type", 2));
- CACHE_METHOD_THUNK_AND_CHECK(Marshaling, variant_to_mono_object_of_type,
- gd_mono_marshal_class->get_method("variant_to_mono_object_of_type", 2));
- CACHE_METHOD_THUNK_AND_CHECK(Marshaling, variant_to_mono_object,
- gd_mono_marshal_class->get_method("variant_to_mono_object", 1));
- CACHE_METHOD_THUNK_AND_CHECK(Marshaling, mono_object_to_variant_out,
- gd_mono_marshal_class->get_method("mono_object_to_variant_out", 3));
-
- CACHE_METHOD_THUNK_AND_CHECK(Marshaling, SetFieldValue,
- gd_mono_marshal_class->get_method("SetFieldValue", 3));
-
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeHasFlagsAttribute, GODOT_API_CLASS(MarshalUtils)->get_method("TypeHasFlagsAttribute", 1));
-
-#ifdef DEBUG_ENABLED
- CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4));
-#endif
+ CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, InstallTraceListener, get_mono_method(GODOT_API_CLASS(DebuggingUtils), "InstallTraceListener", 0));
MonoException *exc = nullptr;
- GDMono::get_singleton()
- ->get_core_api_assembly()
- ->get_class("Godot", "Dispatcher")
- ->get_method("InitializeDefaultGodotTaskScheduler")
- ->invoke(nullptr, &exc);
+ MonoMethod *init_default_godot_task_scheduler =
+ get_mono_method(GODOT_API_CLASS(Dispatcher), "InitializeDefaultGodotTaskScheduler", 0);
+ ERR_FAIL_COND_MSG(init_default_godot_task_scheduler == nullptr,
+ "Mono Cache: InitializeDefaultGodotTaskScheduler is null.");
+ mono_runtime_invoke(init_default_godot_task_scheduler, nullptr, nullptr, (MonoObject **)&exc);
if (exc) {
GDMonoUtils::debug_unhandled_exception(exc);
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 5876583260..5785347938 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -31,115 +31,57 @@
#ifndef GD_MONO_CACHE_H
#define GD_MONO_CACHE_H
-#include "gd_mono_header.h"
#include "gd_mono_method_thunk.h"
+class CSharpScript;
+
namespace GDMonoCache {
struct CachedData {
- // -----------------------------------------------
- // corlib classes
-
- // Let's use the no-namespace format for these too
- GDMonoClass *class_MonoObject = nullptr; // object
- GDMonoClass *class_String = nullptr; // string
-
-#ifdef DEBUG_ENABLED
- GDMonoClass *class_System_Diagnostics_StackTrace = nullptr;
- GDMonoMethodThunkR<MonoArray *, MonoObject *> methodthunk_System_Diagnostics_StackTrace_GetFrames;
- GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool = nullptr;
- GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr;
-#endif
-
- GDMonoClass *class_KeyNotFoundException = nullptr;
- // -----------------------------------------------
-
- GDMonoClass *class_GodotObject = nullptr;
- GDMonoClass *class_GodotResource = nullptr;
- GDMonoClass *class_Node = nullptr;
- GDMonoClass *class_Control = nullptr;
- GDMonoClass *class_Callable = nullptr;
- GDMonoClass *class_SignalInfo = nullptr;
- GDMonoClass *class_ISerializationListener = nullptr;
-
-#ifdef DEBUG_ENABLED
- GDMonoClass *class_DebuggingUtils = nullptr;
- GDMonoMethodThunk<MonoObject *, MonoString **, int *, MonoString **> methodthunk_DebuggingUtils_GetStackFrameInfo;
-#endif
-
- GDMonoClass *class_ExportAttribute = nullptr;
- GDMonoField *field_ExportAttribute_hint = nullptr;
- GDMonoField *field_ExportAttribute_hintString = nullptr;
- GDMonoClass *class_SignalAttribute = nullptr;
- GDMonoClass *class_ToolAttribute = nullptr;
- GDMonoClass *class_RPCAttribute = nullptr;
- GDMonoProperty *property_RPCAttribute_Mode = nullptr;
- GDMonoProperty *property_RPCAttribute_CallLocal = nullptr;
- GDMonoProperty *property_RPCAttribute_TransferMode = nullptr;
- GDMonoProperty *property_RPCAttribute_TransferChannel = nullptr;
- GDMonoClass *class_GodotMethodAttribute = nullptr;
- GDMonoField *field_GodotMethodAttribute_methodName = nullptr;
- GDMonoClass *class_ScriptPathAttribute = nullptr;
- GDMonoField *field_ScriptPathAttribute_path = nullptr;
- GDMonoClass *class_AssemblyHasScriptsAttribute = nullptr;
- GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup = nullptr;
- GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes = nullptr;
-
-
- GDMonoField *field_GodotObject_ptr = nullptr;
-
- GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose;
- GDMonoMethodThunk<MonoObject *, MonoArray *> methodthunk_SignalAwaiter_SignalCallback;
-
- GDMonoMethodThunkR<MonoBoolean, MonoObject *, MonoObject *> methodthunk_Delegate_Equals;
-
- GDMonoMethodThunkR<MonoBoolean, void *, MonoObject *> methodthunk_DelegateUtils_TrySerializeDelegateWithGCHandle;
- GDMonoMethodThunkR<MonoBoolean, MonoObject *, void **> methodthunk_DelegateUtils_TryDeserializeDelegateWithGCHandle;
-
- GDMonoMethodThunkR<MonoBoolean, MonoDelegate *, MonoObject *> methodthunk_DelegateUtils_TrySerializeDelegate;
- GDMonoMethodThunkR<MonoBoolean, MonoObject *, MonoDelegate **> methodthunk_DelegateUtils_TryDeserializeDelegate;
-
- GDMonoMethodThunk<void *, const Variant **, uint32_t, const Variant *> methodthunk_DelegateUtils_InvokeWithVariantArgs;
- GDMonoMethodThunkR<MonoBoolean, void *, void *> methodthunk_DelegateUtils_DelegateEquals;
- GDMonoMethodThunk<void *> methodthunk_DelegateUtils_FreeGCHandle;
-
- GDMonoMethodThunkR<int32_t, MonoReflectionType *, MonoBoolean *> methodthunk_Marshaling_managed_to_variant_type;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *, MonoReflectionType **> methodthunk_Marshaling_try_get_array_element_type;
- GDMonoMethodThunkR<MonoObject *, const Variant *, MonoReflectionType *> methodthunk_Marshaling_variant_to_mono_object_of_type;
- GDMonoMethodThunkR<MonoObject *, const Variant *> methodthunk_Marshaling_variant_to_mono_object;
- GDMonoMethodThunk<MonoObject *, MonoBoolean, Variant *> methodthunk_Marshaling_mono_object_to_variant_out;
-
- GDMonoMethodThunk<MonoReflectionField *, MonoObject *, const Variant *> methodthunk_Marshaling_SetFieldValue;
-
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeHasFlagsAttribute;
-
- bool corlib_cache_updated;
- bool godot_api_cache_updated;
-
- void clear_corlib_cache();
- void clear_godot_api_cache();
-
- CachedData() {
- clear_corlib_cache();
- clear_godot_api_cache();
- }
+ // Mono method thunks require structs to be boxed, even if passed by ref (out, ref, in).
+ // As such we need to use pointers instead for now, instead of by ref parameters.
+
+ GDMonoMethodThunk<GCHandleIntPtr, const Variant **, int, bool *> methodthunk_SignalAwaiter_SignalCallback;
+
+ GDMonoMethodThunk<GCHandleIntPtr, const Variant **, uint32_t, const Variant *> methodthunk_DelegateUtils_InvokeWithVariantArgs;
+ GDMonoMethodThunkR<bool, GCHandleIntPtr, GCHandleIntPtr> methodthunk_DelegateUtils_DelegateEquals;
+
+ GDMonoMethodThunk<> methodthunk_ScriptManagerBridge_FrameCallback;
+ GDMonoMethodThunkR<GCHandleIntPtr, const StringName *, Object *> methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectBinding;
+ GDMonoMethodThunk<const CSharpScript *, Object *, const Variant **, int> methodthunk_ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance;
+ GDMonoMethodThunk<const CSharpScript *, StringName *> methodthunk_ScriptManagerBridge_GetScriptNativeName;
+ GDMonoMethodThunk<MonoReflectionAssembly *> methodthunk_ScriptManagerBridge_LookupScriptsInAssembly;
+ GDMonoMethodThunk<GCHandleIntPtr, Object *> methodthunk_ScriptManagerBridge_SetGodotObjectPtr;
+ GDMonoMethodThunk<GCHandleIntPtr, const StringName *, const Variant **, int, bool *> methodthunk_ScriptManagerBridge_RaiseEventSignal;
+ GDMonoMethodThunk<const CSharpScript *, Dictionary *> methodthunk_ScriptManagerBridge_GetScriptSignalList;
+ GDMonoMethodThunkR<bool, const CSharpScript *, const String *> methodthunk_ScriptManagerBridge_HasScriptSignal;
+ GDMonoMethodThunkR<bool, const CSharpScript *, const String *, bool> methodthunk_ScriptManagerBridge_HasMethodUnknownParams;
+ GDMonoMethodThunkR<bool, const CSharpScript *, const CSharpScript *> methodthunk_ScriptManagerBridge_ScriptIsOrInherits;
+ GDMonoMethodThunkR<bool, const CSharpScript *, const String *> methodthunk_ScriptManagerBridge_AddScriptBridge;
+ GDMonoMethodThunk<const CSharpScript *> methodthunk_ScriptManagerBridge_RemoveScriptBridge;
+ GDMonoMethodThunk<const CSharpScript *, bool *, Dictionary *> methodthunk_ScriptManagerBridge_UpdateScriptClassInfo;
+ GDMonoMethodThunkR<bool, GCHandleIntPtr, GCHandleIntPtr *, bool> methodthunk_ScriptManagerBridge_SwapGCHandleForType;
+
+ GDMonoMethodThunk<GCHandleIntPtr, const StringName *, const Variant **, int, Callable::CallError *, Variant *> methodthunk_CSharpInstanceBridge_Call;
+ GDMonoMethodThunkR<bool, GCHandleIntPtr, const StringName *, const Variant *> methodthunk_CSharpInstanceBridge_Set;
+ GDMonoMethodThunkR<bool, GCHandleIntPtr, const StringName *, Variant *> methodthunk_CSharpInstanceBridge_Get;
+ GDMonoMethodThunk<GCHandleIntPtr, bool> methodthunk_CSharpInstanceBridge_CallDispose;
+ GDMonoMethodThunk<GCHandleIntPtr, String *, bool *> methodthunk_CSharpInstanceBridge_CallToString;
+
+ GDMonoMethodThunk<GCHandleIntPtr> methodthunk_GCHandleBridge_FreeGCHandle;
+
+ GDMonoMethodThunk<> methodthunk_DebuggingUtils_InstallTraceListener;
+
+ bool godot_api_cache_updated = false;
};
extern CachedData cached_data;
-void update_corlib_cache();
void update_godot_api_cache();
inline void clear_godot_api_cache() {
- cached_data.clear_godot_api_cache();
+ cached_data = CachedData();
}
} // namespace GDMonoCache
-#define CACHED_CLASS(m_class) (GDMonoCache::cached_data.class_##m_class)
-#define CACHED_CLASS_RAW(m_class) (GDMonoCache::cached_data.class_##m_class->get_mono_ptr())
-#define CACHED_FIELD(m_class, m_field) (GDMonoCache::cached_data.field_##m_class##_##m_field)
-#define CACHED_METHOD(m_class, m_method) (GDMonoCache::cached_data.method_##m_class##_##m_method)
-#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoCache::cached_data.methodthunk_##m_class##_##m_method)
-#define CACHED_PROPERTY(m_class, m_property) (GDMonoCache::cached_data.property_##m_class##_##m_property)
-
#endif // GD_MONO_CACHE_H
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
deleted file mode 100644
index 24b46d2ce8..0000000000
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ /dev/null
@@ -1,569 +0,0 @@
-/*************************************************************************/
-/* gd_mono_class.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 "gd_mono_class.h"
-
-#include <mono/metadata/attrdefs.h>
-#include <mono/metadata/debug-helpers.h>
-
-#include "gd_mono_assembly.h"
-#include "gd_mono_cache.h"
-#include "gd_mono_marshal.h"
-
-String GDMonoClass::get_full_name(MonoClass *p_mono_class) {
- // mono_type_get_full_name is not exposed to embedders, but this seems to do the job
- MonoReflectionType *type_obj = mono_type_get_object(mono_domain_get(), get_mono_type(p_mono_class));
-
- MonoException *exc = nullptr;
- MonoString *str = GDMonoUtils::object_to_string((MonoObject *)type_obj, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return GDMonoMarshal::mono_string_to_godot(str);
-}
-
-MonoType *GDMonoClass::get_mono_type(MonoClass *p_mono_class) {
- return mono_class_get_type(p_mono_class);
-}
-
-String GDMonoClass::get_full_name() const {
- return get_full_name(mono_class);
-}
-
-String GDMonoClass::get_type_desc() const {
- return GDMonoUtils::get_type_desc(get_mono_type());
-}
-
-MonoType *GDMonoClass::get_mono_type() const {
- // Careful, you cannot compare two MonoType*.
- // There is mono_metadata_type_equal, how is this different from comparing two MonoClass*?
- return get_mono_type(mono_class);
-}
-
-uint32_t GDMonoClass::get_flags() const {
- return mono_class_get_flags(mono_class);
-}
-
-bool GDMonoClass::is_static() const {
- uint32_t static_class_flags = MONO_TYPE_ATTR_ABSTRACT | MONO_TYPE_ATTR_SEALED;
- return (get_flags() & static_class_flags) == static_class_flags;
-}
-
-bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
- return mono_class_is_assignable_from(mono_class, p_from->mono_class);
-}
-
-StringName GDMonoClass::get_namespace() const {
- GDMonoClass *nesting_class = get_nesting_class();
- if (!nesting_class) {
- return namespace_name;
- }
- return nesting_class->get_namespace();
-}
-
-String GDMonoClass::get_name_for_lookup() const {
- GDMonoClass *nesting_class = get_nesting_class();
- if (!nesting_class) {
- return class_name;
- }
- return nesting_class->get_name_for_lookup() + "/" + class_name;
-}
-
-GDMonoClass *GDMonoClass::get_parent_class() const {
- MonoClass *parent_mono_class = mono_class_get_parent(mono_class);
- return parent_mono_class ? GDMono::get_singleton()->get_class(parent_mono_class) : nullptr;
-}
-
-GDMonoClass *GDMonoClass::get_nesting_class() const {
- MonoClass *nesting_type = mono_class_get_nesting_type(mono_class);
- return nesting_type ? GDMono::get_singleton()->get_class(nesting_type) : nullptr;
-}
-
-#ifdef TOOLS_ENABLED
-Vector<MonoClassField *> GDMonoClass::get_enum_fields() {
- bool class_is_enum = mono_class_is_enum(mono_class);
- ERR_FAIL_COND_V(!class_is_enum, Vector<MonoClassField *>());
-
- Vector<MonoClassField *> enum_fields;
-
- void *iter = nullptr;
- MonoClassField *raw_field = nullptr;
- while ((raw_field = mono_class_get_fields(get_mono_ptr(), &iter)) != nullptr) {
- uint32_t field_flags = mono_field_get_flags(raw_field);
-
- // Enums have an instance field named value__ which holds the value of the enum.
- // Enum constants are static, so we will use this to ignore the value__ field.
- if (field_flags & MONO_FIELD_ATTR_PUBLIC && field_flags & MONO_FIELD_ATTR_STATIC) {
- enum_fields.push_back(raw_field);
- }
- }
-
- return enum_fields;
-}
-#endif
-
-bool GDMonoClass::has_attribute(GDMonoClass *p_attr_class) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_NULL_V(p_attr_class, false);
-#endif
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return false;
- }
-
- return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-MonoObject *GDMonoClass::get_attribute(GDMonoClass *p_attr_class) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_NULL_V(p_attr_class, nullptr);
-#endif
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return nullptr;
- }
-
- return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-void GDMonoClass::fetch_attributes() {
- ERR_FAIL_COND(attributes != nullptr);
-
- attributes = mono_custom_attrs_from_class(get_mono_ptr());
- attrs_fetched = true;
-}
-
-void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base) {
- CRASH_COND(!CACHED_CLASS(GodotObject)->is_assignable_from(this));
-
- if (methods_fetched) {
- return;
- }
-
- void *iter = nullptr;
- MonoMethod *raw_method = nullptr;
- while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) {
- StringName name = String::utf8(mono_method_get_name(raw_method));
-
- // get_method implicitly fetches methods and adds them to this->methods
- GDMonoMethod *method = get_method(raw_method, name);
- ERR_CONTINUE(!method);
-
- if (method->get_name() != name) {
-#ifdef DEBUG_ENABLED
- String fullname = method->get_ret_type_full_name() + " " + name + "(" + method->get_signature_desc(true) + ")";
- WARN_PRINT("Method '" + fullname + "' is hidden by Godot API method. Should be '" +
- method->get_full_name_no_class() + "'. In class '" + namespace_name + "." + class_name + "'.");
-#endif
- continue;
- }
-
-#ifdef DEBUG_ENABLED
- // For debug builds, we also fetched from native base classes as well before if this is not a native base class.
- // This allows us to warn the user here if they are using snake_case by mistake.
-
- if (p_native_base != this) {
- GDMonoClass *native_top = p_native_base;
- while (native_top) {
- GDMonoMethod *m = native_top->get_method(name, method->get_parameters_count());
-
- if (m && m->get_name() != name) {
- // found
- String fullname = m->get_ret_type_full_name() + " " + name + "(" + m->get_signature_desc(true) + ")";
- WARN_PRINT("Method '" + fullname + "' should be '" + m->get_full_name_no_class() +
- "'. In class '" + namespace_name + "." + class_name + "'.");
- break;
- }
-
- if (native_top == CACHED_CLASS(GodotObject)) {
- break;
- }
-
- native_top = native_top->get_parent_class();
- }
- }
-#endif
-
- uint32_t flags = mono_method_get_flags(method->mono_method, nullptr);
-
- if (!(flags & MONO_METHOD_ATTR_VIRTUAL)) {
- continue;
- }
-
- // Virtual method of Godot Object derived type, let's try to find GodotMethod attribute
-
- GDMonoClass *top = p_native_base;
-
- while (top) {
- GDMonoMethod *base_method = top->get_method(name, method->get_parameters_count());
-
- if (base_method && base_method->has_attribute(CACHED_CLASS(GodotMethodAttribute))) {
- // Found base method with GodotMethod attribute.
- // We get the original API method name from this attribute.
- // This name must point to the virtual method.
-
- MonoObject *attr = base_method->get_attribute(CACHED_CLASS(GodotMethodAttribute));
-
- StringName godot_method_name = CACHED_FIELD(GodotMethodAttribute, methodName)->get_string_value(attr);
-#ifdef DEBUG_ENABLED
- CRASH_COND(godot_method_name == StringName());
-#endif
- MethodKey key = MethodKey(godot_method_name, method->get_parameters_count());
- GDMonoMethod **existing_method = methods.getptr(key);
- if (existing_method) {
- memdelete(*existing_method); // Must delete old one
- }
- methods.insert(key, method);
-
- break;
- }
-
- if (top == CACHED_CLASS(GodotObject)) {
- break;
- }
-
- top = top->get_parent_class();
- }
- }
-
- methods_fetched = true;
-}
-
-GDMonoMethod *GDMonoClass::get_fetched_method_unknown_params(const StringName &p_name) {
- ERR_FAIL_COND_V(!methods_fetched, nullptr);
-
- for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) {
- if (E.key.name == p_name) {
- return E.value;
- }
- }
-
- return nullptr;
-}
-
-bool GDMonoClass::has_fetched_method_unknown_params(const StringName &p_name) {
- return get_fetched_method_unknown_params(p_name) != nullptr;
-}
-
-bool GDMonoClass::implements_interface(GDMonoClass *p_interface) {
- return mono_class_implements_interface(mono_class, p_interface->get_mono_ptr());
-}
-
-bool GDMonoClass::has_public_parameterless_ctor() {
- GDMonoMethod *ctor = get_method(".ctor", 0);
- return ctor && ctor->get_visibility() == IMonoClassMember::PUBLIC;
-}
-
-GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_params_count) {
- MethodKey key = MethodKey(p_name, p_params_count);
-
- GDMonoMethod **match = methods.getptr(key);
-
- if (match) {
- return *match;
- }
-
- if (methods_fetched) {
- return nullptr;
- }
-
- MonoMethod *raw_method = mono_class_get_method_from_name(mono_class, String(p_name).utf8().get_data(), p_params_count);
-
- if (raw_method) {
- GDMonoMethod *method = memnew(GDMonoMethod(p_name, raw_method));
- methods.insert(key, method);
-
- return method;
- }
-
- return nullptr;
-}
-
-GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method) {
- MonoMethodSignature *sig = mono_method_signature(p_raw_method);
-
- int params_count = mono_signature_get_param_count(sig);
- StringName method_name = String::utf8(mono_method_get_name(p_raw_method));
-
- return get_method(p_raw_method, method_name, params_count);
-}
-
-GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name) {
- MonoMethodSignature *sig = mono_method_signature(p_raw_method);
- int params_count = mono_signature_get_param_count(sig);
- return get_method(p_raw_method, p_name, params_count);
-}
-
-GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count) {
- ERR_FAIL_NULL_V(p_raw_method, nullptr);
-
- MethodKey key = MethodKey(p_name, p_params_count);
-
- GDMonoMethod **match = methods.getptr(key);
-
- if (match) {
- return *match;
- }
-
- GDMonoMethod *method = memnew(GDMonoMethod(p_name, p_raw_method));
- methods.insert(key, method);
-
- return method;
-}
-
-GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, bool p_include_namespace) {
- MonoMethodDesc *desc = mono_method_desc_new(p_description.utf8().get_data(), p_include_namespace);
- MonoMethod *method = mono_method_desc_search_in_class(desc, mono_class);
- mono_method_desc_free(desc);
-
- if (!method) {
- return nullptr;
- }
-
- ERR_FAIL_COND_V(mono_method_get_class(method) != mono_class, nullptr);
-
- return get_method(method);
-}
-
-GDMonoField *GDMonoClass::get_field(const StringName &p_name) {
- HashMap<StringName, GDMonoField *>::Iterator result = fields.find(p_name);
-
- if (result) {
- return result->value;
- }
-
- if (fields_fetched) {
- return nullptr;
- }
-
- MonoClassField *raw_field = mono_class_get_field_from_name(mono_class, String(p_name).utf8().get_data());
-
- if (raw_field) {
- GDMonoField *field = memnew(GDMonoField(raw_field, this));
- fields.insert(p_name, field);
-
- return field;
- }
-
- return nullptr;
-}
-
-const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
- if (fields_fetched) {
- return fields_list;
- }
-
- void *iter = nullptr;
- MonoClassField *raw_field = nullptr;
- while ((raw_field = mono_class_get_fields(mono_class, &iter)) != nullptr) {
- StringName name = String::utf8(mono_field_get_name(raw_field));
-
- HashMap<StringName, GDMonoField *>::Iterator match = fields.find(name);
-
- if (match) {
- fields_list.push_back(match->value);
- } else {
- GDMonoField *field = memnew(GDMonoField(raw_field, this));
- fields.insert(name, field);
- fields_list.push_back(field);
- }
- }
-
- fields_fetched = true;
-
- return fields_list;
-}
-
-GDMonoProperty *GDMonoClass::get_property(const StringName &p_name) {
- HashMap<StringName, GDMonoProperty *>::Iterator result = properties.find(p_name);
-
- if (result) {
- return result->value;
- }
-
- if (properties_fetched) {
- return nullptr;
- }
-
- MonoProperty *raw_property = mono_class_get_property_from_name(mono_class, String(p_name).utf8().get_data());
-
- if (raw_property) {
- GDMonoProperty *property = memnew(GDMonoProperty(raw_property, this));
- properties.insert(p_name, property);
-
- return property;
- }
-
- return nullptr;
-}
-
-const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() {
- if (properties_fetched) {
- return properties_list;
- }
-
- void *iter = nullptr;
- MonoProperty *raw_property = nullptr;
- while ((raw_property = mono_class_get_properties(mono_class, &iter)) != nullptr) {
- StringName name = String::utf8(mono_property_get_name(raw_property));
-
- HashMap<StringName, GDMonoProperty *>::Iterator match = properties.find(name);
-
- if (match) {
- properties_list.push_back(match->value);
- } else {
- GDMonoProperty *property = memnew(GDMonoProperty(raw_property, this));
- properties.insert(name, property);
- properties_list.push_back(property);
- }
- }
-
- properties_fetched = true;
-
- return properties_list;
-}
-
-const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
- if (delegates_fetched) {
- return delegates_list;
- }
-
- // NOTE: Temporarily reverted d28be4d5808947606b8189ae1b2900b8fd2925cf, while we move code to C#
-
- void *iter = nullptr;
- MonoClass *raw_class = nullptr;
- while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != nullptr) {
- if (mono_class_is_delegate(raw_class)) {
- StringName name = String::utf8(mono_class_get_name(raw_class));
-
- HashMap<StringName, GDMonoClass *>::Iterator match = delegates.find(name);
-
- if (match) {
- delegates_list.push_back(match->value);
- } else {
- GDMonoClass *delegate = memnew(GDMonoClass(String::utf8(mono_class_get_namespace(raw_class)), String::utf8(mono_class_get_name(raw_class)), raw_class, assembly));
- delegates.insert(name, delegate);
- delegates_list.push_back(delegate);
- }
- }
- }
-
- delegates_fetched = true;
-
- return delegates_list;
-}
-
-const Vector<GDMonoMethod *> &GDMonoClass::get_all_methods() {
- if (!method_list_fetched) {
- void *iter = nullptr;
- MonoMethod *raw_method = nullptr;
- while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) {
- method_list.push_back(memnew(GDMonoMethod(String::utf8(mono_method_get_name(raw_method)), raw_method)));
- }
-
- method_list_fetched = true;
- }
-
- return method_list;
-}
-
-GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly) {
- namespace_name = p_namespace;
- class_name = p_name;
- mono_class = p_class;
- assembly = p_assembly;
-
- attrs_fetched = false;
- attributes = nullptr;
-
- methods_fetched = false;
- method_list_fetched = false;
- fields_fetched = false;
- properties_fetched = false;
- delegates_fetched = false;
-}
-
-GDMonoClass::~GDMonoClass() {
- if (attributes) {
- mono_custom_attrs_free(attributes);
- }
-
- for (const KeyValue<StringName, GDMonoField *> &E : fields) {
- memdelete(E.value);
- }
-
- for (const KeyValue<StringName, GDMonoProperty *> &E : properties) {
- memdelete(E.value);
- }
-
- {
- // Ugly workaround...
- // We may have duplicated values, because we redirect snake_case methods to PascalCasel (only Godot API methods).
- // This way, we end with both the snake_case name and the PascalCasel name paired with the same method.
- // Therefore, we must avoid deleting the same pointer twice.
-
- int offset = 0;
- Vector<GDMonoMethod *> deleted_methods;
- deleted_methods.resize(methods.size());
-
- for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) {
- GDMonoMethod *method = E.value;
-
- if (method) {
- for (int i = 0; i < offset; i++) {
- if (deleted_methods[i] == method) {
- // Already deleted
- goto already_deleted;
- }
- }
-
- deleted_methods.write[offset] = method;
- ++offset;
-
- memdelete(method);
- }
-
- already_deleted:;
- }
-
- methods.clear();
- }
-
- for (int i = 0; i < method_list.size(); ++i) {
- memdelete(method_list[i]);
- }
-}
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
deleted file mode 100644
index 6b35da30f9..0000000000
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*************************************************************************/
-/* gd_mono_class.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-
-#ifndef GD_MONO_CLASS_H
-#define GD_MONO_CLASS_H
-
-#include "core/string/ustring.h"
-#include "core/templates/rb_map.h"
-
-#include "gd_mono_field.h"
-#include "gd_mono_header.h"
-#include "gd_mono_method.h"
-#include "gd_mono_property.h"
-#include "gd_mono_utils.h"
-
-class GDMonoClass {
- struct MethodKey {
- struct Hasher {
- static _FORCE_INLINE_ uint32_t hash(const MethodKey &p_key) {
- uint32_t hash = 0;
-
- GDMonoUtils::hash_combine(hash, p_key.name.hash());
- GDMonoUtils::hash_combine(hash, HashMapHasherDefault::hash(p_key.params_count));
-
- return hash;
- }
- };
-
- _FORCE_INLINE_ bool operator==(const MethodKey &p_a) const {
- return p_a.params_count == params_count && p_a.name == name;
- }
-
- MethodKey() {}
-
- MethodKey(const StringName &p_name, uint16_t p_params_count) :
- name(p_name), params_count(p_params_count) {
- }
-
- StringName name;
- uint16_t params_count = 0;
- };
-
- StringName namespace_name;
- StringName class_name;
-
- MonoClass *mono_class = nullptr;
- GDMonoAssembly *assembly = nullptr;
-
- bool attrs_fetched;
- MonoCustomAttrInfo *attributes = nullptr;
-
- // This contains both the original method names and remapped method names from the native Godot identifiers to the C# functions.
- // Most method-related functions refer to this and it's possible this is unintuitive for outside users; this may be a prime location for refactoring or renaming.
- bool methods_fetched;
- HashMap<MethodKey, GDMonoMethod *, MethodKey::Hasher> methods;
-
- bool method_list_fetched;
- Vector<GDMonoMethod *> method_list;
-
- bool fields_fetched;
- HashMap<StringName, GDMonoField *> fields;
- Vector<GDMonoField *> fields_list;
-
- bool properties_fetched;
- HashMap<StringName, GDMonoProperty *> properties;
- Vector<GDMonoProperty *> properties_list;
-
- bool delegates_fetched;
- HashMap<StringName, GDMonoClass *> delegates;
- Vector<GDMonoClass *> delegates_list;
-
- friend class GDMonoAssembly;
- GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
-
-public:
- static String get_full_name(MonoClass *p_mono_class);
- static MonoType *get_mono_type(MonoClass *p_mono_class);
-
- String get_full_name() const;
- String get_type_desc() const;
- MonoType *get_mono_type() const;
-
- uint32_t get_flags() const;
- bool is_static() const;
-
- bool is_assignable_from(GDMonoClass *p_from) const;
-
- StringName get_namespace() const;
- _FORCE_INLINE_ StringName get_name() const { return class_name; }
- String get_name_for_lookup() const;
-
- _FORCE_INLINE_ MonoClass *get_mono_ptr() const { return mono_class; }
- _FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; }
-
- GDMonoClass *get_parent_class() const;
- GDMonoClass *get_nesting_class() const;
-
-#ifdef TOOLS_ENABLED
- Vector<MonoClassField *> get_enum_fields();
-#endif
-
- GDMonoMethod *get_fetched_method_unknown_params(const StringName &p_name);
- bool has_fetched_method_unknown_params(const StringName &p_name);
-
- bool has_attribute(GDMonoClass *p_attr_class);
- MonoObject *get_attribute(GDMonoClass *p_attr_class);
-
- void fetch_attributes();
- void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base);
-
- bool implements_interface(GDMonoClass *p_interface);
- bool has_public_parameterless_ctor();
-
- GDMonoMethod *get_method(const StringName &p_name, uint16_t p_params_count = 0);
- GDMonoMethod *get_method(MonoMethod *p_raw_method);
- GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name);
- GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count);
- GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace);
-
- GDMonoField *get_field(const StringName &p_name);
- const Vector<GDMonoField *> &get_all_fields();
-
- GDMonoProperty *get_property(const StringName &p_name);
- const Vector<GDMonoProperty *> &get_all_properties();
-
- const Vector<GDMonoClass *> &get_all_delegates();
-
- const Vector<GDMonoMethod *> &get_all_methods();
-
- ~GDMonoClass();
-};
-
-#endif // GD_MONO_CLASS_H
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
deleted file mode 100644
index 6beeca79c3..0000000000
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*************************************************************************/
-/* gd_mono_field.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 "gd_mono_field.h"
-
-#include <mono/metadata/attrdefs.h>
-
-#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_utils.h"
-
-void GDMonoField::set_value(MonoObject *p_object, MonoObject *p_value) {
- mono_field_set_value(p_object, mono_field, p_value);
-}
-
-void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
- mono_field_set_value(p_object, mono_field, &p_ptr);
-}
-
-void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) {
- MonoReflectionField *reflfield = mono_field_get_object(mono_domain_get(), owner->get_mono_ptr(), mono_field);
-
- MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(Marshaling, SetFieldValue)
- .invoke(reflfield, p_object, &p_value, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- }
-}
-
-MonoObject *GDMonoField::get_value(MonoObject *p_object) {
- return mono_field_get_value_object(mono_domain_get(), mono_field, p_object);
-}
-
-bool GDMonoField::get_bool_value(MonoObject *p_object) {
- return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object));
-}
-
-int GDMonoField::get_int_value(MonoObject *p_object) {
- return GDMonoMarshal::unbox<int32_t>(get_value(p_object));
-}
-
-String GDMonoField::get_string_value(MonoObject *p_object) {
- MonoObject *val = get_value(p_object);
- return GDMonoMarshal::mono_string_to_godot((MonoString *)val);
-}
-
-bool GDMonoField::has_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, false);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return false;
- }
-
- return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-MonoObject *GDMonoField::get_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, nullptr);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return nullptr;
- }
-
- return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-void GDMonoField::fetch_attributes() {
- ERR_FAIL_COND(attributes != nullptr);
- attributes = mono_custom_attrs_from_field(owner->get_mono_ptr(), mono_field);
- attrs_fetched = true;
-}
-
-bool GDMonoField::is_static() {
- return mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_STATIC;
-}
-
-IMonoClassMember::Visibility GDMonoField::get_visibility() {
- switch (mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_FIELD_ACCESS_MASK) {
- case MONO_FIELD_ATTR_PRIVATE:
- return IMonoClassMember::PRIVATE;
- case MONO_FIELD_ATTR_FAM_AND_ASSEM:
- return IMonoClassMember::PROTECTED_AND_INTERNAL;
- case MONO_FIELD_ATTR_ASSEMBLY:
- return IMonoClassMember::INTERNAL;
- case MONO_FIELD_ATTR_FAMILY:
- return IMonoClassMember::PROTECTED;
- case MONO_FIELD_ATTR_PUBLIC:
- return IMonoClassMember::PUBLIC;
- default:
- ERR_FAIL_V(IMonoClassMember::PRIVATE);
- }
-}
-
-GDMonoField::GDMonoField(MonoClassField *p_mono_field, GDMonoClass *p_owner) {
- owner = p_owner;
- mono_field = p_mono_field;
- name = String::utf8(mono_field_get_name(mono_field));
- MonoType *field_type = mono_field_get_type(mono_field);
- type.type_encoding = mono_type_get_type(field_type);
- MonoClass *field_type_class = mono_class_from_mono_type(field_type);
- type.type_class = GDMono::get_singleton()->get_class(field_type_class);
-
- attrs_fetched = false;
- attributes = nullptr;
-}
-
-GDMonoField::~GDMonoField() {
- if (attributes) {
- mono_custom_attrs_free(attributes);
- }
-}
diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h
deleted file mode 100644
index 1d30f7a369..0000000000
--- a/modules/mono/mono_gd/gd_mono_field.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*************************************************************************/
-/* gd_mono_field.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-
-#ifndef GD_MONO_FIELD_H
-#define GD_MONO_FIELD_H
-
-#include "gd_mono.h"
-#include "gd_mono_header.h"
-#include "i_mono_class_member.h"
-
-class GDMonoField : public IMonoClassMember {
- GDMonoClass *owner = nullptr;
- MonoClassField *mono_field = nullptr;
-
- StringName name;
- ManagedType type;
-
- bool attrs_fetched;
- MonoCustomAttrInfo *attributes = nullptr;
-
-public:
- virtual GDMonoClass *get_enclosing_class() const final { return owner; }
-
- virtual MemberType get_member_type() const final { return MEMBER_TYPE_FIELD; }
-
- virtual StringName get_name() const final { return name; }
-
- virtual bool is_static() final;
- virtual Visibility get_visibility() final;
-
- virtual bool has_attribute(GDMonoClass *p_attr_class) final;
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final;
- void fetch_attributes();
-
- _FORCE_INLINE_ ManagedType get_type() const { return type; }
-
- void set_value(MonoObject *p_object, MonoObject *p_value);
- void set_value_raw(MonoObject *p_object, void *p_ptr);
- void set_value_from_variant(MonoObject *p_object, const Variant &p_value);
-
- MonoObject *get_value(MonoObject *p_object);
-
- bool get_bool_value(MonoObject *p_object);
- int get_int_value(MonoObject *p_object);
- String get_string_value(MonoObject *p_object);
-
- GDMonoField(MonoClassField *p_mono_field, GDMonoClass *p_owner);
- ~GDMonoField();
-};
-
-#endif // GD_MONO_FIELD_H
diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h
deleted file mode 100644
index bf21283080..0000000000
--- a/modules/mono/mono_gd/gd_mono_header.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*************************************************************************/
-/* gd_mono_header.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-
-#ifndef GD_MONO_HEADER_H
-#define GD_MONO_HEADER_H
-
-#include <cstdint>
-
-#ifdef WIN32
-#define GD_MONO_STDCALL __stdcall
-#else
-#define GD_MONO_STDCALL
-#endif
-
-class GDMonoAssembly;
-class GDMonoClass;
-class GDMonoField;
-class GDMonoMethod;
-class GDMonoProperty;
-
-class IMonoClassMember;
-
-#include "managed_type.h"
-
-#endif // GD_MONO_HEADER_H
diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp
index d206b0dfc3..7b5fdef8a3 100644
--- a/modules/mono/mono_gd/gd_mono_internals.cpp
+++ b/modules/mono/mono_gd/gd_mono_internals.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -31,10 +31,7 @@
#include "gd_mono_internals.h"
#include "../csharp_script.h"
-#include "../mono_gc_handle.h"
#include "../utils/macros.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
#include "gd_mono_utils.h"
#include "core/debugger/engine_debugger.h"
@@ -43,77 +40,6 @@
#include <mono/metadata/exception.h>
namespace GDMonoInternals {
-void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
- // This method should not fail
-
- CRASH_COND(!unmanaged);
-
- // All mono objects created from the managed world (e.g.: 'new Player()')
- // need to have a CSharpScript in order for their methods to be callable from the unmanaged side
-
- RefCounted *rc = Object::cast_to<RefCounted>(unmanaged);
-
- GDMonoClass *klass = GDMonoUtils::get_object_class(managed);
-
- CRASH_COND(!klass);
-
- GDMonoClass *native = GDMonoUtils::get_class_native_base(klass);
-
- CRASH_COND(native == nullptr);
-
- if (native == klass) {
- // If it's just a wrapper Godot class and not a custom inheriting class, then attach a
- // script binding instead. One of the advantages of this is that if a script is attached
- // later and it's not a C# script, then the managed object won't have to be disposed.
- // Another reason for doing this is that this instance could outlive CSharpLanguage, which would
- // be problematic when using a script. See: https://github.com/godotengine/godot/issues/25621
-
- CSharpScriptBinding script_binding;
-
- script_binding.inited = true;
- script_binding.type_name = NATIVE_GDMONOCLASS_NAME(klass);
- script_binding.wrapper_class = klass;
- script_binding.gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed);
- script_binding.owner = unmanaged;
-
- if (rc) {
- // Unsafe refcount increment. The managed instance also counts as a reference.
- // This way if the unmanaged world has no references to our owner
- // but the managed instance is alive, the refcount will be 1 instead of 0.
- // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
-
- // May not me referenced yet, so we must use init_ref() instead of reference()
- if (rc->init_ref()) {
- CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
- }
- }
-
- // The object was just created, no script instance binding should have been attached
- CRASH_COND(CSharpLanguage::has_instance_binding(unmanaged));
-
- void *data;
- {
- MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
- data = (void *)CSharpLanguage::get_singleton()->insert_script_binding(unmanaged, script_binding);
- }
-
- // Should be thread safe because the object was just created and nothing else should be referencing it
- CSharpLanguage::set_instance_binding(unmanaged, data);
-
- return;
- }
-
- MonoGCHandleData gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed);
-
- Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass, native);
-
- CRASH_COND(script.is_null());
-
- CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle);
-
- unmanaged->set_script_and_instance(script, csharp_instance);
-}
-
void unhandled_exception(MonoException *p_exc) {
mono_print_unhandled_exception((MonoObject *)p_exc);
gd_unhandled_exception_event(p_exc);
@@ -137,7 +63,7 @@ void gd_unhandled_exception_event(MonoException *p_exc) {
MonoImage *mono_image = GDMono::get_singleton()->get_core_api_assembly()->get_image();
MonoClass *gd_klass = mono_class_from_name(mono_image, "Godot", "GD");
- MonoMethod *unhandled_exception_method = mono_class_get_method_from_name(gd_klass, "OnUnhandledException", -1);
+ MonoMethod *unhandled_exception_method = mono_class_get_method_from_name(gd_klass, "OnUnhandledException", 1);
void *args[1];
args[0] = p_exc;
mono_runtime_invoke(unhandled_exception_method, nullptr, (void **)args, nullptr);
diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h
index a8f9cfa3ca..858c395b78 100644
--- a/modules/mono/mono_gd/gd_mono_internals.h
+++ b/modules/mono/mono_gd/gd_mono_internals.h
@@ -37,9 +37,9 @@
#include "core/object/class_db.h"
-namespace GDMonoInternals {
-void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
+class CSharpScript;
+namespace GDMonoInternals {
/**
* Do not call this function directly.
* Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead.
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
deleted file mode 100644
index 8828ec588b..0000000000
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*************************************************************************/
-/* gd_mono_marshal.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 "gd_mono_marshal.h"
-
-#include "../signal_awaiter_utils.h"
-#include "gd_mono.h"
-#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-
-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;
-
- MonoException *exc = nullptr;
- int32_t ret = CACHED_METHOD_THUNK(Marshaling, managed_to_variant_type)
- .invoke(refltype, &nil_is_variant, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- return Variant::NIL;
- }
-
- if (r_nil_is_variant) {
- *r_nil_is_variant = (bool)nil_is_variant;
- }
-
- return (Variant::Type)ret;
-}
-
-bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type) {
- MonoReflectionType *array_refltype = mono_type_get_object(mono_domain_get(), p_array_type.type_class->get_mono_type());
- MonoReflectionType *elem_refltype = nullptr;
-
- MonoException *exc = nullptr;
- MonoBoolean ret = CACHED_METHOD_THUNK(Marshaling, try_get_array_element_type)
- .invoke(array_refltype, &elem_refltype, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- return Variant::NIL;
- }
-
- r_elem_type = ManagedType::from_reftype(elem_refltype);
- return ret;
-}
-
-MonoObject *variant_to_mono_object_of_type(const Variant &p_var, const ManagedType &p_type) {
- MonoReflectionType *refltype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
-
- MonoException *exc = nullptr;
- MonoObject *ret = CACHED_METHOD_THUNK(Marshaling, variant_to_mono_object_of_type)
- .invoke(&p_var, refltype, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- return nullptr;
- }
-
- return ret;
-}
-
-MonoObject *variant_to_mono_object(const Variant &p_var) {
- MonoException *exc = nullptr;
- MonoObject *ret = CACHED_METHOD_THUNK(Marshaling, variant_to_mono_object)
- .invoke(&p_var, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- return nullptr;
- }
-
- return ret;
-}
-
-static Variant mono_object_to_variant_impl(MonoObject *p_obj, bool p_fail_with_err) {
- if (!p_obj) {
- return Variant();
- }
-
- MonoBoolean fail_with_error = p_fail_with_err;
-
- Variant ret;
-
- MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(Marshaling, mono_object_to_variant_out)
- .invoke(p_obj, fail_with_error, &ret, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- return Variant();
- }
-
- return ret;
-}
-
-Variant mono_object_to_variant(MonoObject *p_obj) {
- return mono_object_to_variant_impl(p_obj, /* fail_with_err: */ true);
-}
-
-Variant mono_object_to_variant_no_err(MonoObject *p_obj) {
- return mono_object_to_variant_impl(p_obj, /* fail_with_err: */ false);
-}
-
-MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array) {
- const String *r = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), length);
-
- for (int i = 0; i < length; i++) {
- MonoString *boxed = mono_string_from_godot(r[i]);
- mono_array_setref(ret, i, boxed);
- }
-
- return ret;
-}
-} // namespace GDMonoMarshal
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
deleted file mode 100644
index fbe5795df5..0000000000
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*************************************************************************/
-/* gd_mono_marshal.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-
-#ifndef GD_MONO_MARSHAL_H
-#define GD_MONO_MARSHAL_H
-
-#include "core/variant/variant.h"
-
-#include "gd_mono.h"
-#include "gd_mono_utils.h"
-
-namespace GDMonoMarshal {
-
-template <typename T>
-T unbox(MonoObject *p_obj) {
- return *(T *)mono_object_unbox(p_obj);
-}
-
-Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant = nullptr);
-
-bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type);
-
-// String
-
-_FORCE_INLINE_ String mono_string_to_godot_not_null(MonoString *p_mono_string) {
- char32_t *utf32 = (char32_t *)mono_string_to_utf32(p_mono_string);
- String ret = String(utf32);
- mono_free(utf32);
- return ret;
-}
-
-_FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) {
- if (p_mono_string == nullptr) {
- return String();
- }
-
- return mono_string_to_godot_not_null(p_mono_string);
-}
-
-_FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) {
- return mono_string_from_utf32((mono_unichar4 *)(p_string.get_data()));
-}
-
-// Variant
-
-MonoObject *variant_to_mono_object_of_type(const Variant &p_var, const ManagedType &p_type);
-
-MonoObject *variant_to_mono_object(const Variant &p_var);
-
-// These overloads were added to avoid passing a `const Variant *` to the `const Variant &`
-// parameter. That would result in the `Variant(bool)` copy constructor being called as
-// pointers are implicitly converted to bool. Implicit conversions are f-ing evil.
-
-_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_type(const Variant *p_var, const ManagedType &p_type) {
- return variant_to_mono_object_of_type(*p_var, p_type);
-}
-_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var) {
- return variant_to_mono_object(*p_var);
-}
-
-Variant mono_object_to_variant(MonoObject *p_obj);
-Variant mono_object_to_variant_no_err(MonoObject *p_obj);
-
-// PackedStringArray
-
-MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array);
-
-} // namespace GDMonoMarshal
-
-#endif // GD_MONO_MARSHAL_H
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
deleted file mode 100644
index 97d3c82230..0000000000
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-/*************************************************************************/
-/* gd_mono_method.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 "gd_mono_method.h"
-
-#include <mono/metadata/attrdefs.h>
-#include <mono/metadata/debug-helpers.h>
-
-#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_utils.h"
-
-void GDMonoMethod::_update_signature() {
- // Apparently MonoMethodSignature needs not to be freed.
- // mono_method_signature caches the result, we don't need to cache it ourselves.
-
- MonoMethodSignature *method_sig = mono_method_signature(mono_method);
- _update_signature(method_sig);
-}
-
-void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
- params_count = mono_signature_get_param_count(p_method_sig);
-
- MonoType *ret_type = mono_signature_get_return_type(p_method_sig);
- if (ret_type) {
- return_type.type_encoding = mono_type_get_type(ret_type);
-
- if (return_type.type_encoding != MONO_TYPE_VOID) {
- MonoClass *ret_type_class = mono_class_from_mono_type(ret_type);
- return_type.type_class = GDMono::get_singleton()->get_class(ret_type_class);
- }
- }
-
- void *iter = nullptr;
- MonoType *param_raw_type;
- while ((param_raw_type = mono_signature_get_params(p_method_sig, &iter)) != nullptr) {
- ManagedType param_type;
-
- param_type.type_encoding = mono_type_get_type(param_raw_type);
-
- MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type);
- param_type.type_class = GDMono::get_singleton()->get_class(param_type_class);
-
- param_types.push_back(param_type);
- }
-
- // clear the cache
- method_info_fetched = false;
- method_info = MethodInfo();
-}
-
-GDMonoClass *GDMonoMethod::get_enclosing_class() const {
- return GDMono::get_singleton()->get_class(mono_method_get_class(mono_method));
-}
-
-bool GDMonoMethod::is_static() {
- return mono_method_get_flags(mono_method, nullptr) & MONO_METHOD_ATTR_STATIC;
-}
-
-IMonoClassMember::Visibility GDMonoMethod::get_visibility() {
- switch (mono_method_get_flags(mono_method, nullptr) & MONO_METHOD_ATTR_ACCESS_MASK) {
- case MONO_METHOD_ATTR_PRIVATE:
- return IMonoClassMember::PRIVATE;
- case MONO_METHOD_ATTR_FAM_AND_ASSEM:
- return IMonoClassMember::PROTECTED_AND_INTERNAL;
- case MONO_METHOD_ATTR_ASSEM:
- return IMonoClassMember::INTERNAL;
- case MONO_METHOD_ATTR_FAMILY:
- return IMonoClassMember::PROTECTED;
- case MONO_METHOD_ATTR_PUBLIC:
- return IMonoClassMember::PUBLIC;
- default:
- ERR_FAIL_V(IMonoClassMember::PRIVATE);
- }
-}
-
-MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc) const {
- MonoException *exc = nullptr;
- MonoObject *ret;
-
- if (params_count > 0) {
- MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count());
-
- for (int i = 0; i < params_count; i++) {
- MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object_of_type(p_params[i], param_types[i]);
- mono_array_setref(params, i, boxed_param);
- }
-
- ret = GDMonoUtils::runtime_invoke_array(mono_method, p_object, params, &exc);
- } else {
- ret = GDMonoUtils::runtime_invoke(mono_method, p_object, nullptr, &exc);
- }
-
- if (exc) {
- ret = nullptr;
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
-
- return ret;
-}
-
-MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoException **r_exc) const {
- ERR_FAIL_COND_V(get_parameters_count() > 0, nullptr);
- return invoke_raw(p_object, nullptr, r_exc);
-}
-
-MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc) const {
- MonoException *exc = nullptr;
- MonoObject *ret = GDMonoUtils::runtime_invoke(mono_method, p_object, p_params, &exc);
-
- if (exc) {
- ret = nullptr;
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
-
- return ret;
-}
-
-bool GDMonoMethod::has_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, false);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return false;
- }
-
- return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-MonoObject *GDMonoMethod::get_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, nullptr);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return nullptr;
- }
-
- return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-void GDMonoMethod::fetch_attributes() {
- ERR_FAIL_COND(attributes != nullptr);
- attributes = mono_custom_attrs_from_method(mono_method);
- attrs_fetched = true;
-}
-
-String GDMonoMethod::get_full_name(bool p_signature) const {
- char *res = mono_method_full_name(mono_method, p_signature);
- String full_name(res);
- mono_free(res);
- return full_name;
-}
-
-String GDMonoMethod::get_full_name_no_class() const {
- String res;
-
- MonoMethodSignature *method_sig = mono_method_signature(mono_method);
-
- char *ret_str = mono_type_full_name(mono_signature_get_return_type(method_sig));
- res += ret_str;
- mono_free(ret_str);
-
- res += " ";
- res += name;
- res += "(";
-
- char *sig_desc = mono_signature_get_desc(method_sig, true);
- res += sig_desc;
- mono_free(sig_desc);
-
- res += ")";
-
- return res;
-}
-
-String GDMonoMethod::get_ret_type_full_name() const {
- MonoMethodSignature *method_sig = mono_method_signature(mono_method);
- char *ret_str = mono_type_full_name(mono_signature_get_return_type(method_sig));
- String res = ret_str;
- mono_free(ret_str);
- return res;
-}
-
-String GDMonoMethod::get_signature_desc(bool p_namespaces) const {
- MonoMethodSignature *method_sig = mono_method_signature(mono_method);
- char *sig_desc = mono_signature_get_desc(method_sig, p_namespaces);
- String res = sig_desc;
- mono_free(sig_desc);
- return res;
-}
-
-void GDMonoMethod::get_parameter_names(Vector<StringName> &names) const {
- if (params_count > 0) {
- const char **_names = memnew_arr(const char *, params_count);
- mono_method_get_param_names(mono_method, _names);
- for (int i = 0; i < params_count; ++i) {
- names.push_back(StringName(_names[i]));
- }
- memdelete_arr(_names);
- }
-}
-
-void GDMonoMethod::get_parameter_types(Vector<ManagedType> &types) const {
- for (int i = 0; i < params_count; ++i) {
- types.push_back(param_types[i]);
- }
-}
-
-const MethodInfo &GDMonoMethod::get_method_info() {
- if (!method_info_fetched) {
- method_info.name = name;
-
- bool nil_is_variant = false;
- 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;
- get_parameter_names(names);
-
- for (int i = 0; i < params_count; ++i) {
- nil_is_variant = false;
- PropertyInfo arg_info = PropertyInfo(GDMonoMarshal::managed_to_variant_type(param_types[i], &nil_is_variant), names[i]);
- if (arg_info.type == Variant::NIL && nil_is_variant) {
- arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- }
-
- method_info.arguments.push_back(arg_info);
- }
-
- // TODO: default arguments
-
- method_info_fetched = true;
- }
-
- return method_info;
-}
-
-GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) :
- name(p_name), mono_method(p_method) {
- _update_signature();
-}
-
-GDMonoMethod::~GDMonoMethod() {
- if (attributes) {
- mono_custom_attrs_free(attributes);
- }
-}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
deleted file mode 100644
index 5398f34103..0000000000
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*************************************************************************/
-/* gd_mono_method.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-
-#ifndef GD_MONO_METHOD_H
-#define GD_MONO_METHOD_H
-
-#include "gd_mono.h"
-#include "gd_mono_header.h"
-#include "i_mono_class_member.h"
-
-class GDMonoMethod : public IMonoClassMember {
- StringName name;
-
- uint16_t params_count;
- ManagedType return_type;
- Vector<ManagedType> param_types;
-
- bool method_info_fetched = false;
- MethodInfo method_info;
-
- bool attrs_fetched = false;
- MonoCustomAttrInfo *attributes = nullptr;
-
- void _update_signature();
- void _update_signature(MonoMethodSignature *p_method_sig);
-
- friend class GDMonoClass;
-
- MonoMethod *mono_method = nullptr;
-
-public:
- virtual GDMonoClass *get_enclosing_class() const final;
-
- virtual MemberType get_member_type() const final { return MEMBER_TYPE_METHOD; }
-
- virtual StringName get_name() const final { return name; }
-
- virtual bool is_static() final;
-
- virtual Visibility get_visibility() final;
-
- virtual bool has_attribute(GDMonoClass *p_attr_class) final;
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final;
- void fetch_attributes();
-
- _FORCE_INLINE_ MonoMethod *get_mono_ptr() const { return mono_method; }
-
- _FORCE_INLINE_ uint16_t get_parameters_count() const { return params_count; }
- _FORCE_INLINE_ ManagedType get_return_type() const { return return_type; }
-
- MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = nullptr) const;
- MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = nullptr) const;
- MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = nullptr) const;
-
- String get_full_name(bool p_signature = false) const;
- String get_full_name_no_class() const;
- String get_ret_type_full_name() const;
- String get_signature_desc(bool p_namespaces = false) const;
-
- void get_parameter_names(Vector<StringName> &names) const;
- void get_parameter_types(Vector<ManagedType> &types) const;
-
- const MethodInfo &get_method_info();
-
- GDMonoMethod(StringName p_name, MonoMethod *p_method);
- ~GDMonoMethod();
-};
-
-#endif // GD_MONO_METHOD_H
diff --git a/modules/mono/mono_gd/gd_mono_method_thunk.h b/modules/mono/mono_gd/gd_mono_method_thunk.h
index 0180dee3ea..aa84a7f2d0 100644
--- a/modules/mono/mono_gd/gd_mono_method_thunk.h
+++ b/modules/mono/mono_gd/gd_mono_method_thunk.h
@@ -31,20 +31,19 @@
#ifndef GD_MONO_METHOD_THUNK_H
#define GD_MONO_METHOD_THUNK_H
+#include <mono/jit/jit.h>
+#include <mono/metadata/attrdefs.h>
#include <type_traits>
-#include "gd_mono_class.h"
-#include "gd_mono_header.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_method.h"
+#include "core/error/error_macros.h"
#include "gd_mono_utils.h"
-#if !defined(JAVASCRIPT_ENABLED) && !defined(IOS_ENABLED)
-#define HAVE_METHOD_THUNKS
+#ifdef WIN32
+#define GD_MONO_STDCALL __stdcall
+#else
+#define GD_MONO_STDCALL
#endif
-#ifdef HAVE_METHOD_THUNKS
-
template <class... ParamTypes>
struct GDMonoMethodThunk {
typedef void(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **);
@@ -58,33 +57,30 @@ public:
GD_MONO_END_RUNTIME_INVOKE;
}
- _FORCE_INLINE_ bool is_null() {
+ bool is_null() {
return mono_method_thunk == nullptr;
}
- _FORCE_INLINE_ void nullify() {
- mono_method_thunk = nullptr;
- }
-
- _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
+ void set_from_method(MonoMethod *p_mono_method) {
#ifdef DEBUG_ENABLED
CRASH_COND(p_mono_method == nullptr);
- CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID);
- if (p_mono_method->is_static()) {
- CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
- } else {
- CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
- }
+ MonoMethodSignature *method_sig = mono_method_signature(p_mono_method);
+ MonoType *ret_type = mono_signature_get_return_type(method_sig);
+ int ret_type_encoding = ret_type ? mono_type_get_type(ret_type) : MONO_TYPE_VOID;
+
+ CRASH_COND(ret_type_encoding != MONO_TYPE_VOID);
+
+ bool is_static = mono_method_get_flags(p_mono_method, nullptr) & MONO_METHOD_ATTR_STATIC;
+ CRASH_COND(!is_static);
+
+ uint32_t parameters_count = mono_signature_get_param_count(method_sig);
+ CRASH_COND(parameters_count != sizeof...(ParamTypes));
#endif
- mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr());
+ mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method);
}
GDMonoMethodThunk() {}
-
- explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) {
- set_from_method(p_mono_method);
- }
};
template <class R, class... ParamTypes>
@@ -101,220 +97,30 @@ public:
return r;
}
- _FORCE_INLINE_ bool is_null() {
+ bool is_null() {
return mono_method_thunk == nullptr;
}
- _FORCE_INLINE_ void nullify() {
- mono_method_thunk = nullptr;
- }
-
- _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == nullptr);
- CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID);
-
- if (p_mono_method->is_static()) {
- CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
- } else {
- CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
- }
-#endif
- mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr());
- }
-
- GDMonoMethodThunkR() {}
-
- explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == nullptr);
-#endif
- mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr());
- }
-};
-
-#else
-
-template <unsigned int ThunkParamCount, class P1, class... ParamTypes>
-struct VariadicInvokeMonoMethodImpl {
- static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) {
- if (p_mono_method->is_static()) {
- void *args[ThunkParamCount] = { p_arg1, p_args... };
- p_mono_method->invoke_raw(nullptr, args, r_exc);
- } else {
- void *args[ThunkParamCount] = { p_args... };
- p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc);
- }
- }
-};
-
-template <unsigned int ThunkParamCount, class... ParamTypes>
-struct VariadicInvokeMonoMethod {
- static void invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) {
- VariadicInvokeMonoMethodImpl<ThunkParamCount, ParamTypes...>::invoke(p_mono_method, p_args..., r_exc);
- }
-};
-
-template <>
-struct VariadicInvokeMonoMethod<0> {
- static void invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!p_mono_method->is_static());
-#endif
- p_mono_method->invoke_raw(nullptr, nullptr, r_exc);
- }
-};
-
-template <class P1>
-struct VariadicInvokeMonoMethod<1, P1> {
- static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) {
- if (p_mono_method->is_static()) {
- void *args[1] = { p_arg1 };
- p_mono_method->invoke_raw(nullptr, args, r_exc);
- } else {
- p_mono_method->invoke_raw((MonoObject *)p_arg1, nullptr, r_exc);
- }
- }
-};
-
-template <class R>
-R unbox_if_needed(MonoObject *p_val, const ManagedType &, typename std::enable_if<!std::is_pointer<R>::value>::type * = 0) {
- return GDMonoMarshal::unbox<R>(p_val);
-}
-
-template <class R>
-R unbox_if_needed(MonoObject *p_val, const ManagedType &p_type, typename std::enable_if<std::is_pointer<R>::value>::type * = 0) {
- if (mono_class_is_valuetype(p_type.type_class->get_mono_ptr())) {
- return GDMonoMarshal::unbox<R>(p_val);
- } else {
- // If it's not a value type, we assume 'R' is a pointer to 'MonoObject' or a compatible type, like 'MonoException'.
- return (R)p_val;
- }
-}
-
-template <unsigned int ThunkParamCount, class R, class P1, class... ParamTypes>
-struct VariadicInvokeMonoMethodRImpl {
- static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) {
- if (p_mono_method->is_static()) {
- void *args[ThunkParamCount] = { p_arg1, p_args... };
- MonoObject *r = p_mono_method->invoke_raw(nullptr, args, r_exc);
- return unbox_if_needed<R>(r, p_mono_method->get_return_type());
- } else {
- void *args[ThunkParamCount] = { p_args... };
- MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc);
- return unbox_if_needed<R>(r, p_mono_method->get_return_type());
- }
- }
-};
-
-template <unsigned int ThunkParamCount, class R, class... ParamTypes>
-struct VariadicInvokeMonoMethodR {
- static R invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) {
- return VariadicInvokeMonoMethodRImpl<ThunkParamCount, R, ParamTypes...>::invoke(p_mono_method, p_args..., r_exc);
- }
-};
-
-template <class R>
-struct VariadicInvokeMonoMethodR<0, R> {
- static R invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!p_mono_method->is_static());
-#endif
- MonoObject *r = p_mono_method->invoke_raw(nullptr, nullptr, r_exc);
- return unbox_if_needed<R>(r, p_mono_method->get_return_type());
- }
-};
-
-template <class R, class P1>
-struct VariadicInvokeMonoMethodR<1, R, P1> {
- static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) {
- if (p_mono_method->is_static()) {
- void *args[1] = { p_arg1 };
- MonoObject *r = p_mono_method->invoke_raw(nullptr, args, r_exc);
- return unbox_if_needed<R>(r, p_mono_method->get_return_type());
- } else {
- MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, nullptr, r_exc);
- return unbox_if_needed<R>(r, p_mono_method->get_return_type());
- }
- }
-};
-
-template <class... ParamTypes>
-struct GDMonoMethodThunk {
- GDMonoMethod *mono_method = nullptr;
-
-public:
- _FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) {
- VariadicInvokeMonoMethod<sizeof...(ParamTypes), ParamTypes...>::invoke(mono_method, p_args..., r_exc);
- }
-
- _FORCE_INLINE_ bool is_null() {
- return mono_method == nullptr;
- }
-
- _FORCE_INLINE_ void nullify() {
- mono_method = nullptr;
- }
-
- _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
+ void set_from_method(MonoMethod *p_mono_method) {
#ifdef DEBUG_ENABLED
CRASH_COND(p_mono_method == nullptr);
- CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID);
- if (p_mono_method->is_static()) {
- CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
- } else {
- CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
- }
-#endif
- mono_method = p_mono_method;
- }
-
- GDMonoMethodThunk() {}
-
- explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) {
- set_from_method(p_mono_method);
- }
-};
+ MonoMethodSignature *method_sig = mono_method_signature(p_mono_method);
+ MonoType *ret_type = mono_signature_get_return_type(method_sig);
+ int ret_type_encoding = ret_type ? mono_type_get_type(ret_type) : MONO_TYPE_VOID;
-template <class R, class... ParamTypes>
-struct GDMonoMethodThunkR {
- GDMonoMethod *mono_method = nullptr;
+ CRASH_COND(ret_type_encoding == MONO_TYPE_VOID);
-public:
- _FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) {
- return VariadicInvokeMonoMethodR<sizeof...(ParamTypes), R, ParamTypes...>::invoke(mono_method, p_args..., r_exc);
- }
+ bool is_static = mono_method_get_flags(p_mono_method, nullptr) & MONO_METHOD_ATTR_STATIC;
+ CRASH_COND(!is_static);
- _FORCE_INLINE_ bool is_null() {
- return mono_method == nullptr;
- }
-
- _FORCE_INLINE_ void nullify() {
- mono_method = nullptr;
- }
-
- _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == nullptr);
- CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID);
-
- if (p_mono_method->is_static()) {
- CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
- } else {
- CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
- }
+ uint32_t parameters_count = mono_signature_get_param_count(method_sig);
+ CRASH_COND(parameters_count != sizeof...(ParamTypes));
#endif
- mono_method = p_mono_method;
+ mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method);
}
GDMonoMethodThunkR() {}
-
- explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) {
- set_from_method(p_mono_method);
- }
};
-#endif
-
#endif // GD_MONO_METHOD_THUNK_H
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
deleted file mode 100644
index 7cbf5be151..0000000000
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*************************************************************************/
-/* gd_mono_property.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 "gd_mono_property.h"
-
-#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_utils.h"
-
-#include <mono/metadata/attrdefs.h>
-
-GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_owner) {
- owner = p_owner;
- mono_property = p_mono_property;
- name = String::utf8(mono_property_get_name(mono_property));
-
- MonoMethod *prop_method = mono_property_get_get_method(mono_property);
-
- if (prop_method) {
- MonoMethodSignature *getter_sig = mono_method_signature(prop_method);
-
- MonoType *ret_type = mono_signature_get_return_type(getter_sig);
-
- type.type_encoding = mono_type_get_type(ret_type);
- MonoClass *ret_type_class = mono_class_from_mono_type(ret_type);
- type.type_class = GDMono::get_singleton()->get_class(ret_type_class);
- } else {
- prop_method = mono_property_get_set_method(mono_property);
-
- MonoMethodSignature *setter_sig = mono_method_signature(prop_method);
-
- void *iter = nullptr;
- MonoType *param_raw_type = mono_signature_get_params(setter_sig, &iter);
-
- type.type_encoding = mono_type_get_type(param_raw_type);
- MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type);
- type.type_class = GDMono::get_singleton()->get_class(param_type_class);
- }
-
- attrs_fetched = false;
- attributes = nullptr;
-}
-
-GDMonoProperty::~GDMonoProperty() {
- if (attributes) {
- mono_custom_attrs_free(attributes);
- }
-}
-
-bool GDMonoProperty::is_static() {
- MonoMethod *prop_method = mono_property_get_get_method(mono_property);
- if (prop_method == nullptr) {
- prop_method = mono_property_get_set_method(mono_property);
- }
- return mono_method_get_flags(prop_method, nullptr) & MONO_METHOD_ATTR_STATIC;
-}
-
-IMonoClassMember::Visibility GDMonoProperty::get_visibility() {
- MonoMethod *prop_method = mono_property_get_get_method(mono_property);
- if (prop_method == nullptr) {
- prop_method = mono_property_get_set_method(mono_property);
- }
-
- switch (mono_method_get_flags(prop_method, nullptr) & MONO_METHOD_ATTR_ACCESS_MASK) {
- case MONO_METHOD_ATTR_PRIVATE:
- return IMonoClassMember::PRIVATE;
- case MONO_METHOD_ATTR_FAM_AND_ASSEM:
- return IMonoClassMember::PROTECTED_AND_INTERNAL;
- case MONO_METHOD_ATTR_ASSEM:
- return IMonoClassMember::INTERNAL;
- case MONO_METHOD_ATTR_FAMILY:
- return IMonoClassMember::PROTECTED;
- case MONO_METHOD_ATTR_PUBLIC:
- return IMonoClassMember::PUBLIC;
- default:
- ERR_FAIL_V(IMonoClassMember::PRIVATE);
- }
-}
-
-bool GDMonoProperty::has_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, false);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return false;
- }
-
- return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-MonoObject *GDMonoProperty::get_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, nullptr);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return nullptr;
- }
-
- return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-void GDMonoProperty::fetch_attributes() {
- ERR_FAIL_COND(attributes != nullptr);
- attributes = mono_custom_attrs_from_property(owner->get_mono_ptr(), mono_property);
- attrs_fetched = true;
-}
-
-bool GDMonoProperty::has_getter() {
- return mono_property_get_get_method(mono_property) != nullptr;
-}
-
-bool GDMonoProperty::has_setter() {
- return mono_property_get_set_method(mono_property) != nullptr;
-}
-
-void GDMonoProperty::set_value_from_variant(MonoObject *p_object, const Variant &p_value, MonoException **r_exc) {
- MonoMethod *set_method = mono_property_get_set_method(mono_property);
- ERR_FAIL_COND(set_method == nullptr);
-
- // Temporary solution, while moving code to C#
- MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
- MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object_of_type(p_value, type);
- mono_array_setref(params, 0, boxed_param);
-
- MonoException *exc = nullptr;
- GDMonoUtils::runtime_invoke_array(set_method, p_object, params, &exc);
- if (exc) {
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
-}
-
-MonoObject *GDMonoProperty::get_value(MonoObject *p_object, MonoException **r_exc) {
- MonoException *exc = nullptr;
- MonoObject *ret = GDMonoUtils::property_get_value(mono_property, p_object, nullptr, &exc);
-
- if (exc) {
- ret = nullptr;
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
-
- return ret;
-}
-
-bool GDMonoProperty::get_bool_value(MonoObject *p_object) {
- return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object));
-}
-
-int GDMonoProperty::get_int_value(MonoObject *p_object) {
- return GDMonoMarshal::unbox<int32_t>(get_value(p_object));
-}
-
-String GDMonoProperty::get_string_value(MonoObject *p_object) {
- MonoObject *val = get_value(p_object);
- return GDMonoMarshal::mono_string_to_godot((MonoString *)val);
-}
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
deleted file mode 100644
index 885ea8f011..0000000000
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*************************************************************************/
-/* gd_mono_property.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-
-#ifndef GD_MONO_PROPERTY_H
-#define GD_MONO_PROPERTY_H
-
-#include "gd_mono.h"
-#include "gd_mono_header.h"
-#include "i_mono_class_member.h"
-
-class GDMonoProperty : public IMonoClassMember {
- GDMonoClass *owner = nullptr;
- MonoProperty *mono_property = nullptr;
-
- StringName name;
- ManagedType type;
-
- bool attrs_fetched;
- MonoCustomAttrInfo *attributes = nullptr;
-
-public:
- virtual GDMonoClass *get_enclosing_class() const final { return owner; }
-
- virtual MemberType get_member_type() const final { return MEMBER_TYPE_PROPERTY; }
-
- virtual StringName get_name() const final { return name; }
-
- virtual bool is_static() final;
- virtual Visibility get_visibility() final;
-
- virtual bool has_attribute(GDMonoClass *p_attr_class) final;
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final;
- void fetch_attributes();
-
- bool has_getter();
- bool has_setter();
-
- _FORCE_INLINE_ ManagedType get_type() const { return type; }
-
- void set_value_from_variant(MonoObject *p_object, const Variant &p_value, MonoException **r_exc = nullptr);
- MonoObject *get_value(MonoObject *p_object, MonoException **r_exc = nullptr);
-
- bool get_bool_value(MonoObject *p_object);
- int get_int_value(MonoObject *p_object);
- String get_string_value(MonoObject *p_object);
-
- GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_owner);
- ~GDMonoProperty();
-};
-
-#endif // GD_MONO_PROPERTY_H
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index e240381112..3e2f4b05d5 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -48,68 +48,9 @@
#include "../utils/macros.h"
#include "gd_mono.h"
#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
namespace GDMonoUtils {
-MonoObject *unmanaged_get_managed(Object *unmanaged) {
- if (!unmanaged) {
- return nullptr;
- }
-
- if (unmanaged->get_script_instance()) {
- CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(unmanaged->get_script_instance());
-
- if (cs_instance) {
- return cs_instance->get_mono_object();
- }
- }
-
- // If the owner does not have a CSharpInstance...
-
- void *data = CSharpLanguage::get_instance_binding(unmanaged);
- ERR_FAIL_NULL_V(data, nullptr);
- CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
- ERR_FAIL_COND_V(!script_binding.inited, nullptr);
-
- MonoGCHandleData &gchandle = script_binding.gchandle;
-
- MonoObject *target = gchandle.get_target();
-
- if (target) {
- return target;
- }
-
- CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
-
- // Create a new one
-
-#ifdef DEBUG_ENABLED
- CRASH_COND(script_binding.type_name == StringName());
- CRASH_COND(script_binding.wrapper_class == nullptr);
-#endif
-
- MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(script_binding.wrapper_class, script_binding.type_name, unmanaged);
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- gchandle = MonoGCHandleData::new_strong_handle(mono_object);
-
- // Tie managed to unmanaged
- RefCounted *rc = Object::cast_to<RefCounted>(unmanaged);
-
- if (rc) {
- // Unsafe refcount increment. The managed instance also counts as a reference.
- // This way if the unmanaged world has no references to our owner
- // but the managed instance is alive, the refcount will be 1 instead of 0.
- // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
- rc->reference();
- CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
- }
-
- return mono_object;
-}
-
void set_main_thread(MonoThread *p_thread) {
mono_thread_set_main(p_thread);
}
@@ -148,90 +89,6 @@ bool is_thread_attached() {
return mono_domain_get() != nullptr;
}
-uint32_t new_strong_gchandle(MonoObject *p_object) {
- return mono_gchandle_new(p_object, /* pinned: */ false);
-}
-
-uint32_t new_strong_gchandle_pinned(MonoObject *p_object) {
- return mono_gchandle_new(p_object, /* pinned: */ true);
-}
-
-uint32_t new_weak_gchandle(MonoObject *p_object) {
- return mono_gchandle_new_weakref(p_object, /* track_resurrection: */ false);
-}
-
-void free_gchandle(uint32_t p_gchandle) {
- mono_gchandle_free(p_gchandle);
-}
-
-void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc) {
- GDMonoMethod *ctor = p_class->get_method(".ctor", 0);
- ERR_FAIL_NULL(ctor);
- ctor->invoke_raw(p_this_obj, nullptr, r_exc);
-}
-
-GDMonoClass *get_object_class(MonoObject *p_object) {
- return GDMono::get_singleton()->get_class(mono_object_get_class(p_object));
-}
-
-GDMonoClass *type_get_proxy_class(const StringName &p_type) {
- String class_name = p_type;
-
- if (class_name[0] == '_') {
- class_name = class_name.substr(1, class_name.length());
- }
-
- GDMonoClass *klass = GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
-
- if (klass && klass->is_static()) {
- // A static class means this is a Godot singleton class. If an instance is needed we use Godot.Object.
- return GDMonoCache::cached_data.class_GodotObject;
- }
-
-#ifdef TOOLS_ENABLED
- if (!klass) {
- return GDMono::get_singleton()->get_editor_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
- }
-#endif
-
- return klass;
-}
-
-GDMonoClass *get_class_native_base(GDMonoClass *p_class) {
- GDMonoClass *klass = p_class;
-
- do {
- const GDMonoAssembly *assembly = klass->get_assembly();
-
- if (assembly == GDMono::get_singleton()->get_core_api_assembly()) {
- return klass;
- }
-#ifdef TOOLS_ENABLED
- if (assembly == GDMono::get_singleton()->get_editor_api_assembly()) {
- return klass;
- }
-#endif
- } while ((klass = klass->get_parent_class()) != nullptr);
-
- return nullptr;
-}
-
-MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) {
- bool parent_is_object_class = ClassDB::is_parent_class(p_object->get_class_name(), p_native);
- ERR_FAIL_COND_V_MSG(!parent_is_object_class, nullptr,
- "Type inherits from native type '" + p_native + "', so it can't be instantiated in object of type: '" + p_object->get_class() + "'.");
-
- MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
-
- // Construct
- GDMonoUtils::runtime_object_init(mono_object, p_class);
-
- return mono_object;
-}
-
MonoDomain *create_domain(const String &p_friendly_name) {
print_verbose("Mono: Creating domain '" + p_friendly_name + "'...");
@@ -247,14 +104,12 @@ MonoDomain *create_domain(const String &p_friendly_name) {
return domain;
}
-String get_type_desc(MonoType *p_type) {
- return mono_type_full_name(p_type);
-}
-
-String get_type_desc(MonoReflectionType *p_reftype) {
- return get_type_desc(mono_reflection_type_get_type(p_reftype));
-}
+// TODO:
+// Implement all of the disabled exception logging below. Once we move to .NET 6.
+// It will have to be done from C# as UnmanagedCallersOnly doesn't allow throwing.
+#warning TODO
+#if 0
String get_exception_name_and_message(MonoException *p_exc) {
String res;
@@ -273,6 +128,7 @@ String get_exception_name_and_message(MonoException *p_exc) {
return res;
}
+#endif
void debug_print_unhandled_exception(MonoException *p_exc) {
print_unhandled_exception(p_exc);
@@ -284,7 +140,10 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
if (!EngineDebugger::is_active()) {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
+#warning TODO
+#if 0
ERR_PRINT(GDMonoUtils::get_exception_name_and_message(p_exc));
+#endif
}
#endif
return;
@@ -305,6 +164,8 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
Vector<ScriptLanguage::StackInfo> si;
String exc_msg;
+#warning TODO
+#if 0
while (p_exc != nullptr) {
GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace);
MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr());
@@ -341,6 +202,7 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
p_exc = (MonoException *)inner_exc;
}
+#endif
String file = si.size() ? si[0].file : __FILE__;
String func = si.size() ? si[0].func : FUNCTION_STR;
@@ -377,101 +239,6 @@ void set_pending_exception(MonoException *p_exc) {
thread_local int current_invoke_count = 0;
-MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_runtime_invoke(p_method, p_obj, p_params, (MonoObject **)r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- return ret;
-}
-
-MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- return ret;
-}
-
-MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- return ret;
-}
-
-void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- mono_property_set_value(p_prop, p_obj, p_params, (MonoObject **)r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
-}
-
-MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_property_get_value(p_prop, p_obj, p_params, (MonoObject **)r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- return ret;
-}
-
-uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error) {
- r_error = false;
- switch (mono_type_get_type(p_enum_basetype)) {
- case MONO_TYPE_BOOLEAN:
- return (bool)GDMonoMarshal::unbox<MonoBoolean>(p_boxed) ? 1 : 0;
- case MONO_TYPE_CHAR:
- return GDMonoMarshal::unbox<uint16_t>(p_boxed);
- case MONO_TYPE_U1:
- return GDMonoMarshal::unbox<uint8_t>(p_boxed);
- case MONO_TYPE_U2:
- return GDMonoMarshal::unbox<uint16_t>(p_boxed);
- case MONO_TYPE_U4:
- return GDMonoMarshal::unbox<uint32_t>(p_boxed);
- case MONO_TYPE_U8:
- return GDMonoMarshal::unbox<uint64_t>(p_boxed);
- case MONO_TYPE_I1:
- return GDMonoMarshal::unbox<int8_t>(p_boxed);
- case MONO_TYPE_I2:
- return GDMonoMarshal::unbox<int16_t>(p_boxed);
- case MONO_TYPE_I4:
- return GDMonoMarshal::unbox<int32_t>(p_boxed);
- case MONO_TYPE_I8:
- return GDMonoMarshal::unbox<int64_t>(p_boxed);
- default:
- r_error = true;
- return 0;
- }
-}
-
-void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
- CACHED_METHOD_THUNK(GodotObject, Dispose).invoke(p_mono_object, r_exc);
-}
-
-namespace Marshal {
-
-#ifdef MONO_GLUE_ENABLED
-#ifdef TOOLS_ENABLED
-#define NO_GLUE_RET(m_ret) \
- { \
- if (!GDMonoCache::cached_data.godot_api_cache_updated) \
- return m_ret; \
- }
-#else
-#define NO_GLUE_RET(m_ret) \
- {}
-#endif
-#else
-#define NO_GLUE_RET(m_ret) \
- { return m_ret; }
-#endif
-
-bool type_has_flags_attribute(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeHasFlagsAttribute).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-} // namespace Marshal
-
ScopeThreadAttach::ScopeThreadAttach() {
if (likely(GDMono::get_singleton()->is_runtime_initialized()) && unlikely(!mono_domain_get())) {
mono_thread = GDMonoUtils::attach_current_thread();
@@ -483,9 +250,4 @@ ScopeThreadAttach::~ScopeThreadAttach() {
GDMonoUtils::detach_current_thread(mono_thread);
}
}
-
-StringName get_native_godot_class_name(GDMonoClass *p_class) {
- MonoObject *native_name_obj = p_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(nullptr);
- return (StringName)GDMonoMarshal::mono_object_to_variant(native_name_obj);
-}
} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index ee1be979e7..16fc3cc757 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -35,7 +35,6 @@
#include "../mono_gc_handle.h"
#include "../utils/macros.h"
-#include "gd_mono_header.h"
#ifdef JAVASCRIPT_ENABLED
#include "gd_mono_wasm_m2n.h"
#endif
@@ -60,13 +59,6 @@ _FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash)
p_hash ^= p_with_hash + 0x9e3779b9 + (p_hash << 6) + (p_hash >> 2);
}
-/**
- * If the object has a csharp script, returns the target of the gchandle stored in the script instance
- * Otherwise returns a newly constructed MonoObject* which is attached to the object
- * Returns nullptr on error
- */
-MonoObject *unmanaged_get_managed(Object *unmanaged);
-
void set_main_thread(MonoThread *p_thread);
MonoThread *attach_current_thread();
void detach_current_thread();
@@ -74,24 +66,8 @@ void detach_current_thread(MonoThread *p_mono_thread);
MonoThread *get_current_thread();
bool is_thread_attached();
-uint32_t new_strong_gchandle(MonoObject *p_object);
-uint32_t new_strong_gchandle_pinned(MonoObject *p_object);
-uint32_t new_weak_gchandle(MonoObject *p_object);
-void free_gchandle(uint32_t p_gchandle);
-
-void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc = nullptr);
-
-GDMonoClass *get_object_class(MonoObject *p_object);
-GDMonoClass *type_get_proxy_class(const StringName &p_type);
-GDMonoClass *get_class_native_base(GDMonoClass *p_class);
-
-MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object);
-
MonoDomain *create_domain(const String &p_friendly_name);
-String get_type_desc(MonoType *p_type);
-String get_type_desc(MonoReflectionType *p_reftype);
-
String get_exception_name_and_message(MonoException *p_exc);
void debug_print_unhandled_exception(MonoException *p_exc);
@@ -116,18 +92,8 @@ _FORCE_INLINE_ int &get_runtime_invoke_count_ref() {
return current_invoke_count;
}
-MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc);
-MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc);
-
-MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc);
-
-void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc);
-MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc);
-
uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error);
-void dispose(MonoObject *p_mono_object, MonoException **r_exc);
-
struct ScopeThreadAttach {
ScopeThreadAttach();
~ScopeThreadAttach();
@@ -136,8 +102,6 @@ private:
MonoThread *mono_thread = nullptr;
};
-StringName get_native_godot_class_name(GDMonoClass *p_class);
-
template <typename... P>
void add_internal_call(const char *p_name, void (*p_func)(P...)) {
#ifdef JAVASCRIPT_ENABLED
@@ -155,8 +119,6 @@ void add_internal_call(const char *p_name, R (*p_func)(P...)) {
}
} // namespace GDMonoUtils
-#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoUtils::get_native_godot_class_name(m_class))
-
#define GD_MONO_BEGIN_RUNTIME_INVOKE \
int &_runtime_invoke_count_ref = GDMonoUtils::get_runtime_invoke_count_ref(); \
_runtime_invoke_count_ref += 1; \
diff --git a/modules/mono/mono_gd/i_mono_class_member.h b/modules/mono/mono_gd/i_mono_class_member.h
deleted file mode 100644
index 14e8ca82b9..0000000000
--- a/modules/mono/mono_gd/i_mono_class_member.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*************************************************************************/
-/* i_mono_class_member.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-
-#ifndef I_MONO_CLASS_MEMBER_H
-#define I_MONO_CLASS_MEMBER_H
-
-#include "gd_mono_header.h"
-
-#include <mono/metadata/object.h>
-
-class IMonoClassMember {
-public:
- enum Visibility {
- PRIVATE,
- PROTECTED_AND_INTERNAL, // FAM_AND_ASSEM
- INTERNAL, // ASSEMBLY
- PROTECTED, // FAMILY
- PUBLIC
- };
-
- enum MemberType {
- MEMBER_TYPE_FIELD,
- MEMBER_TYPE_PROPERTY,
- MEMBER_TYPE_METHOD
- };
-
- virtual ~IMonoClassMember() {}
-
- virtual GDMonoClass *get_enclosing_class() const = 0;
-
- virtual MemberType get_member_type() const = 0;
-
- virtual StringName get_name() const = 0;
-
- virtual bool is_static() = 0;
-
- virtual Visibility get_visibility() = 0;
-
- virtual bool has_attribute(GDMonoClass *p_attr_class) = 0;
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) = 0;
-};
-
-#endif // I_MONO_CLASS_MEMBER_H
diff --git a/modules/mono/mono_gd/managed_type.cpp b/modules/mono/mono_gd/managed_type.cpp
deleted file mode 100644
index 5860d7db1e..0000000000
--- a/modules/mono/mono_gd/managed_type.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*************************************************************************/
-/* managed_type.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 "managed_type.h"
-
-#include "gd_mono.h"
-#include "gd_mono_class.h"
-
-ManagedType ManagedType::from_class(GDMonoClass *p_class) {
- return ManagedType(mono_type_get_type(p_class->get_mono_type()), p_class);
-}
-
-ManagedType ManagedType::from_class(MonoClass *p_mono_class) {
- GDMonoClass *tclass = GDMono::get_singleton()->get_class(p_mono_class);
- ERR_FAIL_COND_V(!tclass, ManagedType());
-
- return ManagedType(mono_type_get_type(tclass->get_mono_type()), tclass);
-}
-
-ManagedType ManagedType::from_type(MonoType *p_mono_type) {
- MonoClass *mono_class = mono_class_from_mono_type(p_mono_type);
- GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_class);
- ERR_FAIL_COND_V(!tclass, ManagedType());
-
- return ManagedType(mono_type_get_type(p_mono_type), tclass);
-}
-
-ManagedType ManagedType::from_reftype(MonoReflectionType *p_mono_reftype) {
- MonoType *mono_type = mono_reflection_type_get_type(p_mono_reftype);
- return from_type(mono_type);
-}
diff --git a/modules/mono/mono_gd/managed_type.h b/modules/mono/mono_gd/managed_type.h
deleted file mode 100644
index 603ff3aca1..0000000000
--- a/modules/mono/mono_gd/managed_type.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*************************************************************************/
-/* managed_type.h */
-/*************************************************************************/
-/* 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. */
-/*************************************************************************/
-
-#ifndef MANAGED_TYPE_H
-#define MANAGED_TYPE_H
-
-#include <mono/metadata/object.h>
-
-#include "gd_mono_header.h"
-
-struct ManagedType {
- int type_encoding = 0;
- GDMonoClass *type_class = nullptr;
-
- static ManagedType from_class(GDMonoClass *p_class);
- static ManagedType from_class(MonoClass *p_mono_class);
- static ManagedType from_type(MonoType *p_mono_type);
- static ManagedType from_reftype(MonoReflectionType *p_mono_reftype);
-
- ManagedType() {}
-
- ManagedType(int p_type_encoding, GDMonoClass *p_type_class) :
- type_encoding(p_type_encoding),
- type_class(p_type_class) {
- }
-};
-
-#endif // MANAGED_TYPE_H
diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp
index 4797d5dae1..7fb983cd37 100644
--- a/modules/mono/mono_gd/support/android_support.cpp
+++ b/modules/mono/mono_gd/support/android_support.cpp
@@ -359,7 +359,7 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) {
ScopedLocalRef<jbyteArray> encoded(env, (jbyteArray)env->CallObjectMethod(certificate, getEncoded));
jsize encodedLength = env->GetArrayLength(encoded);
- MonoArray *encoded_ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), encodedLength);
+ MonoArray *encoded_ret = mono_array_new(mono_domain_get(), mono_get_byte_class(), encodedLength);
uint8_t *dest = (uint8_t *)mono_array_addr(encoded_ret, uint8_t, 0);
env->GetByteArrayRegion(encoded, 0, encodedLength, reinterpret_cast<jbyte *>(dest));
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index f26459554c..b71e5f392b 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -32,16 +32,15 @@
#include "csharp_script.h"
#include "mono_gd/gd_mono_cache.h"
-#include "mono_gd/gd_mono_class.h"
-#include "mono_gd/gd_mono_marshal.h"
#include "mono_gd/gd_mono_utils.h"
-Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, MonoObject *p_awaiter) {
+Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr) {
ERR_FAIL_NULL_V(p_source, ERR_INVALID_DATA);
ERR_FAIL_NULL_V(p_target, ERR_INVALID_DATA);
// TODO: Use pooling for ManagedCallable instances.
- SignalAwaiterCallable *awaiter_callable = memnew(SignalAwaiterCallable(p_target, p_awaiter, p_signal));
+ MonoGCHandleData awaiter_handle(p_awaiter_handle_ptr, gdmono::GCHandleType::STRONG_HANDLE);
+ SignalAwaiterCallable *awaiter_callable = memnew(SignalAwaiterCallable(p_target, awaiter_handle, p_signal));
Callable callable = Callable(awaiter_callable);
return p_source->connect(p_signal, callable, Object::CONNECT_ONESHOT);
@@ -51,7 +50,7 @@ bool SignalAwaiterCallable::compare_equal(const CallableCustom *p_a, const Calla
// Only called if both instances are of type SignalAwaiterCallable. Static cast is safe.
const SignalAwaiterCallable *a = static_cast<const SignalAwaiterCallable *>(p_a);
const SignalAwaiterCallable *b = static_cast<const SignalAwaiterCallable *>(p_b);
- return a->awaiter_handle.handle == b->awaiter_handle.handle;
+ return a->awaiter_handle.handle.value == b->awaiter_handle.handle.value;
}
bool SignalAwaiterCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
@@ -105,38 +104,26 @@ void SignalAwaiterCallable::call(const Variant **p_arguments, int p_argcount, Va
"Resumed after await, but class instance is gone.");
#endif
- MonoArray *signal_args = nullptr;
-
- if (p_argcount > 0) {
- signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_argcount);
+ MonoException *exc = nullptr;
+ bool awaiter_is_null = false;
+ GDMonoCache::cached_data.methodthunk_SignalAwaiter_SignalCallback.invoke(awaiter_handle.get_intptr(), p_arguments, p_argcount, &awaiter_is_null, &exc);
- for (int i = 0; i < p_argcount; i++) {
- MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_arguments[i]);
- mono_array_setref(signal_args, i, boxed);
- }
+ if (exc) {
+ GDMonoUtils::set_pending_exception(exc);
+ ERR_FAIL();
}
- MonoObject *awaiter = awaiter_handle.get_target();
-
- if (!awaiter) {
+ if (awaiter_is_null) {
r_call_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
return;
}
- MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback).invoke(awaiter, signal_args, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- ERR_FAIL();
- } else {
- r_call_error.error = Callable::CallError::CALL_OK;
- }
+ r_call_error.error = Callable::CallError::CALL_OK;
}
-SignalAwaiterCallable::SignalAwaiterCallable(Object *p_target, MonoObject *p_awaiter, const StringName &p_signal) :
+SignalAwaiterCallable::SignalAwaiterCallable(Object *p_target, MonoGCHandleData p_awaiter_handle, const StringName &p_signal) :
target_id(p_target->get_instance_id()),
- awaiter_handle(MonoGCHandleData::new_strong_handle(p_awaiter)),
+ awaiter_handle(p_awaiter_handle),
signal(p_signal) {
}
@@ -152,7 +139,7 @@ bool EventSignalCallable::compare_equal(const CallableCustom *p_a, const Callabl
return false;
}
- if (a->event_signal != b->event_signal) {
+ if (a->event_signal_name != b->event_signal_name) {
return false;
}
@@ -167,7 +154,7 @@ bool EventSignalCallable::compare_less(const CallableCustom *p_a, const Callable
}
uint32_t EventSignalCallable::hash() const {
- uint32_t hash = event_signal->field->get_name().hash();
+ uint32_t hash = event_signal_name.hash();
return hash_murmur3_one_64(owner->get_instance_id(), hash);
}
@@ -177,8 +164,7 @@ String EventSignalCallable::get_as_text() const {
if (script.is_valid() && script->get_path().is_resource_file()) {
class_name += "(" + script->get_path().get_file() + ")";
}
- StringName signal = event_signal->field->get_name();
- return class_name + "::EventSignalMiddleman::" + String(signal);
+ return class_name + "::EventSignalMiddleman::" + String(event_signal_name);
}
CallableCustom::CompareEqualFunc EventSignalCallable::get_compare_equal_func() const {
@@ -194,39 +180,38 @@ ObjectID EventSignalCallable::get_object() const {
}
StringName EventSignalCallable::get_signal() const {
- return event_signal->field->get_name();
+ return event_signal_name;
}
void EventSignalCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // Can't find anything better
r_return_value = Variant();
- ERR_FAIL_COND(p_argcount < event_signal->invoke_method->get_parameters_count());
-
CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(owner->get_script_instance());
ERR_FAIL_NULL(csharp_instance);
- MonoObject *owner_managed = csharp_instance->get_mono_object();
- ERR_FAIL_NULL(owner_managed);
-
- MonoObject *delegate_field_value = event_signal->field->get_value(owner_managed);
- if (!delegate_field_value) {
- r_call_error.error = Callable::CallError::CALL_OK;
- return;
- }
+ GCHandleIntPtr owner_gchandle_intptr = csharp_instance->get_gchandle_intptr();
MonoException *exc = nullptr;
- event_signal->invoke_method->invoke(delegate_field_value, p_arguments, &exc);
+ bool awaiter_is_null = false;
+ GDMonoCache::cached_data.methodthunk_ScriptManagerBridge_RaiseEventSignal.invoke(
+ owner_gchandle_intptr, &event_signal_name,
+ p_arguments, p_argcount, &awaiter_is_null, &exc);
if (exc) {
GDMonoUtils::set_pending_exception(exc);
ERR_FAIL();
- } else {
- r_call_error.error = Callable::CallError::CALL_OK;
}
+
+ if (awaiter_is_null) {
+ r_call_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return;
+ }
+
+ r_call_error.error = Callable::CallError::CALL_OK;
}
-EventSignalCallable::EventSignalCallable(Object *p_owner, const CSharpScript::EventSignal *p_event_signal) :
+EventSignalCallable::EventSignalCallable(Object *p_owner, const StringName &p_event_signal_name) :
owner(p_owner),
- event_signal(p_event_signal) {
+ event_signal_name(p_event_signal_name) {
}
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index 4f4986baf3..a53ae56bf5 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -36,7 +36,7 @@
#include "csharp_script.h"
#include "mono_gc_handle.h"
-Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, MonoObject *p_awaiter);
+Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr);
class BaseSignalCallable : public CallableCustom {
public:
@@ -68,13 +68,13 @@ public:
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
- SignalAwaiterCallable(Object *p_target, MonoObject *p_awaiter, const StringName &p_signal);
+ SignalAwaiterCallable(Object *p_target, MonoGCHandleData p_awaiter_handle, const StringName &p_signal);
~SignalAwaiterCallable();
};
class EventSignalCallable : public BaseSignalCallable {
Object *owner = nullptr;
- const CSharpScript::EventSignal *event_signal;
+ StringName event_signal_name;
public:
static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
@@ -96,7 +96,7 @@ public:
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
- EventSignalCallable(Object *p_owner, const CSharpScript::EventSignal *p_event_signal);
+ EventSignalCallable(Object *p_owner, const StringName &p_event_signal_name);
};
#endif // SIGNAL_AWAITER_UTILS_H