4141
4242typedef enum {
4343 STALLED , // Intitial state
44+
4445 ENTRYPOINT_CALLED , // pythonscript_init called
4546 ENTRYPOINT_RETURNED , // pythonscript_init returns
4647
47- PYTHON_INTERPRETER_INIT ,
48- PYTHONSCRIPT_MODULE_INIT ,
49- PYTHONSCRIPT_INTERNAL_INIT ,
50-
51- // All set !
52- READY ,
53-
54- // Teardown
55- PYTHONSCRIPT_MODULE_TEARDOWN ,
56- PYTHON_INTERPRETER_TEARDOWN ,
48+ PYTHON_INTERPRETER_READY ,
5749
5850 CRASHED , // Something went wrong :'(
5951} PythonscriptState ;
@@ -100,23 +92,15 @@ DLL_EXPORT void pythonscript_gdstringname_delete(GDExtensionStringNamePtr ptr) {
10092 pythonscript_gdextension->print_warning(msg, __func__, __FILE__, __LINE__, false); \
10193}
10294
103- static void _late_initialize () {
104- if (state == PYTHONSCRIPT_INTERNAL_INIT ) {
105- _pythonscript_late_init ();
106- state = READY ;
107- }
108- }
109-
110- static void _early_initialize () {
95+ // Initialize Python interpreter & godot
96+ static void _initialize_python () {
11197 if (state != ENTRYPOINT_RETURNED ) {
11298 printf ("Pythonscript: Invalid internal state (this should never happen !)\n" );
11399 goto error ;
114100 }
115101
116102 // Initialize CPython interpreter
117- state = PYTHON_INTERPRETER_INIT ;
118103
119- PyStatus status ;
120104 PyConfig config ;
121105 PyConfig_InitIsolatedConfig (& config );
122106 config .configure_c_stdio = 1 ;
@@ -165,22 +149,24 @@ static void _early_initialize() {
165149 gdstring_destructor (gd_basedir_path );
166150
167151 // 4) Configure pythonhome with base dir
168- status = PyConfig_SetBytesString (
169- & config ,
170- & config .home ,
171- basedir_path
172- );
173- pythonscript_gdextension -> mem_free (basedir_path );
174- if (PyStatus_Exception (status )) {
175- GD_PRINT_ERROR ("Pythonscript: Cannot initialize Python interpreter" );
176- GD_PRINT_ERROR (status .err_msg );
177- goto error ;
152+ {
153+ PyStatus status = PyConfig_SetBytesString (
154+ & config ,
155+ & config .home ,
156+ basedir_path
157+ );
158+ pythonscript_gdextension -> mem_free (basedir_path );
159+ if (PyStatus_Exception (status )) {
160+ GD_PRINT_ERROR ("Pythonscript: Cannot initialize Python interpreter" );
161+ GD_PRINT_ERROR (status .err_msg );
162+ goto error ;
163+ }
178164 }
179165 }
180166
181167 // Set program name
182168 {
183- status = PyConfig_SetBytesString (
169+ PyStatus status = PyConfig_SetBytesString (
184170 & config ,
185171 & config .program_name ,
186172 // TODO: retrieve real argv[0]
@@ -197,12 +183,14 @@ static void _early_initialize() {
197183 // This is much simpler this way given we will have acces to Godot API
198184 // through the nice Python bindings this way
199185
200- /* Read all configuration at once */
201- status = PyConfig_Read (& config );
202- if (PyStatus_Exception (status )) {
203- GD_PRINT_ERROR ("Pythonscript: Cannot initialize Python interpreter" );
204- GD_PRINT_ERROR (status .err_msg );
205- goto error ;
186+ // Read all configuration at once
187+ {
188+ PyStatus status = PyConfig_Read (& config );
189+ if (PyStatus_Exception (status )) {
190+ GD_PRINT_ERROR ("Pythonscript: Cannot initialize Python interpreter" );
191+ GD_PRINT_ERROR (status .err_msg );
192+ goto error ;
193+ }
206194 }
207195
208196 // TODO
@@ -214,11 +202,13 @@ static void _early_initialize() {
214202 // goto error;
215203 // }
216204
217- status = Py_InitializeFromConfig (& config );
218- if (PyStatus_Exception (status )) {
219- GD_PRINT_ERROR ("Pythonscript: Cannot initialize Python interpreter" );
220- GD_PRINT_ERROR (status .err_msg );
221- goto error ;
205+ {
206+ PyStatus status = Py_InitializeFromConfig (& config );
207+ if (PyStatus_Exception (status )) {
208+ GD_PRINT_ERROR ("Pythonscript: Cannot initialize Python interpreter" );
209+ GD_PRINT_ERROR (status .err_msg );
210+ goto error ;
211+ }
222212 }
223213
224214// // TODO: site.USER_SITE seems to point to an invalid location in ~/.local
@@ -234,78 +224,75 @@ static void _early_initialize() {
234224 PyRun_SimpleString ("import sys\nprint('PYTHON_PATH:', sys.path)\n" );
235225#endif
236226
237- state = PYTHONSCRIPT_MODULE_INIT ;
238227
239- int ret = import__pythonscript ();
240- if (ret != 0 ) {
241- GD_PRINT_ERROR ("Pythonscript: Cannot load Python module `_pythonscript`" );
242- goto error ;
228+ {
229+ int ret = import__pythonscript ();
230+ if (ret != 0 ) {
231+ GD_PRINT_ERROR ("Pythonscript: Cannot load Python module `_pythonscript`" );
232+ goto post_init_error ;
233+ }
243234 }
244235
245- state = PYTHONSCRIPT_INTERNAL_INIT ;
246-
247- _pythonscript_early_init ();
248236
249237 PyConfig_Clear (& config );
250238
251239 // Release the Kraken... er I mean the GIL !
252240 gilstate = PyEval_SaveThread ();
253241
242+ state = PYTHON_INTERPRETER_READY ;
254243 return ;
255244
256- error :
257-
258- if (state > PYTHONSCRIPT_MODULE_INIT && state < PYTHONSCRIPT_MODULE_TEARDOWN ) {
259- _pythonscript_deinitialize ();
260- }
261-
262- if (state > PYTHON_INTERPRETER_INIT && state < PYTHON_INTERPRETER_TEARDOWN ) {
263- PyConfig_Clear (& config );
245+ post_init_error :
246+ PyConfig_Clear (& config );
247+ {
264248 int ret = Py_FinalizeEx ();
265249 if (ret != 0 ) {
266250 GD_PRINT_ERROR ("Pythonscript: Cannot finalize Python interpreter" );
267251 }
268252 }
269253
254+ error :
270255 state = CRASHED ;
271256}
272257
273- static void _deinitialize ( void * userdata , GDExtensionInitializationLevel p_level ) {
274- ( void ) userdata ; // acknowledge unreferenced parameter
275- if ( p_level != GDEXTENSION_INITIALIZATION_SERVERS ) {
276- return ;
258+ static void _deinitialize_python ( ) {
259+ if ( state != PYTHON_INTERPRETER_READY ) {
260+ printf ( "Pythonscript: Invalid internal state (this should never happen !)\n" );
261+ goto error ;
277262 }
278263
279- if (state > PYTHON_INTERPRETER_INIT && state < PYTHON_INTERPRETER_TEARDOWN ) {
280-
281- // Re-acquire the gil in order to finalize properly
282- PyEval_RestoreThread (gilstate );
283-
284- if (state > PYTHONSCRIPT_MODULE_INIT && state < PYTHONSCRIPT_MODULE_TEARDOWN ) {
285- _pythonscript_deinitialize ();
286- }
264+ // Re-acquire the gil in order to finalize properly
265+ PyEval_RestoreThread (gilstate );
287266
288- int ret = Py_FinalizeEx ();
289- if (ret != 0 ) {
290- GD_PRINT_ERROR ("Pythonscript: Cannot finalize Python interpreter" );
291- state = CRASHED ;
292- return ;
293- }
267+ int ret = Py_FinalizeEx ();
268+ if (ret != 0 ) {
269+ GD_PRINT_ERROR ("Pythonscript: Cannot finalize Python interpreter" );
294270 }
295271
296272 state = STALLED ;
273+ return ;
274+
275+ error :
276+ state = CRASHED ;
297277}
298278
299279static void _initialize (void * userdata , GDExtensionInitializationLevel p_level ) {
300280 (void ) userdata ; // acknowledge unreferenced parameter
281+ if (state == ENTRYPOINT_RETURNED && p_level == GDEXTENSION_INITIALIZATION_CORE ) {
282+ _initialize_python ();
283+ }
284+ if (state != CRASHED ) {
285+ _pythonscript_initialize (p_level );
286+ }
287+ }
301288
302- // Language registration must be done at `GDEXTENSION_INITIALIZATION_SERVERS`
303- // level which is too early to have have everything we need for (e.g. `OS` singleton).
304- // So we have to do another init step at `GDEXTENSION_INITIALIZATION_SCENE` level.
305- if ( p_level == GDEXTENSION_INITIALIZATION_SERVERS ) {
306- _early_initialize ();
307- } else if (p_level == GDEXTENSION_INITIALIZATION_SCENE ) {
308- _late_initialize ();
289+ static void _deinitialize ( void * userdata , GDExtensionInitializationLevel p_level ) {
290+ ( void ) userdata ; // acknowledge unreferenced parameter
291+ if ( state != CRASHED ) {
292+ _pythonscript_deinitialize ( p_level );
293+ }
294+ if (state == PYTHON_INTERPRETER_READY && p_level == GDEXTENSION_INITIALIZATION_CORE ) {
295+ _deinitialize_python ();
309296 }
310297}
311298
@@ -381,7 +368,9 @@ DLL_EXPORT GDExtensionBool pythonscript_init(
381368 GD_PRINT_WARNING (buff );
382369 }
383370
384- r_initialization -> minimum_initialization_level = GDEXTENSION_INITIALIZATION_SERVERS ;
371+ // Initialize as early as possible, this way we can have 3rd party plugins written
372+ // in Python/Cython that can do things at this level
373+ r_initialization -> minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE ;
385374 r_initialization -> userdata = NULL ;
386375 r_initialization -> initialize = _initialize ;
387376 r_initialization -> deinitialize = _deinitialize ;
0 commit comments