34
34
#include " core/object/class_db.h"
35
35
#include " core/object/method_bind.h"
36
36
#include " core/os/os.h"
37
+ #include " core/version.h"
38
+
39
+ extern void gdextension_setup_interface ();
40
+ extern void *gdextension_get_legacy_interface ();
41
+ extern GDExtensionInterfaceFunctionPtr gdextension_get_proc_address (const char *p_name);
42
+
43
+ typedef GDExtensionBool (*GDExtensionLegacyInitializationFunction)(void *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
37
44
38
45
String GDExtension::get_extension_list_config_file () {
39
46
return ProjectSettings::get_singleton ()->get_project_data_path ().path_join (" extension_list.cfg" );
@@ -275,8 +282,6 @@ class GDExtensionMethodBind : public MethodBind {
275
282
}
276
283
};
277
284
278
- static GDExtensionInterface gdextension_interface;
279
-
280
285
void GDExtension::_register_extension_class (GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs) {
281
286
GDExtension *self = reinterpret_cast <GDExtension *>(p_library);
282
287
@@ -431,7 +436,20 @@ void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExte
431
436
memnew_placement (r_path, String (self->library_path ));
432
437
}
433
438
434
- Error GDExtension::open_library (const String &p_path, const String &p_entry_symbol) {
439
+ HashMap<StringName, GDExtensionInterfaceFunctionPtr> gdextension_interface_functions;
440
+
441
+ void GDExtension::register_interface_function (StringName p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) {
442
+ ERR_FAIL_COND_MSG (gdextension_interface_functions.has (p_function_name), " Attempt to register interface function '" + p_function_name + " ', which appears to be already registered." );
443
+ gdextension_interface_functions.insert (p_function_name, p_function_pointer);
444
+ }
445
+
446
+ GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function (StringName p_function_name) {
447
+ GDExtensionInterfaceFunctionPtr *function = gdextension_interface_functions.getptr (p_function_name);
448
+ ERR_FAIL_COND_V_MSG (function == nullptr , nullptr , " Attempt to get non-existent interface function: " + p_function_name);
449
+ return *function;
450
+ }
451
+
452
+ Error GDExtension::open_library (const String &p_path, const String &p_entry_symbol, bool p_use_legacy_interface) {
435
453
Error err = OS::get_singleton ()->open_dynamic_library (p_path, library, true , &library_path);
436
454
if (err != OK) {
437
455
ERR_PRINT (" GDExtension dynamic library not found: " + p_path);
@@ -448,9 +466,17 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
448
466
return err;
449
467
}
450
468
451
- GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
469
+ GDExtensionBool ret = 0 ;
470
+ if (p_use_legacy_interface) {
471
+ GDExtensionLegacyInitializationFunction initialization_function = (GDExtensionLegacyInitializationFunction)entry_funcptr;
472
+ ret = initialization_function (gdextension_get_legacy_interface (), this , &initialization);
473
+
474
+ } else {
475
+ GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr;
476
+ ret = initialization_function (&gdextension_get_proc_address, this , &initialization);
477
+ }
452
478
453
- if (initialization_function (&gdextension_interface, this , &initialization) ) {
479
+ if (ret ) {
454
480
level_initialized = -1 ;
455
481
return OK;
456
482
} else {
@@ -459,6 +485,10 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
459
485
}
460
486
}
461
487
488
+ Error GDExtension::open_library_compat_76406 (const String &p_path, const String &p_entry_symbol) {
489
+ return open_library (p_path, p_entry_symbol, true );
490
+ }
491
+
462
492
void GDExtension::close_library () {
463
493
ERR_FAIL_COND (library == nullptr );
464
494
OS::get_singleton ()->close_dynamic_library (library);
@@ -494,7 +524,8 @@ void GDExtension::deinitialize_library(InitializationLevel p_level) {
494
524
}
495
525
496
526
void GDExtension::_bind_methods () {
497
- ClassDB::bind_method (D_METHOD (" open_library" , " path" , " entry_symbol" ), &GDExtension::open_library);
527
+ ClassDB::bind_method (D_METHOD (" open_library" , " path" , " entry_symbol" , " use_legacy_interface" ), &GDExtension::open_library);
528
+ ClassDB::bind_compatibility_method (D_METHOD (" open_library" , " path" , " entry_symbol" ), &GDExtension::open_library_compat_76406);
498
529
ClassDB::bind_method (D_METHOD (" close_library" ), &GDExtension::close_library);
499
530
ClassDB::bind_method (D_METHOD (" is_library_open" ), &GDExtension::is_library_open);
500
531
@@ -516,20 +547,18 @@ GDExtension::~GDExtension() {
516
547
}
517
548
}
518
549
519
- extern void gdextension_setup_interface (GDExtensionInterface *p_interface);
520
-
521
550
void GDExtension::initialize_gdextensions () {
522
- gdextension_setup_interface (&gdextension_interface );
523
-
524
- gdextension_interface. classdb_register_extension_class = _register_extension_class;
525
- gdextension_interface. classdb_register_extension_class_method = _register_extension_class_method;
526
- gdextension_interface. classdb_register_extension_class_integer_constant = _register_extension_class_integer_constant;
527
- gdextension_interface. classdb_register_extension_class_property = _register_extension_class_property;
528
- gdextension_interface. classdb_register_extension_class_property_group = _register_extension_class_property_group;
529
- gdextension_interface. classdb_register_extension_class_property_subgroup = _register_extension_class_property_subgroup;
530
- gdextension_interface. classdb_register_extension_class_signal = _register_extension_class_signal;
531
- gdextension_interface. classdb_unregister_extension_class = _unregister_extension_class;
532
- gdextension_interface. get_library_path = _get_library_path;
551
+ gdextension_setup_interface ();
552
+
553
+ register_interface_function ( " classdb_register_extension_class" , (GDExtensionInterfaceFunctionPtr)&GDExtension:: _register_extension_class) ;
554
+ register_interface_function ( " classdb_register_extension_class_method" , (GDExtensionInterfaceFunctionPtr)&GDExtension:: _register_extension_class_method) ;
555
+ register_interface_function ( " classdb_register_extension_class_integer_constant" , (GDExtensionInterfaceFunctionPtr)&GDExtension:: _register_extension_class_integer_constant) ;
556
+ register_interface_function ( " classdb_register_extension_class_property" , (GDExtensionInterfaceFunctionPtr)&GDExtension:: _register_extension_class_property) ;
557
+ register_interface_function ( " classdb_register_extension_class_property_group" , (GDExtensionInterfaceFunctionPtr)&GDExtension:: _register_extension_class_property_group) ;
558
+ register_interface_function ( " classdb_register_extension_class_property_subgroup" , (GDExtensionInterfaceFunctionPtr)&GDExtension:: _register_extension_class_property_subgroup) ;
559
+ register_interface_function ( " classdb_register_extension_class_signal" , (GDExtensionInterfaceFunctionPtr)&GDExtension:: _register_extension_class_signal) ;
560
+ register_interface_function ( " classdb_unregister_extension_class" , (GDExtensionInterfaceFunctionPtr)&GDExtension:: _unregister_extension_class) ;
561
+ register_interface_function ( " get_library_path" , (GDExtensionInterfaceFunctionPtr)&GDExtension:: _get_library_path) ;
533
562
}
534
563
535
564
Ref<Resource> GDExtensionResourceLoader::load (const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
@@ -557,6 +586,39 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
557
586
558
587
String entry_symbol = config->get_value (" configuration" , " entry_symbol" );
559
588
589
+ uint32_t compatibility_minimum[3 ] = { 0 , 0 , 0 };
590
+ if (config->has_section_key (" configuration" , " compatibility_minimum" )) {
591
+ String compat_string = config->get_value (" configuration" , " compatibility_minimum" );
592
+ Vector<int > parts = compat_string.split_ints (" ." );
593
+ for (int i = 0 ; i < parts.size (); i++) {
594
+ if (i >= 3 ) {
595
+ break ;
596
+ }
597
+ if (parts[i] >= 0 ) {
598
+ compatibility_minimum[i] = parts[i];
599
+ }
600
+ }
601
+ }
602
+ if (compatibility_minimum[0 ] < 4 ) {
603
+ compatibility_minimum[0 ] = 4 ;
604
+ }
605
+
606
+ bool compatible = true ;
607
+ if (VERSION_MAJOR < compatibility_minimum[0 ]) {
608
+ compatible = false ;
609
+ } else if (VERSION_MINOR < compatibility_minimum[1 ]) {
610
+ compatible = false ;
611
+ } else if (VERSION_PATCH < compatibility_minimum[2 ]) {
612
+ compatible = false ;
613
+ }
614
+ if (!compatible) {
615
+ if (r_error) {
616
+ *r_error = ERR_INVALID_DATA;
617
+ }
618
+ ERR_PRINT (vformat (" GDExtension only compatible with Godot version %d.%d.%d or later: %s" , compatibility_minimum[0 ], compatibility_minimum[1 ], compatibility_minimum[2 ], p_path));
619
+ return Ref<Resource>();
620
+ }
621
+
560
622
String library_path = GDExtension::find_extension_library (p_path, config, [](String p_feature) { return OS::get_singleton ()->has_feature (p_feature); });
561
623
562
624
if (library_path.is_empty ()) {
@@ -572,10 +634,12 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
572
634
library_path = p_path.get_base_dir ().path_join (library_path);
573
635
}
574
636
637
+ bool use_legacy_interface = compatibility_minimum[0 ] == 4 && compatibility_minimum[1 ] == 0 ;
638
+
575
639
Ref<GDExtension> lib;
576
640
lib.instantiate ();
577
641
String abs_path = ProjectSettings::get_singleton ()->globalize_path (library_path);
578
- err = lib->open_library (abs_path, entry_symbol);
642
+ err = lib->open_library (abs_path, entry_symbol, use_legacy_interface );
579
643
580
644
if (r_error) {
581
645
*r_error = err;
0 commit comments