Docs · Engine notes
Maturity assessment
How mature V3X is as a platform, area by area, with the evidence for each score.
Copied from docs/maturity.md in the V3X repository, file dated 2026-11-13.
Status of V3X as a platform (loader, bundled plugins, SDK, plugin API, tests and releases).
Scores are out of 5. Overall: about 2.7 / 5 = alpha (independent review, 2026-11-13, before the
loader 0.5.0 hardening). Hardening work is in progress (see “In progress”); the scores below are the
review’s and have not been updated for it. @main updates the “after verification” column once
the hardening is verified.
How to read the evidence: every claim cites a file:line or a test name, as of 2026-11-13.
[unverified] marks claims that were not re-checked when this page was written. Line numbers in
src/core.c and include/v3x.h may move: the sdk worker is still editing them.
Scores
| area | review (pre-hardening) | after verification | main reasons in the review |
|---|---|---|---|
| Loader | 3 / 5 | TBD by @main | no fault isolation; no global build gate; load order = FindFirstFile order; a failed plugin was not rolled back |
| Bundled plugins | 2.5 / 5 | TBD | many measure-only or smoke-tested plugins; crash history; default-on plugins with smoke tests only |
| SDK | 3 / 5 | TBD | clone + zig unpinned; assumes reverse-engineering skill |
| Plugin API | 3 / 5 | TBD | no unregister; no game-level abstractions; script layer (b) exists now, layers (a) and (c) do not |
| Tests and releases | 2 / 5 | TBD | no test runner, no CI, no releases (an installer exists now) |
| Overall | ~2.7 = alpha | TBD |
Loader (3 / 5)
What is solid:
version.dllproxy that forwards the real exports and hooks the entry point; plugins load before the game’s CRT (README “How the loader works”,src/proxy.c,src/core.c). End-to-end teststest/harness.c,test/api_v4_test.c,test/shutdown_test.c(20 runs x 2 modes, every plugin, exit within 10 s).- Per-plugin manifests with
min_api/REQUIRE_BUILDrefusals (test/api_v4_test.c,test/v4_plugin.c),[plugins]skip list inv3x.ini(CHANGELOG.md, API v4 “Added”). - Exit safety: all API calls refuse to act once the process is exiting (CHANGELOG.md,
process_exitentry;test/shutdown_probe.c).
Gaps found by the review (pre-hardening):
- No fault isolation: a fault in a plugin’s
v3x_plugin_load,on_frame, command, event subscriber orrun_on_maincallback took the game down. Hardening adds this (see “In progress”). - No global build gate: on an unknown game build every plugin loaded; only 3 plugins had a manifest at the time (memory note of the review). Hardening adds the gate and manifests.
- Load order =
FindFirstFileorder: plugins are enumerated withFindFirstFileA/FindNextFileA(src/core.c:1383, loop tosrc/core.c:1464), i.e. directory order (NTFS: name order, not guaranteed). There is no explicit order or dependency declaration. Still open (not part of the hardening list). - Failed plugin not rolled back: hooks and patches of a plugin whose
v3x_plugin_loadreturned non-zero stayed in place. Hardening adds rollback.
Bundled plugins (2.5 / 5)
31 plugins (catalog: plugins.md). By class (from installer/profile.txt and each
plugin’s defaults):
- 11 production (shipped on by the player installer:
installer/profile.txt:9-18,:20; plusscript_extat:19, an SDK service that hooks nothing): crash_logger, content_packs, mod_menu, keep_history, ironman_console, log_filter, frame_pacer, cpu_sched, gfx_driver, mem_tuner, fast_load. All but mod_menu were played in the 4-hour session and the 1 h 44 m session of 2026-11-13 evening (docs/sessions/2026-11-13-evening.md:22-23: 28/28 loaded, no crash). mod_menu’s button was not recorded as used in game [unverified] (installer/profile.txt:11). - 6 opt-in (shipped off:
installer/profile.txt:23-28): console_plus, loc_fallback, enhance, asset_stream, lazy_mesh, sim_opt. The review’s gap “enhance / sim_opt default-on with smoke tests only” is closed for players by the installer (both0); for a developer install (./build.sh install) both still load by default with read-only or debug-only features on (plugins/enhance/enhance.ini.example:33,plugins/sim_opt/sim_opt.ini.example:5-17). - 7 measure-only (not shipped): fast_lookup, mod_loader, map_cache, lazy_gfx, par_load, tick_par,
ai_par.
onis refused in tick_par and ai_par, reserved in par_load, and without effect yet in map_cache and lazy_gfx (docs/sessions/2026-11-13-evening.md:171-176). fast_lookup’s criterion foronis met (docs/sessions/2026-11-13-evening.md:170) and mod_loader runsonin the live install with 0 mismatches (docs/sessions/2026-11-13-evening.md:35, :175). - 6 dev tools and 1 SDK service (script_ext).
Crash history (all fixed or withdrawn; details in plugins.md):
- sim_opt: 4-argument detour on a 5-argument function (docs/safety.md:12-16);
stagger_journalwithdrawn (docs/safety.md:53-56, CHANGELOG.md “Removed / withdrawn”). - enhance:
fast_speed5withdrawn (docs/re/enhance.md:145-182). - fast_lookup: crash5, clobbered volatile registers (plugins/fast_lookup/fast_lookup.c:84-87).
- console_plus: crash6, AV in
mi_free(docs/re/console.md:66). - devtools: hang at exit with the profiler on (plugins/devtools/devtools.c:31-34).
- A diagnostic plugin hurt play: alloc_tracker’s 30 s main-thread report caused ~190-200 stalls of
~0.55 s (docs/sessions/2026-11-13-evening.md:78, :83-84); it is off by default
(
plugins/alloc_tracker/alloc_tracker.ini.example:6) and not shipped.
What is solid: every plugin fails closed on anchors (docs/safety.md:102), and every plugin has an
offline or end-to-end test except hello (testing.md).
SDK (3 / 5)
What is solid: header-only helpers in sdk/ (v3x_sdk.h umbrella, mem, scan, anchor, ini, hook,
game, util, script, testkit), sdk/build_plugin.py (build / --test / --install / check,
sdk/build_plugin.py:353), templates/plugin_template/ with an offline test, test/sdk_test.c.
Gaps:
- Unpinned toolchain and source: the quick start clones the default branch
(
README.md:72) and installs the latestziglangfrom pip without a version (README.md:73,docs/getting-started.md:14);build_plugin.pyruns whateverpython -m ziglang ccis installed (sdk/build_plugin.py:65). No tag or release to pin to (git taglists nothing, 2026-11-13). - Assumes reverse-engineering skill: a plugin author must find engine code by strings, xrefs and byte shapes themselves (README “A complete plugin”, docs/reverse-engineering.md). The SDK offers no ready-made handles to game objects (see API).
Plugin API (3 / 5)
What is solid: C ABI, versioned and append-only (include/v3x.h:36, V3X_API_VERSION 5 at
include/v3x.h:39), V3X_HAS for newer fields, hook_safe that forwards all argument slots
(test/hook_safe_test.c) and can be shared (test/hook_chain_test.c), named events, frozen layouts
for v1-v4 (test/compat_v1.h … test/compat_v4.h, test/compat_test.c), ABI freeze test
test/abi_test.c.
Gaps:
- No unregister:
on_frame,register_commandandon_eventhave no removal counterpart ininclude/v3x.h(onlyunhook,include/v3x.h:196). Plugins cannot be unloaded (mod_menu: “All changes need a restart”,plugins/mod_menu/mod_menu.c:19). - No game-level abstractions: no API for countries, states, the tick or saves beyond events;
sdk/v3x_game.hcovers only the script-RNG scope check and the main-thread check (CHANGELOG.md, SDK entry). - Script layers: (b) “ship script, loc and GUI files from a plugin” exists (
plugins/script_ext,sdk/v3x_script.h,test/script_ext_test.c: 45 checks, 0 failed, re-run 2026-11-13); (a) running effect / trigger text from C and (c) C-implemented script keywords are not implemented (docs/scripting.md:8-13, :128-135). Layer (b) has not run in game (docs/scripting.md:11).
Tests and releases (2 / 5)
What exists: 39 C test programs (plus 4 test-only plugin sources) and 3 Python tests (testing.md), each printing ALL OK; offline tests
check anchors against the real exe mapped as an image. Player installer V3X-Setup.exe
(installer/, docs/install.md) with installer/test_installer.py: 49/49 passed (re-run
2026-11-13 after the profile update, on fake game folders).
Gaps:
- No test runner: tests are built and run one by one by hand (testing.md).
test/run_all.shis in progress and does not exist yet. - No CI: no
.github/or other CI configuration in the repo (2026-11-13). - No releases: no git tags, no published zip (README.md “Install in 3 steps” says so).
- The installer builds from
build/(python installer/make_dist.py --no-buildpassed its profile check on 2026-11-13 onceai_parandscript_extwere added toinstaller/profile.txt), but it has not been published as a release.
In progress (sdk worker, loader 0.5.0 / API v5)
Being added by the sdk worker at the time of writing. Code for most items is already in
src/core.c; none of it is verified here: test/api_v5_test.c was not run for this page and
test/run_all.sh does not exist yet. @main: re-score Loader, API and Tests after checking each row.
| item | where (2026-11-13) | test | verified |
|---|---|---|---|
Crash-loop safe mode: loading.marker holds the plugin being loaded; after a crash during load that plugin is skipped for one start |
src/core.c:1261-1265, message at src/core.c “crashed the game while loading” (~line 1376) |
test/api_v5_test.c (-DV5_MARKED) |
no |
Fault isolation: SEH guard around v3x_plugin_load, on_frame, run_on_main, commands, event subscribers; faulted module’s callbacks skipped, its hooks removed |
src/core.c:324-379 (guards), src/core.c:401 (disabled modules), src/core.c:430 (fault handler), src/core.c:1036 (frame skip) |
test/api_v5_test.c (-DV5_FRAME_FAULT, _CMD_FAULT, _EVENT_FAULT, _MAIN_FAULT) |
no |
Rollback of a failed / faulting v3x_plugin_load: hooks (v3x_hook_remove_owner) and patches restored |
src/core.c:988-1000 (rollback_module) |
test/api_v5_test.c (-DV5_LOAD_FAULT, -DV5_LOAD_FAIL) |
no |
Unknown-build gate: on an unknown build only plugins whose manifest matches (*, prefix, exact id) load; unknown_build = load restores the old behaviour |
src/core.c:1049 (known builds), src/core.c:1124-1141, src/core.c:1330-1363 |
test/api_v5_test.c gate, gateload |
no |
| Manifests in all plugins | V3X_PLUGIN_MANIFEST in all 31 plugins/*/*.c (grep 2026-11-13); * for crash_logger, hello, script_ext |
sdk/build_plugin.py check, test/compat_check.py |
partly (grep only) |
Test runner test/run_all.sh |
does not exist yet | - | no |
API v5 additions: log_at, log_level, loader_version, build_matches, core event config_reload |
include/v3x.h:74, src/core.c:1069 |
test/api_v5_test.c, test/compat_test.c |
no |
Not on the hardening list: explicit load order (Loader gap 3), unregister / unload (API), CI, releases, pinned toolchain.
Top 10 to 1.0
The reviewer’s list (verbatim, 2026-11-13, pre-hardening), with the status as of this page. Status “in progress” = code present, not verified (see the table above).
| # | reviewer’s item | status 2026-11-13 |
|---|---|---|
| 1 | Fault isolation around plugin load/frame/command/event callbacks + crash counter / safe mode. | in progress: SEH guards src/core.c:324-379, loading.marker src/core.c:1261-1265 |
| 2 | Global build gate: warn/auto-disable on unknown game_build_id; require manifests. | in progress: gate src/core.c:1330-1363; all 31 plugins have a manifest (grep) |
| 3 | Default enhance and sim_opt (and fast_lookup cache) to off until each is in-game verified. | for players done: enhance and sim_opt shipped off (installer/profile.txt:25, :28), fast_lookup not shipped (:42). Plugin defaults unchanged (plugins/enhance/enhance.ini.example:33, plugins/sim_opt/sim_opt.ini.example:5, plugins/fast_lookup/fast_lookup.ini.example:9 = measure) |
| 4 | Root-cause the console_plus mi_free crash. | root cause found and fixed: crash6, a CString passed by value freed memory owned by the DLL (docs/re/console.md:66, plugins/console_plus/console_plus.c:977). One clean 1 h 44 m session since (docs/sessions/2026-11-13-evening.md:17, :22-23); that is not proof |
| 5 | One test runner script + CI building everything and running offline tests. | runner in progress (test/run_all.sh not yet in the repo); no CI |
| 6 | Finish v5 consistently (core.c, abi_test.c, compat_test.c, api-stability.md). | in progress (sdk worker): V3X_API_VERSION 5 (include/v3x.h:39), test/abi_test.c, test/compat_test.c exist; docs/api-stability.md not yet in the repo |
| 7 | Plugin dependencies/load ordering and rollback on failed load. | rollback in progress (src/core.c:988-1000); ordering/dependencies open (src/core.c:1383 = FindFirstFileA order) |
| 8 | Pinned toolchain, release zip/installer, semver tags. | installer exists (installer/, 49/49); loader semver 0.5.0 (src/core.c:51); toolchain unpinned, no tags, no release |
| 9 | Docs updated to all plugins. | done 2026-11-13: plugins.md covers all 31 |
| 10 | Multiplayer detection + refuse sim-changing features there; faster startup (index scans or show feedback). | open. Only ironman_console keeps multiplayer blocked (plugins/ironman_console/ironman_console.c:1-8); sim_opt throttle is documented as single-player only (plugins/sim_opt/sim_opt.c:25-26) but neither sim_opt nor enhance contains a multiplayer check (grep for MP/multiplay finds only that comment). Startup feedback: not done |
Not verified for this page
- The whole “In progress” table (code read, not tested).
- That mod_menu’s button and loc_fallback’s output work in game.