From 9068d961306a674f4959d0e35eb01406b47385ba Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sat, 6 Jun 2026 10:38:10 -0500 Subject: [PATCH] Add timeouts --- assets/init.js | 4 +- src/dusk/script/module/engine/moduleframe.h | 45 +++++++++++++ src/dusk/script/module/engine/moduletimeout.h | 67 +++++++++++++++++++ src/dusk/script/module/modulelist.c | 11 +++ src/dusk/script/module/modulelist.h | 6 ++ src/dusk/script/script.c | 1 + 6 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 src/dusk/script/module/engine/moduleframe.h create mode 100644 src/dusk/script/module/engine/moduletimeout.h diff --git a/assets/init.js b/assets/init.js index e34e1ce2..611446af 100644 --- a/assets/init.js +++ b/assets/init.js @@ -13,9 +13,9 @@ Console.print('Platform: ' + (platformNames[System.platform] || 'Unknown')); // Testing async/await async function testAsync() { Console.print('Testing async/await...'); - await new Promise(resolve => requestAnimationFrame(resolve)); + await frame(); Console.print('First await done!'); - await new Promise(resolve => setTimeout(resolve, 1000)); + await timeout(1000); Console.print('Async/await works!'); } diff --git a/src/dusk/script/module/engine/moduleframe.h b/src/dusk/script/module/engine/moduleframe.h new file mode 100644 index 00000000..167ae09f --- /dev/null +++ b/src/dusk/script/module/engine/moduleframe.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "script/module/modulebase.h" + +#define MODULE_FRAME_PENDING_MAX 64 + +static jerry_value_t MODULE_FRAME_PENDING[MODULE_FRAME_PENDING_MAX]; +static uint32_t MODULE_FRAME_PENDING_COUNT = 0; + +moduleBaseFunction(moduleFrameFrame) { + if(MODULE_FRAME_PENDING_COUNT >= MODULE_FRAME_PENDING_MAX) { + return moduleBaseThrow("Too many pending frame() calls"); + } + jerry_value_t promise = jerry_promise(); + MODULE_FRAME_PENDING[MODULE_FRAME_PENDING_COUNT++] = jerry_value_copy(promise); + return promise; +} + +static void moduleFrameFlush(void) { + uint32_t count = MODULE_FRAME_PENDING_COUNT; + MODULE_FRAME_PENDING_COUNT = 0; + for(uint32_t i = 0; i < count; i++) { + jerry_value_t ret = jerry_promise_resolve(MODULE_FRAME_PENDING[i], jerry_undefined()); + jerry_value_free(ret); + jerry_value_free(MODULE_FRAME_PENDING[i]); + } +} + +static void moduleFrameInit(void) { + MODULE_FRAME_PENDING_COUNT = 0; + moduleBaseDefineGlobalMethod("frame", moduleFrameFrame); +} + +static void moduleFrameDispose(void) { + for(uint32_t i = 0; i < MODULE_FRAME_PENDING_COUNT; i++) { + jerry_value_free(MODULE_FRAME_PENDING[i]); + } + MODULE_FRAME_PENDING_COUNT = 0; +} diff --git a/src/dusk/script/module/engine/moduletimeout.h b/src/dusk/script/module/engine/moduletimeout.h new file mode 100644 index 00000000..78575b98 --- /dev/null +++ b/src/dusk/script/module/engine/moduletimeout.h @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "script/module/modulebase.h" +#include "time/time.h" + +#define MODULE_TIMEOUT_PENDING_MAX 64 + +typedef struct { + jerry_value_t promise; + float_t targetTime; +} moduletimeoutentry_t; + +static moduletimeoutentry_t MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_MAX]; +static uint32_t MODULE_TIMEOUT_PENDING_COUNT = 0; + +moduleBaseFunction(moduleTimeoutTimeout) { + moduleBaseRequireArgs(1); + moduleBaseRequireNumber(0); + + if(MODULE_TIMEOUT_PENDING_COUNT >= MODULE_TIMEOUT_PENDING_MAX) { + return moduleBaseThrow("Too many pending timeout() calls"); + } + + float_t ms = moduleBaseArgFloat(0); + jerry_value_t promise = jerry_promise(); + MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_COUNT].promise = jerry_value_copy(promise); + MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_COUNT].targetTime = TIME.time + ms / 1000.0f; + MODULE_TIMEOUT_PENDING_COUNT++; + return promise; +} + +static void moduleTimeoutFlush(void) { + uint32_t i = 0; + while(i < MODULE_TIMEOUT_PENDING_COUNT) { + if(TIME.time >= MODULE_TIMEOUT_PENDING[i].targetTime) { + jerry_value_t ret = jerry_promise_resolve( + MODULE_TIMEOUT_PENDING[i].promise, jerry_undefined() + ); + jerry_value_free(ret); + jerry_value_free(MODULE_TIMEOUT_PENDING[i].promise); + MODULE_TIMEOUT_PENDING_COUNT--; + if(i < MODULE_TIMEOUT_PENDING_COUNT) { + MODULE_TIMEOUT_PENDING[i] = MODULE_TIMEOUT_PENDING[MODULE_TIMEOUT_PENDING_COUNT]; + } + } else { + i++; + } + } +} + +static void moduleTimeoutInit(void) { + MODULE_TIMEOUT_PENDING_COUNT = 0; + moduleBaseDefineGlobalMethod("timeout", moduleTimeoutTimeout); +} + +static void moduleTimeoutDispose(void) { + for(uint32_t i = 0; i < MODULE_TIMEOUT_PENDING_COUNT; i++) { + jerry_value_free(MODULE_TIMEOUT_PENDING[i].promise); + } + MODULE_TIMEOUT_PENDING_COUNT = 0; +} diff --git a/src/dusk/script/module/modulelist.c b/src/dusk/script/module/modulelist.c index ed77dd84..8c19ed34 100644 --- a/src/dusk/script/module/modulelist.c +++ b/src/dusk/script/module/modulelist.c @@ -11,6 +11,8 @@ #include "script/module/display/modulecolor.h" #include "script/module/display/modulescreen.h" #include "script/module/engine/moduleengine.h" +#include "script/module/engine/moduleframe.h" +#include "script/module/engine/moduletimeout.h" #include "script/module/entity/component/modulecomponentlist.h" #include "script/module/entity/modulecomponent.h" #include "script/module/entity/moduleentity.h" @@ -28,6 +30,8 @@ void moduleListInit(void) { moduleConsoleInit(); moduleScreenInit(); moduleEngineInit(); + moduleFrameInit(); + moduleTimeoutInit(); moduleVec3Init(); moduleComponentInit(); moduleEntityInit(); @@ -38,6 +42,11 @@ void moduleListInit(void) { moduleSystemInit(); } +void moduleListUpdate(void) { + moduleFrameFlush(); + moduleTimeoutFlush(); +} + void moduleListDispose(void) { moduleSystemDispose(); moduleSceneDispose(); @@ -47,6 +56,8 @@ void moduleListDispose(void) { moduleEntityDispose(); moduleComponentDispose(); moduleVec3Dispose(); + moduleTimeoutDispose(); + moduleFrameDispose(); moduleEngineDispose(); moduleScreenDispose(); moduleConsoleDispose(); diff --git a/src/dusk/script/module/modulelist.h b/src/dusk/script/module/modulelist.h index e789033d..71fd3b9c 100644 --- a/src/dusk/script/module/modulelist.h +++ b/src/dusk/script/module/modulelist.h @@ -13,6 +13,12 @@ */ void moduleListInit(void); +/** + * Flushes per-frame module state. Must be called once per frame before + * jerry_run_jobs() so that frame() promises resolve in the same tick. + */ +void moduleListUpdate(void); + /** * Disposes all of the internal (C) script modules. */ diff --git a/src/dusk/script/script.c b/src/dusk/script/script.c index 00758b94..cc9fcbec 100644 --- a/src/dusk/script/script.c +++ b/src/dusk/script/script.c @@ -28,6 +28,7 @@ errorret_t scriptInit(void) { } errorret_t scriptUpdate() { + moduleListUpdate(); jerry_value_t ret = jerry_run_jobs(); if(jerry_value_is_exception(ret)) {