Skip to content

Commit adc9def

Browse files
committed
[iOS] Fix initialisation/termination of multiple statically linked extensions.
1 parent 3240947 commit adc9def

File tree

2 files changed

+95
-27
lines changed

2 files changed

+95
-27
lines changed

include/godot_cpp/godot.hpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -194,26 +194,44 @@ enum ModuleInitializationLevel {
194194
MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
195195
MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
196196
MODULE_INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
197-
MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
197+
MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR,
198+
MODULE_INITIALIZATION_LEVEL_MAX
198199
};
199200

200201
class GDExtensionBinding {
201202
public:
202203
using Callback = void (*)(ModuleInitializationLevel p_level);
203204

204-
static Callback init_callback;
205-
static Callback terminate_callback;
206-
static GDExtensionInitializationLevel minimum_initialization_level;
207-
static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
205+
struct InitData {
206+
GDExtensionInitializationLevel minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
207+
Callback init_callback = nullptr;
208+
Callback terminate_callback = nullptr;
209+
};
210+
211+
class InitDataList {
212+
int data_count = 0;
213+
int data_capacity = 0;
214+
InitData **data = nullptr;
215+
216+
public:
217+
void add(InitData *p_cb);
218+
~InitDataList();
219+
};
220+
221+
static bool api_initialized;
222+
static int level_initialized[MODULE_INITIALIZATION_LEVEL_MAX];
223+
static InitDataList initdata;
224+
static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, InitData *p_init_data, GDExtensionInitialization *r_initialization);
208225

209226
public:
210-
static void initialize_level(void *userdata, GDExtensionInitializationLevel p_level);
211-
static void deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level);
227+
static void initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
228+
static void deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
212229

213230
class InitObject {
214231
GDExtensionInterfaceGetProcAddress get_proc_address;
215232
GDExtensionClassLibraryPtr library;
216233
GDExtensionInitialization *initialization;
234+
mutable InitData *init_data = nullptr;
217235

218236
public:
219237
InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);

src/godot.cpp

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,9 @@ GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugi
196196

197197
} // namespace internal
198198

199-
GDExtensionBinding::Callback GDExtensionBinding::init_callback = nullptr;
200-
GDExtensionBinding::Callback GDExtensionBinding::terminate_callback = nullptr;
201-
GDExtensionInitializationLevel GDExtensionBinding::minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
199+
bool GDExtensionBinding::api_initialized = false;
200+
int GDExtensionBinding::level_initialized[MODULE_INITIALIZATION_LEVEL_MAX] = { 0 };
201+
GDExtensionBinding::InitDataList GDExtensionBinding::initdata;
202202

203203
#define ERR_PRINT_EARLY(m_msg) \
204204
internal::gdextension_interface_print_error(m_msg, FUNCTION_STR, __FILE__, __LINE__, false)
@@ -225,7 +225,20 @@ typedef struct {
225225
GDExtensionInterfacePrintErrorWithMessage print_error_with_message;
226226
} LegacyGDExtensionInterface;
227227

