@@ -11,7 +11,7 @@ from godot.hazmat.gdextension_interface cimport *
1111from godot.hazmat.gdapi cimport *
1212from godot.hazmat.extension_class cimport *
1313from godot.builtins cimport *
14- from godot.classes cimport _load_class, _load_singleton
14+ from godot.classes cimport _load_class, _load_singleton, _cleanup_loaded_classes_and_singletons
1515
1616include " _pythonscript_editor.pxi"
1717include " _pythonscript_extension_class_language.pxi"
@@ -131,6 +131,11 @@ cdef void _register_pythonscript_classes():
131131 PythonScript._PythonScript__godot_extension_register_class()
132132
133133
134+ cdef void _unregister_pythonscript_classes():
135+ PythonScript._PythonScript__godot_extension_unregister_class()
136+ PythonScriptLanguage._PythonScriptLanguage__godot_extension_unregister_class()
137+
138+
134139cdef void _customize_config():
135140 import sys
136141 ProjectSettings = _load_singleton(" ProjectSettings" )
@@ -241,47 +246,104 @@ cdef void _register_pythonscript_language():
241246 cdef StringName gdname_register_script_language
242247 cdef gd_int_t ret
243248
249+ if _pythons_script_language is not None :
250+ return
251+
252+ # Create the instance of `PythonScriptLanguage` class...
253+
254+ _pythons_script_language = PythonScriptLanguage.__new__ (PythonScriptLanguage)
255+
256+ # ... and actually register Python into Godot \o/
257+
258+ gdname_engine = StringName(" Engine" )
259+ gdname_register_script_language = StringName(" register_script_language" )
260+ engine = pythonscript_gdextension.global_get_singleton(& gdname_engine._gd_data)
261+ if engine == NULL :
262+ print (" Failed to register Python into Godot: failed to retreive `Engine` singleton" , flush= True )
263+ return
264+
265+ bind = pythonscript_gdextension.classdb_get_method_bind(
266+ & gdname_engine._gd_data,
267+ & gdname_register_script_language._gd_data,
268+ 1850254898 ,
269+ )
270+ if bind == NULL :
271+ _pythons_script_language = None
272+ print (" Failed to register Python into Godot: failed to retreive `Engine::register_script_language`" , flush= True )
273+ return
274+
275+ args = [& _pythons_script_language._gd_ptr]
276+ pythonscript_gdextension.object_method_bind_ptrcall(
277+ bind,
278+ engine,
279+ args,
280+ & ret,
281+ )
282+ if ret != Error.OK:
283+ _pythons_script_language = None
284+ print (" Failed to register Python into Godot: `Engine::register_script_language` returned error {ret}" , flush= True )
285+ return
286+
287+
288+ cdef void _unregister_pythonscript_language():
289+ global _pythons_script_language
290+ cdef StringName gdname_engine
291+ cdef StringName gdname_unregister_script_language
292+ cdef GDExtensionObjectPtr engine
293+ cdef GDExtensionMethodBindPtr bind
294+ cdef GDExtensionConstTypePtr[1 ] args
295+ cdef gd_int_t ret
296+
244297 if _pythons_script_language is None :
298+ return
299+
300+ # 1) Unregister the languagee
301+
302+ gdname_engine = StringName(" Engine" )
303+ gdname_unregister_script_language = StringName(" unregister_script_language" )
304+ engine = pythonscript_gdextension.global_get_singleton(& gdname_engine._gd_data)
305+ if engine == NULL :
306+ print (" Failed to unregister Python from Godot: failed to retreive `Engine` singleton" , flush= True )
307+ return
245308
246- # 2) Create the instance of `PythonScriptLanguage` class...
247-
248- _pythons_script_language = PythonScriptLanguage. __new__ (PythonScriptLanguage)
249-
250- # 3) ... and actually register Python into Godot \o/
251-
252- gdname_engine = StringName( " Engine" )
253- gdname_register_script_language = StringName( " register_script_language " )
254- singleton = pythonscript_gdextension.global_get_singleton( & gdname_engine._gd_data)
255- if singleton == NULL :
256- print ( " Failed to register Python into Godot: failed to retreive `Engine` singleton " , flush = True )
257- return
258-
259- bind = pythonscript_gdextension.classdb_get_method_bind(
260- & gdname_engine._gd_data ,
261- & gdname_register_script_language._gd_data,
262- 1850254898 ,
263- )
264- if bind == NULL :
265- _pythons_script_language = None
266- print ( " Failed to register Python into Godot: failed to retreive `Engine::register_script_language` " , flush = True )
267- return
268-
269- args = [ & _pythons_script_language._gd_ptr]
270- pythonscript_gdextension.object_method_bind_ptrcall(
271- bind,
272- singleton,
273- args,
274- & ret,
275- )
276- if ret ! = 0 : # TODO: use `Error.Ok` here
277- _pythons_script_language = None
278- print ( " Failed to register Python into Godot: `Engine::register_script_language` returned error {ret} " , flush = True )
279- return
309+ bind = pythonscript_gdextension.classdb_get_method_bind(
310+ & gdname_engine._gd_data,
311+ & gdname_unregister_script_language._gd_data,
312+ 1850254898 ,
313+ )
314+ if bind == NULL :
315+ print ( " Failed to unregister Python from Godot: failed to retreive ` Engine::unregister_script_language` " , flush = True )
316+ return
317+
318+ args = [ & _pythons_script_language._gd_ptr]
319+ pythonscript_gdextension.object_method_bind_ptrcall(
320+ bind,
321+ engine,
322+ args,
323+ & ret ,
324+ )
325+ if ret ! = Error.OK:
326+ print (f " Failed to unregister Python from Godot: `Engine::unregister_script_language` returned error {ret} " , flush = True )
327+ return
328+
329+ # 2) Free the language instance
330+
331+ pythonscript_gdextension.object_destroy(
332+ _pythons_script_language._gd_ptr,
333+ )
334+
335+ # At this point `_pythons_script_language._gd_ptr` is no longer a valid pointer
336+ # however this is fine since we are clearing the reference to it right now (so
337+ # nobody is going to use it anymore) and `_gd_ptr` field is simply ignored during
338+ # garbage collection.
339+
340+ # 3) Finally clear reference on the language instance Python bindings
341+
342+ _pythons_script_language = None
280343
281344
282345cdef void _print_banner():
283346 import sys
284- ProjectSettings = _load_singleton(" ProjectSettings" )
285347
286348 if _setup_config_entry(" python/print_startup_info" , True ):
287349 from godot._version import __version__ as pythonscript_version
@@ -317,52 +379,20 @@ cdef public void _pythonscript_deinitialize(int p_level) noexcept with gil:
317379 # That will continue until `godot_gdnative_terminate` is called (which is
318380 # responsible for the actual teardown of the interpreter).
319381
320- cdef GDExtensionObjectPtr singleton
321- cdef GDExtensionMethodBindPtr bind
322- cdef GDExtensionConstTypePtr[1 ] args
323- cdef StringName gdname_engine
324- cdef StringName gdname_register_script_language
325- cdef gd_int_t ret
326-
327382 if p_level >= GDEXTENSION_INITIALIZATION_SCENE:
328383 _deinitialize_callback_hook(p_level)
329384
330385 if p_level == GDEXTENSION_INITIALIZATION_SCENE and _pythons_script_language is not None :
331-
332- # Unregister Python from Godot
333-
334- gdname_engine = StringName(" Engine" )
335- gdname_unregister_script_language = StringName(" unregister_script_language" )
336- singleton = pythonscript_gdextension.global_get_singleton(& gdname_engine._gd_data)
337- if singleton == NULL :
338- print (" Failed to unregister Python from Godot: failed to retreive `Engine` singleton" , flush= True )
339- return
340-
341- bind = pythonscript_gdextension.classdb_get_method_bind(
342- & gdname_engine._gd_data,
343- & gdname_unregister_script_language._gd_data,
344- 1850254898 ,
345- )
346- if bind == NULL :
347- print (" Failed to unregister Python from Godot: failed to retreive `Engine::unregister_script_language`" , flush= True )
348- return
349-
350- args = [& _pythons_script_language._gd_ptr]
351- pythonscript_gdextension.object_method_bind_ptrcall(
352- bind,
353- singleton,
354- args,
355- & ret,
356- )
357- if ret != 0 : # TODO: use `Error.Ok` here
358- print (f" Failed to unregister Python from Godot: `Engine::unregister_script_language` returned error {ret}" , flush= True )
359- return
360-
361- _pythons_script_language = None
386+ _unregister_pythonscript_language()
362387
363388 if p_level == GDEXTENSION_INITIALIZATION_SERVERS:
364389
365390 # Unregister Python classes from Godot's classDB
366391
367- PythonScript._PythonScript__godot_extension_unregister_class()
368- PythonScriptLanguage._PythonScriptLanguage__godot_extension_unregister_class()
392+ _unregister_pythonscript_classes()
393+ _cleanup_loaded_classes_and_singletons()
394+
395+ # TODO: needed ?
396+ # gc_protector = _get_extension_gc_protector()
397+ # print('!!!!!!!! gc_protector', repr(gc_protector))
398+ # gc_protector.clear()
0 commit comments