@@ -13,6 +13,60 @@ namespace pkpy {
1313
1414void setup_bindings_generated ();
1515
16+ static bool call_next_for_coroutine (py_i64 id);
17+
18+ static void call_next_for_coroutine_no_error (py_i64 id) {
19+ py_Ref p0 = py_peek (0 );
20+ bool ok = call_next_for_coroutine (id);
21+ if (!ok) log_python_error_and_clearexc (p0);
22+ }
23+
24+ static bool call_next_for_coroutine (py_i64 id) {
25+ std::thread::id current_thread_id = std::this_thread::get_id ();
26+ if (current_thread_id != pyctx ()->main_thread_id ) {
27+ ERR_PRINT (" coroutine can only be resumed in the main thread" );
28+ std::abort ();
29+ }
30+ py_ItemRef gen = pythreadctx ()->pending_coroutines .getptr (id);
31+ if (gen == NULL ) {
32+ return RuntimeError (" cannot find coroutine by id: %i" , id);
33+ }
34+ int res = py_next (gen);
35+ if (res == 1 ) {
36+ if (py_retval ()->type != pyctx ()->tp_Variant ) {
37+ return TypeError (" coroutine yielded value must be 'godot.Signal', got '%t'" , py_typeof (py_retval ()));
38+ }
39+ Variant v = to_variant_exact (py_retval ());
40+ if (v.get_type () != Variant::SIGNAL) {
41+ CharString type_name = Variant::get_type_name (v.get_type ()).utf8 ();
42+ return TypeError (" coroutine yielded value must be 'godot.Signal', got '%s'" , type_name.get_data ());
43+ }
44+ Signal signal = v;
45+ Callable callable = callable_mp_static (call_next_for_coroutine_no_error);
46+ signal.connect (callable.bind (id), Object::CONNECT_ONE_SHOT | Object::CONNECT_DEFERRED);
47+ py_newnone (py_retval ());
48+ return true ;
49+ } else if (res == -1 ) {
50+ pythreadctx ()->pending_coroutines .erase (id);
51+ return false ; // error
52+ } else {
53+ // generator finished
54+ pythreadctx ()->pending_coroutines .erase (id);
55+ py_newnone (py_retval ());
56+ return true ;
57+ }
58+ }
59+
60+ static void setup_awaitables () {
61+ py_bindfunc (pyctx ()->godot , " start_coroutine" , [](int argc, py_Ref argv) -> bool {
62+ PY_CHECK_ARGC (1 );
63+ PY_CHECK_ARG_TYPE (0 , tp_generator);
64+ py_i64 id = argv[0 ]._i64 ;
65+ pythreadctx ()->pending_coroutines [id] = argv[0 ];
66+ return call_next_for_coroutine (id);
67+ });
68+ }
69+
1670static void setup_exports () {
1771 // export
1872 pyctx ()->tp_DefineStatement = py_newtype (" _DefineStatement" , tp_object, pyctx ()->godot , [](void *ud) {
@@ -304,6 +358,9 @@ void setup_python_bindings() {
304358#undef DEF_UNARY_OP
305359
306360 setup_bindings_generated ();
361+
362+ setup_awaitables ();
363+
307364 printf (" ==> setup_python_bindings() done!\n " );
308365}
309366
0 commit comments