228-
GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
228+
GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, InitData *p_init_data, GDExtensionInitialization *r_initialization) {
229+
if (!p_init_data || !p_init_data->init_callback) {
230+
ERR_FAIL_V_MSG(false, "Initialization callback must be defined.");
231+
}
232+
233+
if (api_initialized) {
234+
r_initialization->initialize = initialize_level;
235+
r_initialization->deinitialize = deinitialize_level;
236+
r_initialization->userdata = p_init_data;
237+
r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
238+
239+
return true;
240+
}
241+
229242
// Make sure we weren't passed the legacy struct.
230243
uint32_t *raw_interface = (uint32_t *)(void *)p_get_proc_address;
231244
if (raw_interface[0] == 4 && raw_interface[1] == 0) {
@@ -415,59 +428,96 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
415428

416429
r_initialization->initialize = initialize_level;
417430
r_initialization->deinitialize = deinitialize_level;
418-
r_initialization->minimum_initialization_level = minimum_initialization_level;
419-
420-
ERR_FAIL_NULL_V_MSG(init_callback, false, "Initialization callback must be defined.");
431+
r_initialization->userdata = p_init_data;
432+
r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
421433

422434
Variant::init_bindings();
423435
godot::internal::register_engine_classes();
424436

437+
api_initialized = true;
425438
return true;
426439
}
427440

428441
#undef LOAD_PROC_ADDRESS
429442
#undef ERR_PRINT_EARLY
430443

431-
void GDExtensionBinding::initialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
444+
void GDExtensionBinding::initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) {
445+
ERR_FAIL_COND(static_cast<ModuleInitializationLevel>(p_level) >= MODULE_INITIALIZATION_LEVEL_MAX);
432446
ClassDB::current_level = p_level;
433447

434-
if (init_callback) {
435-
init_callback(static_cast<ModuleInitializationLevel>(p_level));
448+
InitData *init_data = static_cast<InitData *>(p_userdata);
449+
if (init_data && init_data->init_callback) {
450+
init_data->init_callback(static_cast<ModuleInitializationLevel>(p_level));
436451
}
437452

438-
ClassDB::initialize(p_level);
453+
if (level_initialized[p_level] == 0) {
454+
ClassDB::initialize(p_level);
455+
}
456+
level_initialized[p_level]++;
439457
}
440458

441-
void GDExtensionBinding::deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
459+
void GDExtensionBinding::deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) {
460+
ERR_FAIL_COND(static_cast<ModuleInitializationLevel>(p_level) >= MODULE_INITIALIZATION_LEVEL_MAX);
442461
ClassDB::current_level = p_level;
443462

444-
if (terminate_callback) {
445-
terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
463+
InitData *init_data = static_cast<InitData *>(p_userdata);
464+
if (init_data && init_data->terminate_callback) {
465+
init_data->terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
466+
}
467+
468+
level_initialized[p_level]--;
469+
if (level_initialized[p_level] == 0) {
470+
EditorPlugins::deinitialize(p_level);
471+
ClassDB::deinitialize(p_level);
472+
}
473+
}
474+
475+
void GDExtensionBinding::InitDataList::add(InitData *p_data) {
476+
if (data_count == data_capacity) {
477+
void *new_ptr = realloc(data, sizeof(InitData *) * (data_capacity + 32));
478+
if (new_ptr) {
479+
data = (InitData **)(new_ptr);
480+
data_capacity += 32;
481+
} else {
482+
ERR_FAIL_MSG("Unable to allocate memory for extension callbacks.");
483+
}
446484
}
485+
data[data_count++] = p_data;
486+
}
447487

448-
EditorPlugins::deinitialize(p_level);
449-
ClassDB::deinitialize(p_level);
488+
GDExtensionBinding::InitDataList::~InitDataList() {
489+
for (int i = 0; i < data_count; i++) {
490+
if (data[i]) {
491+
delete data[i];
492+
}
493+
}
494+
if (data) {
495+
free(data);
496+
}
450497
}
498+
451499
GDExtensionBinding::InitObject::InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
452500
get_proc_address = p_get_proc_address;
453501
library = p_library;
454502
initialization = r_initialization;
503+
init_data = new InitData();
504+
GDExtensionBinding::initdata.add(init_data);
455505
}
456506

457507
void GDExtensionBinding::InitObject::register_initializer(Callback p_init) const {
458-
GDExtensionBinding::init_callback = p_init;
508+
init_data->init_callback = p_init;
459509
}
460510

461511
void GDExtensionBinding::InitObject::register_terminator(Callback p_terminate) const {
462-
GDExtensionBinding::terminate_callback = p_terminate;
512+
init_data->terminate_callback = p_terminate;
463513
}
464514

465515
void GDExtensionBinding::InitObject::set_minimum_library_initialization_level(ModuleInitializationLevel p_level) const {
466-
GDExtensionBinding::minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
516+
init_data->minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
467517
}
468518

469519
GDExtensionBool GDExtensionBinding::InitObject::init() const {
470-
return GDExtensionBinding::init(get_proc_address, library, initialization);
520+
return GDExtensionBinding::init(get_proc_address, library, init_data, initialization);
471521
}
472522

473523
} // namespace godot

0 commit comments

Comments
 (0)