From cbad9e88713fcd7859c77aa9af55cce1107e8d86 Mon Sep 17 00:00:00 2001 From: Jeff Ward Date: Sun, 30 Jul 2023 17:20:33 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fix=20casting=20to=20script=20ty?= =?UTF-8?q?pes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Casting to script types requires [this PR](https://github.com/godotengine/godot/pull/80040), which will make this extension require Godot 4.2 when it is merged. --- README.md | 7 ++++- godot-headers/godot/gdextension_interface.h | 3 +- src/cpp/dart_bindings.cpp | 15 +++++++++ src/cpp/dart_bindings.h | 5 +++ src/cpp/dart_script_instance.cpp | 3 +- src/cpp/dart_script_instance.h | 4 +++ src/cpp/gde_c_interface.cpp | 10 ++++++ src/cpp/gde_c_interface.h | 2 ++ src/cpp/gde_dart_converters.cpp | 17 ++++++++++ src/cpp/gde_dart_converters.h | 1 + src/dart/godot_dart/lib/godot_dart.dart | 4 ++- .../godot_dart/lib/src/core/gdextension.dart | 31 ++++++++++++------- .../src/core/gdextension_ffi_bindings.dart | 19 ++++++++++++ .../src/core/godot_dart_native_bindings.dart | 5 +++ 14 files changed, 110 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 4727f81..eed0aac 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,11 @@ And I want to use it in Godot. # Current State +``` +⚠ NOTE -- Current master of this extension currently requires [this PR](https://github.com/godotengine/godot/pull/80040). Once that +PR is merged, this extension will only be Godot 4.2 compatible +``` + Here's a list of planned features and work still to be done ( ✅ - Seems to be working, 🟨 - Partially working, ❌ - Not working) @@ -44,7 +49,7 @@ I have only tested this on Windows. I know for certain it will only work on 'flo * A clone of this repo. * Dart (2.19 Current Stable, not tested with 3.0) -* Godot 4.1.x or a custom build compatible with 4.1.x +* Godot 4.2.x - Note above the pending pull request. * A build of the [Dart Shared Library](https://github.com/fuzzybinary/dart_shared_libray). Windows x64 .dlls for Dart 2.19 are provided in `src/dart_dll/bin/win64`. diff --git a/godot-headers/godot/gdextension_interface.h b/godot-headers/godot/gdextension_interface.h index 74696df..c2680dd 100644 --- a/godot-headers/godot/gdextension_interface.h +++ b/godot-headers/godot/gdextension_interface.h @@ -2114,10 +2114,11 @@ typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate) * Get the script instance data attached to this object. * * @param p_object A pointer to the Object + * @param p_language A pointer to the language expected for this script instance * * @return A GDExtensionScriptInstanceDataPtr that was attached to this object as part of script_instance_create */ -typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptInstance)(GDExtensionConstObjectPtr p_object); +typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptInstance)(GDExtensionConstObjectPtr p_object, GDExtensionObjectPtr p_language); /* INTERFACE: ClassDB */ diff --git a/src/cpp/dart_bindings.cpp b/src/cpp/dart_bindings.cpp index 878c1fd..082b4a9 100644 --- a/src/cpp/dart_bindings.cpp +++ b/src/cpp/dart_bindings.cpp @@ -253,6 +253,9 @@ bool GodotDartBindings::initialize(const char *script_path, const char *package_ }; DART_CHECK_RET(result, Dart_Invoke(godot_dart_library, Dart_NewStringFromCString("_registerGodot"), 2, args), false, "Error calling '_registerGodot'"); + + // Get the language pointer from the result: + _dart_language = get_object_address(result); } // And call the main function from the user supplied library @@ -987,6 +990,18 @@ GDE_EXPORT void *create_script_instance(Dart_Handle type, Dart_Handle script, vo return godot_script_instance; } +GDE_EXPORT Dart_Handle object_from_script_instance(DartScriptInstance *script_instance) { + if (!script_instance) { + return Dart_Null(); + } + + Dart_PersistentHandle persistent = script_instance->get_dart_object(); + DART_CHECK_RET(dart_object, Dart_HandleFromPersistent(persistent), Dart_Null(), + "Failed to get object from persistent handle"); + + return dart_object; +} + GDE_EXPORT void perform_frame_maintenance() { Dart_EnterScope(); diff --git a/src/cpp/dart_bindings.h b/src/cpp/dart_bindings.h index ae3c3ab..553494a 100644 --- a/src/cpp/dart_bindings.h +++ b/src/cpp/dart_bindings.h @@ -53,6 +53,10 @@ class GodotDartBindings { bool initialize(const char *script_path, const char *package_config); void shutdown(); + GDExtensionScriptLanguagePtr get_language() { + return _dart_language; + } + void bind_method(const TypeInfo &bind_type, const char *method_name, const TypeInfo &ret_type_info, Dart_Handle args_list, MethodFlags method_flags); void add_property(const TypeInfo &bind_type, Dart_Handle dart_prop_info); @@ -84,6 +88,7 @@ class GodotDartBindings { Dart_PersistentHandle _native_library; // Some things we need often + GDExtensionScriptLanguagePtr _dart_language; Dart_PersistentHandle _void_pointer_type; Dart_PersistentHandle _void_pointer_optional_type; Dart_PersistentHandle _void_pointer_pointer_type; diff --git a/src/cpp/dart_script_instance.cpp b/src/cpp/dart_script_instance.cpp index a7f1562..28cce78 100644 --- a/src/cpp/dart_script_instance.cpp +++ b/src/cpp/dart_script_instance.cpp @@ -425,8 +425,7 @@ bool DartScriptInstance::get_fallback(const GDStringName &p_name, GDExtensionVar } GDExtensionScriptLanguagePtr DartScriptInstance::get_language() { - - return nullptr; + return GodotDartBindings::instance()->get_language(); } // * Static Callback Functions for Godot */ diff --git a/src/cpp/dart_script_instance.h b/src/cpp/dart_script_instance.h index f77c390..55aabcb 100644 --- a/src/cpp/dart_script_instance.h +++ b/src/cpp/dart_script_instance.h @@ -44,6 +44,10 @@ class DartScriptInstance { GDExtensionScriptLanguagePtr get_language(); + Dart_PersistentHandle get_dart_object() { + return _dart_object; + } + static const GDExtensionScriptInstanceInfo* get_script_instance_info(); private: diff --git a/src/cpp/gde_c_interface.cpp b/src/cpp/gde_c_interface.cpp index dc516f7..746dcb9 100644 --- a/src/cpp/gde_c_interface.cpp +++ b/src/cpp/gde_c_interface.cpp @@ -350,6 +350,15 @@ GDExtensionScriptInstancePtr gde_script_instance_create(const GDExtensionScriptI return nullptr; } +static GDExtensionInterfaceObjectGetScriptInstance _object_get_script_instance_func = nullptr; +GDExtensionScriptInstanceDataPtr gde_object_get_script_instance(GDExtensionConstObjectPtr p_object, + GDExtensionObjectPtr p_language) { + if (_object_get_script_instance_func) { + return _object_get_script_instance_func(p_object, p_language); + } + return nullptr; +} + #define LOAD_METHOD(method, type) _##method##_func = (type)get_proc_address(#method) void gde_init_c_interface(GDExtensionInterfaceGetProcAddress get_proc_address) { @@ -395,6 +404,7 @@ void gde_init_c_interface(GDExtensionInterfaceGetProcAddress get_proc_address) { LOAD_METHOD(ref_get_object, GDExtensionInterfaceRefGetObject); LOAD_METHOD(ref_set_object, GDExtensionInterfaceRefSetObject); LOAD_METHOD(script_instance_create, GDExtensionInterfaceScriptInstanceCreate); + LOAD_METHOD(object_get_script_instance, GDExtensionInterfaceObjectGetScriptInstance); } } \ No newline at end of file diff --git a/src/cpp/gde_c_interface.h b/src/cpp/gde_c_interface.h index b91e881..6ba2449 100644 --- a/src/cpp/gde_c_interface.h +++ b/src/cpp/gde_c_interface.h @@ -108,6 +108,8 @@ GDE_EXPORT void gde_ref_set_object(GDExtensionRefPtr p_ref, GDExtensionObjectPtr GDE_EXPORT GDExtensionScriptInstancePtr gde_script_instance_create(const GDExtensionScriptInstanceInfo *p_info, GDExtensionScriptInstanceDataPtr p_instance_data); +GDE_EXPORT GDExtensionScriptInstanceDataPtr gde_object_get_script_instance(GDExtensionConstObjectPtr p_object, + GDExtensionObjectPtr p_language); #ifdef __cplusplus } diff --git a/src/cpp/gde_dart_converters.cpp b/src/cpp/gde_dart_converters.cpp index 3db5217..3023cd1 100644 --- a/src/cpp/gde_dart_converters.cpp +++ b/src/cpp/gde_dart_converters.cpp @@ -6,6 +6,23 @@ #include "gde_wrapper.h" #include "godot_string_wrappers.h" +void *get_object_address(Dart_Handle engine_handle) { + Dart_Handle native_ptr = Dart_GetField(engine_handle, Dart_NewStringFromCString("nativePtr")); + if (Dart_IsError(native_ptr)) { + GD_PRINT_ERROR(Dart_GetError(native_ptr)); + return nullptr; + } + Dart_Handle address = Dart_GetField(native_ptr, Dart_NewStringFromCString("address")); + if (Dart_IsError(address)) { + GD_PRINT_ERROR(Dart_GetError(address)); + return nullptr; + } + uint64_t object_ptr = 0; + Dart_IntegerToUint64(address, &object_ptr); + + return reinterpret_cast(object_ptr); +} + void *get_opaque_address(Dart_Handle variant_handle) { // TODO: Look for a better way convert the variant. Dart_Handle opaque = Dart_GetField(variant_handle, Dart_NewStringFromCString("_opaque")); diff --git a/src/cpp/gde_dart_converters.h b/src/cpp/gde_dart_converters.h index 69c56f1..2e5bc3f 100644 --- a/src/cpp/gde_dart_converters.h +++ b/src/cpp/gde_dart_converters.h @@ -17,6 +17,7 @@ struct TypeInfo { // Actually defined in dart_bindings.cpp void type_info_from_dart(TypeInfo *type_info, Dart_Handle dart_type_info); +void *get_object_address(Dart_Handle variant_handle); void *get_opaque_address(Dart_Handle variant_handle); void gde_method_info_from_dart(Dart_Handle dart_method_info, GDExtensionMethodInfo *method_info); diff --git a/src/dart/godot_dart/lib/godot_dart.dart b/src/dart/godot_dart/lib/godot_dart.dart index 888c16e..2ce0f6a 100644 --- a/src/dart/godot_dart/lib/godot_dart.dart +++ b/src/dart/godot_dart/lib/godot_dart.dart @@ -26,7 +26,7 @@ late GodotDart _globalExtension; DartScriptLanguage? _dartScriptLanguage; @pragma('vm:entry-point') -void _registerGodot(int libraryAddress, int bindingCallbacks) { +DartScriptLanguage _registerGodot(int libraryAddress, int bindingCallbacks) { final godotDart = GodotDartNativeBindings.openLibrary('godot_dart'); final ffiInterface = GDExtensionFFI(godotDart); @@ -57,6 +57,8 @@ void _registerGodot(int libraryAddress, int bindingCallbacks) { .addResourceFormatSaver(Ref(DartResourceFormatSaver()), false); print('Everything loaded a-ok!'); + + return _dartScriptLanguage!; } @pragma('vm:entry-point') diff --git a/src/dart/godot_dart/lib/src/core/gdextension.dart b/src/dart/godot_dart/lib/src/core/gdextension.dart index d2dc63c..84121ee 100644 --- a/src/dart/godot_dart/lib/src/core/gdextension.dart +++ b/src/dart/godot_dart/lib/src/core/gdextension.dart @@ -257,19 +257,28 @@ class GodotDart { if (casted == nullptr) { return null; } - } else { - casted = from.nativePtr; - } - if (typeInfo.bindingToken != null) { - final persistent = gde.ffiBindings.gde_object_get_instance_binding( - casted, - typeInfo.bindingToken!, - gde.engineBindingCallbacks, - ); - final dartObject = dartBindings.fromPersistentHandle(persistent); + if (typeInfo.bindingToken != null) { + final persistent = gde.ffiBindings.gde_object_get_instance_binding( + casted, + typeInfo.bindingToken!, + gde.engineBindingCallbacks, + ); + final dartObject = dartBindings.fromPersistentHandle(persistent); - return dartObject as T; + return dartObject as T; + } + // TODO: What case is there where there is a class tag but no binding token? + } else { + // Try getting the script instance, and casting from that + final scriptInstance = gde.ffiBindings.gde_object_get_script_instance( + from.nativePtr, DartScriptLanguage.singleton.nativePtr); + if (scriptInstance != nullptr) { + final o = gde.dartBindings.objectFromScriptInstance(scriptInstance); + if (o is T) { + return o; + } + } } return null; diff --git a/src/dart/godot_dart/lib/src/core/gdextension_ffi_bindings.dart b/src/dart/godot_dart/lib/src/core/gdextension_ffi_bindings.dart index a3ca684..1a92c12 100644 --- a/src/dart/godot_dart/lib/src/core/gdextension_ffi_bindings.dart +++ b/src/dart/godot_dart/lib/src/core/gdextension_ffi_bindings.dart @@ -1071,6 +1071,25 @@ class GDExtensionFFI { GDExtensionScriptInstancePtr Function( ffi.Pointer, GDExtensionScriptInstanceDataPtr)>(); + + GDExtensionScriptInstanceDataPtr gde_object_get_script_instance( + GDExtensionConstObjectPtr p_object, + GDExtensionObjectPtr p_language, + ) { + return _gde_object_get_script_instance( + p_object, + p_language, + ); + } + + late final _gde_object_get_script_instancePtr = _lookup< + ffi.NativeFunction< + GDExtensionScriptInstanceDataPtr Function(GDExtensionConstObjectPtr, + GDExtensionObjectPtr)>>('gde_object_get_script_instance'); + late final _gde_object_get_script_instance = + _gde_object_get_script_instancePtr.asFunction< + GDExtensionScriptInstanceDataPtr Function( + GDExtensionConstObjectPtr, GDExtensionObjectPtr)>(); } typedef va_list = ffi.Pointer; diff --git a/src/dart/godot_dart/lib/src/core/godot_dart_native_bindings.dart b/src/dart/godot_dart/lib/src/core/godot_dart_native_bindings.dart index b3961d4..7b5f445 100644 --- a/src/dart/godot_dart/lib/src/core/godot_dart_native_bindings.dart +++ b/src/dart/godot_dart/lib/src/core/godot_dart_native_bindings.dart @@ -41,6 +41,11 @@ class GodotDartNativeBindings { Bool)>>('create_script_instance') .asFunction< Pointer Function(Type, DartScript, Pointer, bool)>(); + late final objectFromScriptInstance = godotDartDylib + .lookup)>>( + 'object_from_script_instance') + .asFunction)>(); + late final _safeNewPersistentHandle = godotDartDylib .lookup Function(Handle)>>( 'safe_new_persistent_handle')