openvibers/source.openvibe.games Commits

Diagnose client JS world-load crash + local-test improvements

CO Copilot committed 2 Jul 2026 · 404b07b8cb · 3 files, +28 −3

Isolated the "crash on world load" to the client JS runtime init: with
ov_client_js_enabled 0 the world loads and stays stable in-game, so the
crash is in the (previously unproven-at-runtime) ovjs_core.c path.

- Instrument ovjs_create with per-phase host->log traces and log each JS
  file as it loads, so console.log pinpoints the exact crash phase.
- Lower JS_SetMaxStackSize 1MB -> 256KB: on Windows the main-thread stack
  is ~1MB, so a 1MB JS recursion limit lets deep calls overflow the real
  C stack and hard-crash instead of raising a catchable JS error (prime
  suspect for the Windows-only crash).
- Local testing: OPENVIBE_STARTUP_MAP env loads straight into a local
  listen-server world (bypasses the dedicated travel/token flow); add
  "sandbox" to the client mode allowlist + local connect map (27020).

Changes

ddiff --git a/sdk/openvibe/client/hl2mp/openvibe_client.cpp b/sdk/openvibe/client/hl2mp/openvibe_client.cpp
iindex 8100ab0..0ed8936 100644
---- a/sdk/openvibe/client/hl2mp/openvibe_client.cpp
++++ b/sdk/openvibe/client/hl2mp/openvibe_client.cpp
@@@ -76,6 +76,7 @@ static const char *s_OpenVibeModes[] =
"deathrun",
"fortwars",
"traitortown",
++ "sandbox",
};
static bool OV_IsModeAllowed( const char *pszMode )
@@@ -95,6 +96,7 @@ static const char *OV_LocalConnectForMode( const char *pszMode )
if ( !Q_stricmp( pszMode, "deathrun" ) ) return "127.0.0.1:27017";
if ( !Q_stricmp( pszMode, "fortwars" ) ) return "127.0.0.1:27018";
if ( !Q_stricmp( pszMode, "traitortown" ) ) return "127.0.0.1:27019";
++ if ( !Q_stricmp( pszMode, "sandbox" ) ) return "127.0.0.1:27020";
return "127.0.0.1:27015";
}
ddiff --git a/sdk/openvibe/shared/ovjs_core.c b/sdk/openvibe/shared/ovjs_core.c
iindex f7cbee0..306443f 100644
---- a/sdk/openvibe/shared/ovjs_core.c
++++ b/sdk/openvibe/shared/ovjs_core.c
@@@ -207,6 +207,7 @@ int ovjs_eval(OVJSCore *c, const char *code, const char *filename)
static int OVJS_LoadFile(OVJSCore *c, const char *path)
{
if (!c->host || !c->host->readFile) return 0;
++ if (c->host->log) { char b[256]; snprintf(b, sizeof(b), "core: loading %s", path); c->host->log(b); }
char *code = c->host->readFile(path);
if (!code) {
if (c->host->warn) {
@@@ -250,8 +251,14 @@ static void OVJS_RegisterBindings(OVJSCore *c)
JS_FreeValue(c->ctx, global);
}
++static void OVJS_Trace(const OVJSHost *host, const char *msg)
++{
++ if (host && host->log) host->log(msg);
++}
++
OVJSCore *ovjs_create(const OVJSHost *host, int isServerRealm, const char *mode)
{
++ OVJS_Trace(host, "core: ovjs_create begin");
OVJSCore *c = (OVJSCore *)calloc(1, sizeof(OVJSCore));
if (!c) return NULL;
c->host = host;
@@@ -262,15 +269,23 @@ OVJSCore *ovjs_create(const OVJSHost *host, int isServerRealm, const char *mode)
c->rt = JS_NewRuntime();
if (!c->rt) { free(c); return NULL; }
JS_SetMemoryLimit(c->rt, 32 * 1024 * 1024);
-- JS_SetMaxStackSize(c->rt, 1024 * 1024);
++ /* Keep well under the OS thread stack (Windows main thread ~1MB): if the JS
++ * recursion limit exceeds the real C stack, deep calls overflow and crash
++ * the process instead of raising a catchable JS error. */
++ JS_SetMaxStackSize(c->rt, 256 * 1024);
++ OVJS_Trace(host, "core: runtime created");
c->ctx = JS_NewContext(c->rt);
if (!c->ctx) { JS_FreeRuntime(c->rt); free(c); return NULL; }
JS_SetContextOpaque(c->ctx, c);
++ OVJS_Trace(host, "core: context created");
OVJS_RegisterBindings(c);
-- if (!OVJS_LoadCoreFiles(c)) { ovjs_destroy(c); return NULL; }
++ OVJS_Trace(host, "core: bindings registered");
++ if (!OVJS_LoadCoreFiles(c)) { OVJS_Trace(host, "core: LoadCoreFiles FAILED"); ovjs_destroy(c); return NULL; }
++ OVJS_Trace(host, "core: core files loaded");
OVJS_LoadGamemode(c);
++ OVJS_Trace(host, "core: gamemode loaded — create done");
return c;
}
ddiff --git a/tools/run-client-proton-x64.sh b/tools/run-client-proton-x64.sh
iindex e029218..8353d9e 100755
---- a/tools/run-client-proton-x64.sh
++++ b/tools/run-client-proton-x64.sh
@@@ -26,6 +26,14 @@ if [ "${1:-}" != "" ] && [ "${2:-}" != "" ]; then
CONNECT_ARGS="+connect $1:$2"
fi
++# Load straight into a local listen-server world (bypasses the dedicated-server
++# travel/token flow) for reliable local testing and crash reproduction:
++# OPENVIBE_STARTUP_MAP=ov_hub tools/run-client-proton-x64.sh
++STARTUP_MAP_ARGS=""
++if [ -n "${OPENVIBE_STARTUP_MAP:-}" ]; then
++ STARTUP_MAP_ARGS="+map ${OPENVIBE_STARTUP_MAP}"
++fi
++
echo "Launching OpenVibe: Source via Proton..."
echo " Game: $GAME_DIR"
echo " Proton: $GE_PROTON"
@@@ -67,4 +75,4 @@ exec "$GE_PROTON/proton" waitforexitandrun \
+exec openvibe_proton_stability.cfg \
+con_logfile openvibe_proton_console.log \
+exec openvibe_proton_client.cfg \
-- $CONNECT_ARGS
++ $CONNECT_ARGS $STARTUP_MAP_ARGS