105 Commits

Author SHA1 Message Date
YourWishes 8f8fa8f8d1 Scene.set() JS lifecycle, UI sprite caching, emulator test scripts
- Add Scene.set(module) so JerryScript can switch scenes via
  require()'d {init, update, dispose} modules; wire it into
  engineUpdate() and rework overworldscene.js/init.js to the new shape.
- Fix scriptManagerExecFile() never pushing its own file's directory
  onto the require() dir stack, breaking relative require() calls from
  a top-level entry script (e.g. init.js -> ./overworldscene.js).
- Cache sprite geometry across frames for uislider/uitab/uiframe
  (dialogs/textbox/settings) and give uitextbox a per-page glyph cache
  instead of one spriteBatchBuffer call per visible character. uiconsole
  drops its alloc/free vertex buffer for a fixed-size one. uifps skips
  rebuilding its label when the text hasn't changed.
- Add PSP_OPTIMIZATION_PLAN.md and a handful of UI/spritebatch unit
  tests covering the new caching logic.
- Add Dolphin/PPSSPP emulator smoke-test scripts (+ Docker variants and
  CI jobs) for GameCube/Wii/PSP.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 13:21:57 -05:00
YourWishes 07f98c119a Script stuff 2026-07-31 09:40:53 -05:00
YourWishes d49194fc4d Embed font into binary 2026-07-30 15:18:07 -05:00
YourWishes e61914bad4 Finish JerryScript Entity/Scene wiring; remove JSON serialize/deserialize
Register Entity, the generic Component wrapper, and Scene as JerryScript
classes (modulelist.c ties them together, plus their .d.ts stubs), so
scenes/entities can be built from script going forward instead of the
JSON scene format.

With scripting now the intended authoring path, drop the JSON
serialize/deserialize machinery entirely: componentdefinition_t's
serialize/deserialize callbacks, every component's *Serialize/
*Deserialize function, entitySerialize/entityDeserialize,
sceneSerialize/sceneDeserialize, and the "prefabs/<name>.json"/
"scenes/<name>.json" asset fallback in entityPrefabResolveAndApply/
scenePrefabResolveAndApply (C-coded prefabs only now). physicsshape.c
and its test are removed outright since they only existed for this.
game.c's test scene now comes from the existing overworldSceneCreate()
C builder instead of loading the now-deleted assets/scenes/test.json.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 11:19:08 -05:00
YourWishes 015d90519f WIP: start JerryScript integration (core engine + Component wrapper)
Ports the core scripting engine (scriptmanager, scriptproto, modulebase,
moduleplatform) and a generic Component JS wrapper from the old we-ball
branch, adapted to the current entitymanager_t/multi-scene architecture.

Not yet buildable: moduleentity.c, modulescene, modulelist.h/.c, and the
CMakeLists.txt for the new module subdirectories are still missing, and
engine.c isn't wired up yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 09:06:34 -05:00
YourWishes 7b4f0abfb8 Cutscene progress 2026-07-24 15:57:13 -05:00
YourWishes 0667a44e14 Restored cutscene code 2026-07-23 09:15:47 -05:00
YourWishes 0852b8463b ANIM 2026-07-21 18:55:23 -05:00
YourWishes 1436fda858 Some animation work 2026-07-21 09:29:14 -05:00
YourWishes 0826908068 First round of animation improvements 2026-07-20 16:07:38 -05:00
YourWishes 7ceb9e571d Scene prefabs 2026-07-20 15:11:38 -05:00
YourWishes 38c2f6b6f9 Add prefab support 2026-07-20 14:44:14 -05:00
YourWishes b9f06fef7a Add area and flag on physics 2026-07-20 12:31:14 -05:00
YourWishes 373f1c1010 test 2026-07-19 22:12:53 -05:00
YourWishes e80d693d85 More ui optimization 2026-07-19 17:39:38 -05:00
YourWishes ef60ddf6a8 UI Optim 2026-07-19 17:31:29 -05:00
YourWishes de0ff2e263 Fix collide issue on PSP 2026-07-19 14:51:57 -05:00
YourWishes 13a435e9c1 Test 2026-07-19 14:05:46 -05:00
YourWishes 725338cd5a Game code start 2026-07-19 11:49:13 -05:00
YourWishes acd14f46a8 Optimize PSP slightly 2026-07-19 11:15:22 -05:00
YourWishes ef78f023ed yeah whatever 2026-07-18 23:07:45 -05:00
YourWishes 85b6109792 Fixed save crash 2026-07-18 21:17:24 -05:00
YourWishes 6c5738c863 Testing physics 2026-07-18 20:53:22 -05:00
YourWishes 1174e471f6 Time fixes 2026-07-18 20:31:42 -05:00
YourWishes a618ff46fe Physics 2026-07-18 20:01:44 -05:00
YourWishes 1fa5cd316e Restore ECS 2026-07-18 19:05:51 -05:00
YourWishes 11e5d37563 Cleanup more. 2026-07-18 17:38:25 -05:00
YourWishes 9f86c20129 remove rpg 2026-07-18 17:15:45 -05:00
YourWishes 8fb1c9fb42 physics and rendering fixes 2026-07-17 21:06:21 -05:00
YourWishes 5f08337726 physics stuff 2026-07-17 19:07:32 -05:00
YourWishes 0bc80d5df3 Roadmap and physics 2026-07-17 13:09:58 -05:00
YourWishes 2432443ea6 Cleaned settings a bit 2026-07-17 09:11:19 -05:00
YourWishes fa138971e7 Console optimized slightly for rendering 2026-07-16 23:52:47 -05:00
YourWishes d7982599d1 Simplified PSP network 2026-07-16 22:55:47 -05:00
YourWishes f16c80aa0f Fixed PSP rendering 2026-07-16 21:20:49 -05:00
YourWishes ef5adf8274 PSP Network connect 2026-07-16 20:09:39 -05:00
YourWishes 2ffc65b1b1 Network conn and disconn 2026-07-16 19:32:44 -05:00
YourWishes d4a17bd98d Net 2026-07-16 19:08:32 -05:00
YourWishes dcf5f434c5 Remove vita for now 2026-07-16 15:50:19 -05:00
YourWishes 78cd973a33 Remove story and battle stuff 2026-07-16 15:37:55 -05:00
YourWishes ca02ee0352 Add camera shake 2026-07-11 11:02:09 -05:00
YourWishes fbaa54145e Fixed dolphin rendering. 2026-07-10 20:15:26 -05:00
YourWishes 28754ffbf2 Removed old scripted types 2026-07-10 13:24:21 -05:00
YourWishes 470c0eba7a Whatever, some minor map chunking improvements 2026-07-10 12:57:31 -05:00
YourWishes 7098dcec43 Cleaned some log 2026-07-09 23:25:43 -05:00
YourWishes 07137f57af Assets are slightly optimized 2026-07-09 23:25:26 -05:00
YourWishes 8b7491a3d3 Emoji support to characters 2026-07-09 13:18:48 -05:00
YourWishes 8cfa8ddfeb Weaather baseline 2026-07-08 12:57:13 -05:00
YourWishes ef284a15a1 pre-cache shader matrices 2026-07-08 12:36:40 -05:00
YourWishes 3723921573 Render culling on sceneoverworld.h 2026-07-08 12:02:41 -05:00
YourWishes 195399635e Updating mini textbox 2026-07-08 11:45:10 -05:00
YourWishes 46e2a924d3 Mini textboxes 2026-07-08 10:53:53 -05:00
YourWishes b693ea4102 Starting item and battle stuff 2026-07-08 10:05:21 -05:00
YourWishes a73f55beb0 Battle stuff
Build Dusk / build-linux (push) Successful in 7m5s
Build Dusk / build-psp (push) Successful in 1m33s
Build Dusk / build-knulli (push) Successful in 4m0s
Build Dusk / build-gamecube (push) Successful in 3m31s
Build Dusk / build-gamecube-iso (push) Successful in 3m39s
Build Dusk / build-wii (push) Successful in 3m5s
Build Dusk / build-wii-iso (push) Successful in 3m25s
2026-07-08 07:55:15 -05:00
YourWishes 0bd2491ab7 Dropdown test. 2026-07-07 15:18:33 -05:00
YourWishes 860c797c9c Last round of cleanup for settings for now. 2026-07-07 14:56:08 -05:00
YourWishes 38c5080f9f Collapsing more ui settings code 2026-07-07 14:36:19 -05:00
YourWishes fae191d8fe Settings improvements 2026-07-07 14:00:37 -05:00
YourWishes d83a953e2d First pass of language 2026-07-07 11:14:02 -05:00
YourWishes 2dcf0d0f0d UI Confirm 2026-07-07 10:12:22 -05:00
YourWishes 6dee37d8c1 Slider widget and some cleanup 2026-07-07 09:58:10 -05:00
YourWishes 3bad03afb3 Item entity 2026-07-07 07:52:22 -05:00
YourWishes 6a6d8448f7 Area cutscene controls 2026-07-07 07:28:12 -05:00
YourWishes 189babd2cf Trigger types on areas 2026-07-07 07:07:32 -05:00
YourWishes 988a0f2294 Area basics 2026-07-06 23:19:05 -05:00
YourWishes 85bf455731 entity pos sets chunk now 2026-07-04 18:43:09 -05:00
YourWishes 589e4224f3 Example global ent 2026-07-04 13:03:24 -05:00
YourWishes bd7fa154b4 Add user data to callbacks 2026-07-04 09:13:37 -05:00
YourWishes a292f1992b Change to use the Z tile system 2026-07-04 08:40:53 -05:00
YourWishes 88ddf429b7 add some entity management in prep for global entities. 2026-07-03 12:25:24 -05:00
YourWishes 7a1f6662df More cutscene tools 2026-07-03 09:17:49 -05:00
YourWishes afc68bccc6 Update test runner
Build Dusk / build-linux (push) Successful in 5m36s
Build Dusk / build-psp (push) Successful in 1m15s
Build Dusk / build-knulli (push) Successful in 4m53s
Build Dusk / build-gamecube (push) Successful in 3m51s
Build Dusk / build-gamecube-iso (push) Successful in 3m52s
Build Dusk / build-wii (push) Successful in 3m17s
Build Dusk / build-wii-iso (push) Successful in 4m54s
2026-07-02 19:20:17 -05:00
YourWishes b4cdc4a64f Add remove event
Build Dusk / run-tests (push) Failing after 5m7s
Build Dusk / build-linux (push) Successful in 5m41s
Build Dusk / build-psp (push) Successful in 1m17s
Build Dusk / build-knulli (push) Successful in 4m22s
Build Dusk / build-gamecube (push) Successful in 3m43s
Build Dusk / build-gamecube-iso (push) Successful in 3m36s
Build Dusk / build-wii (push) Successful in 3m36s
Build Dusk / build-wii-iso (push) Successful in 3m22s
2026-07-02 16:10:47 -05:00
YourWishes 3ad5afb81c Fix item crash 2026-07-02 16:04:41 -05:00
YourWishes bed3f20118 Lot of cutscene cleanup 2026-07-02 15:53:02 -05:00
YourWishes de67315178 Cutscene cleanup 2026-07-02 14:59:41 -05:00
YourWishes 8d5c0c7cad Path finding (first pass) 2026-07-02 14:08:59 -05:00
YourWishes a8271e01bd Fade cutscene items 2026-07-02 13:26:41 -05:00
YourWishes 900b3f8558 More cutscene stuff 2026-07-02 12:54:12 -05:00
YourWishes fdc4e056f9 Cutscene defs 2026-07-02 11:32:31 -05:00
YourWishes 7b98e40ccf Cutscene tests 2026-07-02 11:18:36 -05:00
YourWishes 01d89cf22c Map tweaks 2026-07-01 21:07:24 -05:00
YourWishes 503a3c799a Grid to editor 2026-07-01 20:51:46 -05:00
YourWishes 0b21388844 Fixing bugs, one at a time 2026-07-01 20:23:44 -05:00
YourWishes 117bdf0c00 Fov tweaks 2026-07-01 20:18:32 -05:00
YourWishes 172dc5d37b Tile Z is now hypotenused to 1 rather than stretching to have Z of 1. 2026-07-01 16:27:59 -05:00
YourWishes 874c6258ab New ramp types
Build Dusk / run-tests (push) Failing after 5m33s
Build Dusk / build-linux (push) Successful in 5m3s
Build Dusk / build-psp (push) Successful in 1m17s
Build Dusk / build-knulli (push) Successful in 4m45s
Build Dusk / build-gamecube (push) Successful in 3m49s
Build Dusk / build-gamecube-iso (push) Successful in 3m50s
Build Dusk / build-wii (push) Successful in 3m29s
Build Dusk / build-wii-iso (push) Successful in 4m4s
2026-07-01 16:05:02 -05:00
YourWishes a2d0a12c1a more editor stuff 2026-07-01 15:58:59 -05:00
YourWishes 38b24e1c3d editor first pass 2026-07-01 15:48:59 -05:00
YourWishes 5ecbbe296b Chunk load skin 2026-07-01 13:29:01 -05:00
YourWishes 9d7a769d8f Disable console printing on map chunk loading 2026-07-01 13:03:54 -05:00
YourWishes 9b75e5ed83 Async chunk loading 2026-07-01 12:58:33 -05:00
YourWishes a9ab8dc1d8 Chunks, models, and more 2026-07-01 08:35:01 -05:00
YourWishes a34831aa02 Add entity turn lockout 2026-06-30 21:23:34 -05:00
YourWishes 84ebaa0751 A lot of PSP optimizations 2026-06-30 21:01:11 -05:00
YourWishes 55352805ee Efficient loading of chunks now and PSP is slighty more optimized 2026-06-30 20:00:34 -05:00
YourWishes c0a3f2e16a Add scene scaling 2026-06-30 19:30:13 -05:00
YourWishes 28ff331a28 Create some test chunks and buildings 2026-06-30 19:08:39 -05:00
YourWishes f9a53ec719 Ramps fixed 2026-06-30 18:30:10 -05:00
YourWishes 6a403e6caf Add test hill 2026-06-30 18:21:46 -05:00
YourWishes a6f449bb93 example building 2 2026-06-30 16:21:47 -05:00
YourWishes 0614bfc446 example building 2026-06-30 16:21:46 -05:00
YourWishes bb020c36c1 CHUNK STUFF 2026-06-27 17:19:44 -05:00
YourWishes f17b0bfcfb Tiles 2026-06-27 08:50:55 -05:00
YourWishes 2a85c9503f npc interact turn to face player 2026-06-27 06:30:45 -05:00
727 changed files with 41924 additions and 8487 deletions
-30
View File
@@ -4,36 +4,6 @@ on:
tags:
- '*'
jobs:
run-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
python3 \
python3-pip \
python3-polib \
python3-pil \
libsdl2-dev \
libgl1-mesa-dev \
libzip-dev \
python3-dotenv \
python3-pyqt5 \
python3-opengl \
xz-utils \
liblzma-dev \
libbz2-dev \
zlib1g-dev \
git \
libssl-dev
- name: Run tests
run: ./scripts/test-linux.sh
build-linux:
runs-on: ubuntu-latest
steps:
+106
View File
@@ -0,0 +1,106 @@
name: Test Dusk
on:
pull_request:
branches:
- main
jobs:
run-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
python3 \
python3-pip \
python3-polib \
python3-pil \
libsdl2-dev \
libgl1-mesa-dev \
libzip-dev \
python3-dotenv \
python3-pyqt5 \
python3-opengl \
xz-utils \
liblzma-dev \
libbz2-dev \
zlib1g-dev \
git \
libssl-dev
- name: Run tests
run: ./scripts/test-linux.sh
# Emulator smoke tests: boot the built disc/EBOOT for a fixed window and
# confirm the emulator doesn't crash. Not yet verified against a real
# runner (no CI run has exercised these) -- continue-on-error so a
# flaky/broken emulator step doesn't block the required Linux test job.
run-tests-gamecube-dolphin:
runs-on: ubuntu-latest
continue-on-error: true
container:
image: ghcr.io/extremscorner/libogc2:latest
steps:
- name: Install Node.js
run: apt-get update && apt-get install -y nodejs
- name: Checkout repository
uses: actions/checkout@v4
- name: Install additional dependencies
run: |
apt-get install -y \
python3-pip python3-polib python3-pil \
python3-dotenv python3-pyqt5 python3-opengl xorriso \
dolphin-emu xvfb
dkp-pacman -Syu --noconfirm
dkp-pacman -S --needed --noconfirm \
gamecube-sdl2 ppc-liblzma ppc-libzip \
gamecube-tools ppc-libmad ppc-zlib-ng ppc-bzip2 ppc-zstd
- name: Build GameCube ISO and boot it in Dolphin
run: ./scripts/test-gamecube-dolphin.sh
run-tests-wii-dolphin:
runs-on: ubuntu-latest
continue-on-error: true
container:
image: ghcr.io/extremscorner/libogc2:latest
steps:
- name: Install Node.js
run: apt-get update && apt-get install -y nodejs
- name: Checkout repository
uses: actions/checkout@v4
- name: Install additional dependencies
run: |
apt-get install -y \
python3-pip python3-polib python3-pil \
python3-dotenv python3-pyqt5 python3-opengl xorriso \
dolphin-emu xvfb
dkp-pacman -Syu --noconfirm
dkp-pacman -S --needed --noconfirm \
gamecube-sdl2 ppc-liblzma ppc-libzip \
gamecube-tools ppc-libmad ppc-zlib-ng ppc-bzip2 ppc-zstd
- name: Build Wii ISO and boot it in Dolphin
run: ./scripts/test-wii-dolphin.sh
run-tests-psp-ppsspp:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup pspdev
uses: ./.github/actions/setup-pspdev
- name: Install PPSSPPHeadless build dependencies
run: |
sudo apt-get update
sudo apt-get install -y git cmake ninja-build libsdl2-dev zlib1g-dev
- name: Build PPSSPPHeadless
run: |
git clone --recursive --depth 1 https://github.com/hrydgard/ppsspp.git /tmp/ppsspp
cmake -S /tmp/ppsspp -B /tmp/ppsspp/build -DCMAKE_BUILD_TYPE=Release
cmake --build /tmp/ppsspp/build --target PPSSPPHeadless -- -j$(nproc)
echo "PPSSPP_HEADLESS_BIN=/tmp/ppsspp/build/PPSSPPHeadless" >> "$GITHUB_ENV"
- name: Build PSP EBOOT and boot it in PPSSPPHeadless
run: ./scripts/test-psp-ppsspp.sh
+106 -12
View File
@@ -1,5 +1,9 @@
# Dusk — Claude Code rules
See `STATUS.md` for a periodically-refreshed inventory of subsystem
maturity, test coverage gaps, and known open issues — check it before
assuming a subsystem is fully wired up or before picking a next task.
## File headers
Every C, H, and JS file starts with:
@@ -124,18 +128,16 @@ Set `DUSK_TARGET_SYSTEM` at CMake configure time to select a platform:
| `linux` | `DUSK_LINUX` | Linux desktop |
| `knulli` | `DUSK_KNULLI` | Knulli (handheld)|
| `psp` | `DUSK_PSP` | Sony PSP |
| `vita` | `DUSK_VITA` | PlayStation Vita |
| `gamecube` | `DUSK_GAMECUBE` | Nintendo GameCube|
| `wii` | `DUSK_WII` | Nintendo Wii |
### Layer structure
```
src/dusk/ core, platform-agnostic game logic
src/duskgl/ OpenGL abstraction (Linux, Knulli, PSP, Vita)
src/dusksdl2/ SDL2 window + input (Linux, Knulli, PSP, Vita)
src/duskgl/ OpenGL abstraction (Linux, Knulli, PSP)
src/dusksdl2/ SDL2 window + input (Linux, Knulli, PSP)
src/dusklinux/ Linux + Knulli platform impl
src/duskpsp/ PSP platform impl
src/duskvita/ Vita platform impl
src/duskdolphin/ GameCube / Wii platform impl (no SDL2/OpenGL)
```
@@ -190,21 +192,110 @@ simply left undefined — the core guards calls with `#ifdef`.
## Adding a new entity component
1. Create `src/dusk/entity/component/<category>/entityMyComp.h/.c` with
struct `entityMyComp_t`, `entityMyCompInit()`, and optionally
`entityMyCompDispose()`.
2. Add the include to `src/dusk/entity/componentlist.h` header block.
3. Add a row to `src/dusk/entity/componentlist.h`:
`entityMyCompDispose()`, `entityMyCompRender()`.
2. Add the include to `src/dusk/entity/componentlist.h` header block
(or `src/duskrpg/entity/gamecomponentlist.h` for a game-specific
component, appended after the engine's inbuilt ones).
3. Add a row:
```c
X(MYCOMP, entityMyComp_t, myComp, entityMyCompInit, NULL, NULL)
```
This auto-generates the enum, union field, and definition entry.
Params are `(enumName, type, field, init, dispose, render)` — pass
`NULL` for any callback the component doesn't need. This
auto-generates the enum, union field, and definition entry.
4. If JS-facing, create the script module and `.d.ts` (see below).
Entities/components/scenes have no JSON serialize/deserialize path —
that was removed in favor of building scenes from C-coded prefabs
(below) or from JerryScript (`Entity`/`Component`/`Scene`, see
"Adding a new script (JS) module").
---
## Adding a new entity/scene prefab
Entity prefabs (`src/dusk/entity/entityprefab.h`) and scene prefabs
(`src/dusk/scene/sceneprefab.h`) follow the same pattern:
1. Write an apply function: `errorret_t entityPrefabXxxApply(mgr,
entityId)` (or `errorret_t scenePrefabXxxApply(sceneId)`), building
up the entity/scene with the normal component/entity APIs.
2. Add an entry to the sentinel-terminated `ENTITY_PREFABS[]` (in
`src/dusk/entity/entityprefablist.h`, or a game-specific list it
includes) or `SCENE_PREFABS[]`:
```c
{ .name = "MY_PREFAB", .extends = "", .apply = entityPrefabXxxApply }
```
`extends` names another prefab to apply first (recurses through
`entityPrefabResolveAndApply`/`scenePrefabResolveAndApply`), or `""`
for none. Do not add an enum or count field — the array is iterated
until `.name[0] == '\0'`.
3. `entityPrefabResolveAndApply`/`scenePrefabResolveAndApply` only
resolve names against the C-coded registry above — there is no JSON
asset fallback. Throws if no prefab with that name is registered.
---
## Adding a new cutscene item type
1. Create `src/duskrpg/cutscene/item/<category>/cutsceneMyItem.h/.c`
with a data struct (e.g. `cutscenemyitem_t`) and
`cutsceneMyItemStart(item, data)` / `cutsceneMyItemUpdate(item,
data)` (the latter returns `true` once the item has completed). Add
a matching `cutscenemyitemdata_t` runtime-data struct only if the
item needs per-run state across ticks (most don't).
2. Add `CUTSCENE_ITEM_TYPE_MY_ITEM` to the enum and a union member to
`cutsceneitem_t` (and `cutsceneitemdata_t` if it has runtime data) in
`src/duskrpg/cutscene/item/cutsceneitem.h`.
3. Register the `{ start, update }` pair in `CUTSCENE_ITEM_CALLBACKS[]`
in `cutsceneitem.c`.
4. Add an authoring macro to `src/duskrpg/cutscene/cutscene.h`:
```c
#define CUTSCENE_MY_ITEM(ARGS...) \
{ .type = CUTSCENE_ITEM_TYPE_MY_ITEM, .myItem = { ARGS } }
```
used inside a `CUTSCENE(NAME, SIZE, PAUSE_TYPE, ...)` block.
---
## Save system
Save data lives under `src/dusk/save/` (`save.h`/`savefile.h`/
`saveplatform.h`). Slots are fixed-count (`SAVE_FILE_COUNT_MAX`), each
holding a yyjson document persisted with its byte size and a CRC32
checksum. `saveLoad`/`saveSave` read/write the JSON fresh every call —
callers own the returned/passed `yyjson_doc`/`yyjson_mut_doc` and must
free it themselves. Actual file I/O goes through platform-specific
`saveplatform_t`/stream hooks (one implementation per platform under
`src/dusk<platform>/save/`) — do not add direct filesystem calls to the
core `save.c`, extend the platform stream hooks instead.
## Network system
`src/dusk/network/` (`network.h`) is a connection-state layer only — a
`networkstate_t` state machine (`DISCONNECTED`/`CONNECTING`/`CONNECTED`/
`DISCONNECTING`) plus an HTTP client (`network/http/`) used for one-off
requests. It is not a multiplayer/replication protocol — that layer
doesn't exist yet (see `ROADMAP.md` items on the socket server/client
and packet handlers). Platform-specific connection logic (e.g. PSP's
`sceNetApctl` polling, GameCube/Wii's `if_config()`) lives under
`src/dusk<platform>/network/`, wired through `networkplatform.h` macros
the same way display/input are. Whenever this eventually grows a
multiplayer protocol, apply `ROADMAP.md`'s principle: never trust
incoming packet data — validate defensively with `errorret_t`/
`errorThrow()`, not asserts.
## Adding a new script (JS) module
Dusk embeds JerryScript (`src/dusk/script/`, fetched via
`cmake/modules/Findjerryscript.cmake`). Today only `Entity`, the
generic `Component` wrapper, and `Scene` are registered (see
`src/dusk/script/module/modulelist.c`) — no per-component-type typed
wrappers exist yet (e.g. no `.position` on a `POSITION` component);
`entity.add(TYPE)`/`entity.getComponent(TYPE)` always return the
generic `Component`.
1. Create `src/dusk/script/module/<category>/moduleMyMod.h/.c`.
- Declare `extern scriptproto_t MODULE_MYMOD_PROTO;` in the header.
- Use `moduleBaseFunction(name)` to define JS-callable functions.
- Use `moduleBaseFunction(name)` to define JS-callable functions
these are the one exception to "no `static` in `.c` files": the
macro itself expands to a `static jerry_value_t name(...)`
JerryScript external-handler trampoline, never called by name
from other C files, so it isn't declared in the `.h`.
- Register props/funcs in `moduleMyModInit()` with
`scriptProtoDefineProp` / `scriptProtoDefineFunc` /
`scriptProtoDefineStaticFunc`.
@@ -212,9 +303,12 @@ simply left undefined — the core guards calls with `#ifdef`.
`src/dusk/script/module/modulelist.c` and call
`moduleMyModInit()` in `moduleListInit()` (and `Dispose` in
`moduleListDispose()`).
3. For component modules also register in
`src/dusk/script/module/entity/component/modulecomponentlist.c`
so `entity.add()` returns the typed wrapper.
3. For a component module that adds a *typed* wrapper for a specific
component type, create
`src/dusk/script/module/entity/component/modulecomponentlist.c` (it
doesn't exist yet — the first such module creates it) so
`entity.add()` can return the typed wrapper instead of the generic
`Component`.
4. Create `types/<category>/mymod.d.ts` and add a
`/// <reference path="..." />` line to `types/index.d.ts`.
+260
View File
@@ -0,0 +1,260 @@
# PSP Optimization Plan
A survey of concrete memory and CPU (especially floating-point) optimization
opportunities for the PSP target, done 2026-07-31 on branch `ac2` at commit
`e61914ba` + this session's scripting work. Point-in-time findings, not a
substitute for reading the referenced source before acting on it.
## Why this exists
The PSP (Allegrex MIPS CPU, 222-333MHz, single core, 32-64MB main RAM, 2MB
eDRAM, 16KB I-cache / 16KB D-cache, no virtual memory or memory protection)
is the tightest-constrained target this engine ships to. Two rules guide
everything below, both already correctly applied in one place in this
codebase (`entityposition_t` caching its transform matrices instead of
recomputing them from position/rotation/scale every read — see "Already
correct" below):
- **Memory is finite and cannot be compacted.** No VM means a fragmented
heap after a few minutes of play can fail an allocation even with
"enough" total free bytes. Prefer static/pool allocation over
malloc/free churn; prefer trading memory for CPU only when the memory
cost is bounded and paid once.
- **CPU is finite and floating-point math is not free**, especially
trig/sqrt on the plain scalar FPU. Prefer caching a computed result
behind a dirty flag over recomputing it unconditionally; prefer
avoiding a sqrt via squared-distance comparison wherever only a
yes/no or ordering result is needed.
## Priority 1 — Entity/component memory: a union tax paid on every slot, times 4 scenes
**The single biggest finding.** `entitymanager_t` (`src/dusk/entity/entitymanager.h:11-15`)
is a flat, statically-sized struct:
```c
typedef struct entitymanager_t {
entity_t entities[ENTITY_COUNT_MAX]; // 64
component_t components[ENTITY_COUNT_MAX * ENTITY_COMPONENT_COUNT_MAX]; // 64*16 = 1024
componentid_t entitiesWithComponent[COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX];
} entitymanager_t;
```
`component_t` (`src/dusk/entity/component.h:69-72`) holds a **tagged union**
(`componentdata_t`) sized to its largest variant. That variant is
`entityrenderable_t`'s spritebatch payload (`entityrenderable.h:25-66`):
`spritebatchsprite_t sprites[64]` at 40 bytes each (`vec3 min + vec3 max +
vec2 uvMin + vec2 uvMax`) = **2560 bytes**, versus ~28-300 bytes for every
other component type (camera, physics, animation, position, trigger).
Because the union is embedded by value in a flat array — not behind a
pointer, not sparse — **every one of the 1024 component slots in every
entity manager costs ~2580 bytes, whether it holds a 28-byte camera or
nothing at all.** `1024 * 2580 ≈ 2.52MB` per `entitymanager_t`, confirmed
by the engine's own startup log every run: `Entity manager size: 2684992
bytes (2622.06 KB)`.
`scene_t` (`src/dusk/scene/scene.h:14-18`) embeds `entitymanager_t` by
value too, and `SCENE_COUNT_MAX = 4` (`scene/scenebase.h:11`) with
`SCENE_MANAGER` declared as a plain global (`scene/scene.c:20`) — so this
~2.52MB exists as static BSS from process start for **all 4 scene slots**,
used or not. **Total: ~10.1MB reserved permanently for entity storage
alone** — 16-31% of PSP main RAM — before a single texture, mesh, or audio
asset is loaded.
**Options to fix (roughly increasing effort/risk):**
1. Pull `entityrenderablespritebatch_t` out of the component union entirely
— store spritebatch entities via a pointer/handle into a separate,
smaller fixed pool sized to how many spritebatch-renderable entities
actually coexist (almost certainly far fewer than 64 per entity, and
far fewer entities need spritebatch at all vs. mesh/material
rendering). This alone would shrink the union's dominant variant from
~2560 bytes to whatever the next-largest variant is (~300 bytes,
`entitytrigger_t`) — an ~88% reduction, dropping the ~10.1MB down to
roughly ~1.2MB.
2. Reduce `SCENE_COUNT_MAX` from 4 if 4 concurrent scenes were never a
deliberate requirement (check with the project owner — this may just
be a round-number default nobody revisited), or make scene storage
pointer-based/lazily allocated so unused scene slots cost ~0 instead
of a full `entitymanager_t`.
3. Reduce `ENTITY_COMPONENT_COUNT_MAX` (16) if entities realistically use
far fewer distinct component types simultaneously — check actual
usage across `entityprefablist.h`/`gameprefablist.h` prefabs.
Do (1) first — it's the highest-leverage, most contained change (touches
`entityrenderable.h`'s data layout and its render/dispose paths, not the
general entity/component system), and re-measure via the same startup
log line before deciding whether (2)/(3) are still worth doing.
## Priority 2 — VFPU is completely unused; all vec/mat math is scalar
The PSP's Allegrex CPU has a **VFPU** (vector floating-point unit) capable
of fast SIMD-style 4-wide float ops and hardware-accelerated matrix
operations, exposed by pspsdk's `pspvfpu`/GU "Geometry Utility" (`gum_*`)
helpers. This engine links `pspvfpu` (`cmake/targets/psp.cmake`) but
**never calls into it** — confirmed via a zero-hit grep for
`vfpu|pspmath|gum_|vcst|gu_matrix` across `src/duskpsp/` and `src/duskgl/`.
All vector/matrix math instead goes through cglm (`glm_vec3_*`,
`glm_mat4_*`), which auto-detects SIMD only for x86 (`CGLM_SSE2`/`AVX`) or
ARM (`CGLM_NEON`) — neither applies to MIPS, and no `CGLM_*` macros are
set anywhere in this repo (confirmed zero hits). **Every `glm_mat4_mul`,
every position/rotation rebuild, every physics vector op runs on the
plain scalar MIPS FPU with the VFPU sitting idle.**
This is the single largest *available* CPU win identified in this survey
— larger than any specific hot-path fix below, because it's a multiplier
on all of them. Concretely: route `entityposition.c`'s matrix
rebuild/multiply path and `physicsworld.c`'s per-body vector math through
`pspvfpu`/`gum_*` on the PSP build specifically (behind `#ifdef DUSK_PSP`,
matching the project's existing platform-guard convention), while keeping
cglm as the portable fallback for Linux/Knulli/GameCube/Wii. This is a
genuinely large effort (new platform-specific math backend, careful
correctness verification since VFPU has its own quirks around
pipelining/hazards) — scope it as its own project, not a quick pass.
## Priority 3 — UI/spritebatch rebuilds and redraws every vertex, every frame
Already flagged in `STATUS.md`/`ROADMAP.md` (item 4/5) as a known open
issue; this session's research adds concrete numbers. `meshvertex_t`
(`display/mesh/meshvertex.h:14-17`) is `{ float uv[2]; float pos[3]; }` =
**20 bytes/vertex**, no packing. `SPRITEBATCH_SPRITES_MAX = 512`,
`SPRITEBATCH_FLUSH_COUNT = 16` → 32 sprites/flush = 192 vertices = **3,840
bytes rebuilt and redrawn per flush**, with a flush forced on every
shader/material change (`spritebatch.c:38-50`) and used unconditionally
by every widget except `uiconsole.c` (`uitab.c:56`, `uislider.c:183/199/231`,
final flush in `ui.c:51`). A UI screen with ~50-100 sprites and 2-3
material changes costs an estimated **8-15KB of vertex rebuild + GU
submission every single frame**, regardless of whether the UI changed
since the last frame.
Confirmed on the PSP legacy-GL path specifically: there's no GPU buffer
re-upload cost (`meshFlushGL` is a literal no-op comment: "we use the
glClientState stuff" — `meshgl.c:91-93`; `meshDrawGL` just points
`glVertexPointer` at the CPU-side array each call), so the real cost is
(a) the CPU-side per-sprite vertex rewrite every frame and (b) GU
re-transforming the full vertex stream from RAM on every draw with no
skip for unchanged geometry.
**Fix direction** (already captured in `ROADMAP.md`'s debt backlog item 5):
extend `uiconsole.c`'s cached-mesh, dirty-flag-gated rebuild pattern to
the rest of the widget tree. This plan adds one refinement: also consider
packing `meshvertex_t` down (next item) since it multiplies this cost.
## Priority 4 — All-float vertex format wastes bandwidth and T&L cost
`meshvertex_t` uses two `float` fields (20 bytes) for every mesh and
sprite vertex, mesh-wide, with no normal or per-vertex color (color is
already handled at the material level, so that part is already optimal).
GU natively supports fixed-point 16-bit positions/UVs
(`GU_VERTEX_16BIT`/`GU_TEXTURE_16BIT`), which would roughly halve
per-vertex size and the corresponding vertex-fetch/transform cost, at the
cost of position precision (fine for UI/sprite work and most world
geometry at this engine's scale; worth checking against the largest
world coordinates actually used before committing). Pair with Priority 3
so the packing benefit compounds with the dirty-tracking benefit instead
of just reducing the cost of a rebuild that still happens every frame.
## Priority 5 — Running gameplay logic in JerryScript has a real per-frame cost on PSP
This is new since last session's work, not a pre-existing issue: `assets/
scripts/overworldscene.js`'s `update()` is now called every frame via
`scriptManagerCallGlobal("update")` (wired into `engine.c`'s
`engineUpdate()`), replacing what used to be a direct `cosf`/`sinf` C
callback (`entityUpdateAdd`). Per call, `scriptManagerCallGlobal`
(`scriptmanager.c:91-144`) does: a global-object property lookup (key is
cached, but the `jerry_object_get` dispatch still runs), full JS
interpreter call dispatch (frame setup, argument marshaling) for what's a
two-line function, and an unconditional `jerry_value_is_promise` check
every call even though `update()` is synchronous. Inside, `Math.cos`/
`Math.sin` run as JS builtin calls rather than direct libm calls.
Additionally: this project's JerryScript fork is already patched to use
32-bit float internally (`JERRY_NUMBER_TYPE_FLOAT64=0`,
`Findjerryscript.cmake`) — a deliberate, already-correct optimization for
this exact concern — but the *public* engine API (`jerry_value_as_number()`)
still returns `double`, so every native↔JS boundary crossing (every
`moduleBaseArgFloat`, every `moduleBaseVec3ToObject`) still pays a
float→double→float round trip. Also note `JERRY_MATH` is off, so
`Math.sin`/`cos` fall through to whatever generic libm the platform
provides rather than JerryScript's own fdlibm implementation — worth
checking whether turning it on changes anything measurable on PSP.
**This is one `update()` call for one scene-level script today — cheap in
absolute terms.** It becomes a real problem only if the pattern scales:
giving many individual entities their own per-frame JS update callback
would multiply all of the above per entity. **Recommendation: keep
high-frequency, hot per-entity logic (movement, camera math, physics
response) in native C update callbacks (`entityUpdateAdd`, the existing
mechanism), and reserve JS for one-time setup, infrequent/event-driven
logic, and coarse-grained per-scene orchestration** — which is exactly
what `require()` and the typed component wrappers built this session are
suited for, not a per-entity-per-frame hot path. This is a design
guideline to apply going forward, not a regression to fix in the current
`overworldscene.js` (one scene-level `update()` call per frame is fine).
## Priority 6 — No pooling/arena allocator; plain malloc/free everywhere
`memoryAllocate`/`memoryFree` (`util/memory.c`) are direct `malloc`/`free`
passthroughs (`memoryAlign``memalign`, `memoryReallocate`/`memoryResize`
`realloc`), with the only extra behavior being a global allocation-count
tracker used solely for test leak detection. No pool, arena, free-list,
or size-class allocator exists anywhere.
This survey found **no rogue per-frame heap allocations** in the hot
paths checked (render dispatch in `entityrenderable.c`, all of
`physics/*.c`) — so this is not an active bug today. But it's a
structural risk for a no-VM platform over a long play session: any future
code that does frequent small alloc/free (dynamic lists, string
building, temp buffers) will fragment the 32-64MB heap with no OS-level
recovery mechanism. **Recommendation: before adding any new subsystem
that allocates/frees frequently at runtime (not just at load time),
default to a fixed-size pool or arena for it**, following the same
"static, bounded" philosophy already used for `ENTITY_COUNT_MAX`/
`SCENE_COUNT_MAX`/`ASSET_ENTRY_COUNT_MAX` elsewhere in the engine, rather
than reaching for `memoryAllocate` per-instance.
## Already correct — don't touch without new evidence
- **`entityposition_t`'s matrix caching** (the pattern the project owner
called out as the reason for writing this plan). Verified: a full
"dirty" recompute chain (decompose + rebuild local + rebuild world) is
~10 trig calls (`asinf`/`cosf`/`atan2f`) plus at most one 4x4 matrix
multiply, and `entityPositionEnsurePRS`/`EnsureLocal`/`EnsureWorld`
(`entityposition.c:596-669`) all early-return on a flag check, only
doing that work when something actually changed. The cache is correct
and clearly worth its ~128-byte-per-entity matrix storage cost.
- **Physics narrow-phase sqrt avoidance.** All three `sqrtf` call sites
in `physicstest.c`/`physicsshapemesh.c` already sit behind a
squared-distance early-reject and only compute the real (linear)
distance once, when actually needed for penetration depth — no further
"use squared distance instead" opportunity was found here.
- **No allocations in the render/physics hot loop** (Priority 6) — this
is good and worth preserving as new code is added to those files.
- **Asset decompression already runs off the main thread.** Assets are
DEFLATE-compressed (not stored) in `dusk.dsk`, so loading pays a real
CPU cost for decompression — but every `*LoaderAsync` function
(`asset/loader/*/*.c`) runs via `ASSET.loadThread`
(`assertNotMainThread` in `asset.c:365`), so this cost is already kept
off the main thread. Low priority to change; if load-time CPU cost
becomes a measured problem later, revisit stored-vs-compressed as a
build-time flag rather than assuming compression is free.
## Suggested approach
1. **Measure before changing.** None of the above have been profiled on
real PSP hardware in this pass — this is a source-level survey, not a
profile. Before investing in Priority 1 or 2 especially, confirm with
an actual PSP build/run (or at minimum the existing "Entity manager
size" startup log plus a frame-time counter) that these are the real
bottlenecks, not just the largest numbers on paper.
2. **Priority 1 first** — it's the most contained (one component's data
layout), has the clearest before/after metric (the startup log line),
and doesn't require new platform-specific code.
3. **Priority 3 next** (extend the console's dirty-tracking pattern to
the rest of the UI) — already scoped in `ROADMAP.md`, no new design
needed, just implementation.
4. **Priority 2 (VFPU) as a dedicated project**, not a quick pass — it's
the largest potential win but touches core math plumbing and needs
careful correctness verification on real hardware.
5. Treat Priority 5 as a standing design guideline for all future
scripting work, not a one-time fix.
+90
View File
@@ -0,0 +1,90 @@
# Dusk Roadmap
Tracking upcoming milestones for the engine. See `PSP_OPTIMIZATION_PLAN.md`
for a memory/CPU optimization survey specifically targeting the PSP build
(milestone 4 below is its Priority 3).
## Upcoming milestones
1. Add a very basic physics engine, moving away from the current
tile-based movement.
2. Give entities full freedom of movement (no longer locked to tile
grid positions).
3. Update entity interaction, triggers, chunk management, and other
systems that currently assume tile-based positioning so they work
with the new 3D positioning/movement code.
4. Investigate and fix poor UI rendering performance. Rendering the
console alone tanks framerate despite the existing mesh
optimizations, so there is likely more headroom to find in the
vertex/text rendering path.
5. Create UI elements for displaying status indicators, e.g. network
connection state and save-in-progress.
6. Fully test saving end-to-end on all supported platforms.
7. Remove the tile system from chunks in favor of meshes, with
dynamic hitboxes per chunk loaded in from the chunk file data.
8. Create UI elements for network status: a connecting modal, an
error state, and a connected flag. Retire the test HTTP request
once these are in place.
9. Build the socket server and client implementation, including
handlers for the different packet types.
10. Add a dedicated multiplayer entity type, `clientplayer`, alongside
the existing `npc` and `player` types. Limit to 8 (defined
constant) for now.
11. Send and receive `clientplayer` position over the network.
12. Create a UI menu for creating a server and joining a server. For
now, join IPs are hard-coded (testing against a fixed IP of
10.0.0.94).
13. Create "handshake" packets. For now, just send the username,
enforced to be under 10 characters long.
14. Server tracks all players' positions and broadcasts them to all
connected clients.
15. Server sends disconnect packets for users who leave.
16. Server assigns each client a UUID; all clients know every other
client's UUID (used to reference them across position updates,
disconnect packets, etc).
17. Server notifies all clients (by UUID) when a user joins, leaves,
or is disconnected, so clients can spawn or remove the
corresponding `clientplayer` entity in the world.
## Infrastructure / debt backlog
Found during a full-codebase inventory pass (2026-07-30, see `STATUS.md`
for the full survey). These aren't new feature milestones so much as
loose ends worth closing, roughly in order of how cheap/safe they are to
fix:
1. Re-enable `test/item` (currently commented out in
`test/CMakeLists.txt`) -- confirm it still passes and turn it back on.
2. Restore `itemgive.c/h` in `src/duskrpg/item/CMakeLists.txt` -- the
textbox UI dependency it was waiting on (`ui/textbox/`) is already
back.
3. Decide the fate of the `vita` target: `scripts/build-vita.sh` and
`docker/vita/` reference `-DDUSK_TARGET_SYSTEM=vita`, but no
`cmake/targets/vita.cmake` exists, so the build is currently broken.
Either implement it or remove the dangling scripts/Dockerfile.
4. Add per-PR CI build coverage for at least one non-Linux target (PSP,
Knulli, GameCube, Wii currently only build on tag push, so
regressions there are invisible until a release).
5. Tackle milestone 4 above (poor UI rendering performance) with a
concrete lead: extend `uiconsole.c`'s cached-mesh pattern (rebuild
only on dirty) to the general widget framework
(`uiframe.c`/`uilabel.c`/buttons/menus), which currently rebuilds and
re-uploads geometry via `spriteBatchBuffer`/`meshFlush` every frame.
6. Revisit the GameCube/Wii networking static-IP workaround in
`networkdolphin.c` -- it's standing in for an unresolved suspected
memory-corruption bug in `if_config()`'s DHCP path.
7. Decide whether the PSP dialog-based network connect UI needs to come
back -- it was removed entirely (not fixed) when the original
dialog-tearing bug proved hard to resolve.
8. Backfill unit tests for the biggest untested surfaces: `ui/` (whole
widget framework), `save/`, `script/` (JerryScript bindings), `event/`.
## Principles
- Never trust the network implicitly. Neither side (server or client)
should assume the other's packets are well-formed or benign --
validate all incoming packet data defensively, since either side
may send garbage or malicious data. Use `errorret_t` /
`errorThrow()` for these runtime checks, not assert macros --
asserts are debug-only and won't guard release builds against
malformed or malicious packet data.
+102
View File
@@ -0,0 +1,102 @@
# Dusk Engine - Status Snapshot
This is a point-in-time inventory of the codebase's maturity, test coverage,
and known gaps. It is not auto-maintained -- re-survey periodically (or
whenever picking a new roadmap milestone) rather than trusting it blindly.
See `ROADMAP.md` for the ordered feature milestones this status feeds into,
and `CLAUDE.md` for coding conventions.
Last surveyed: 2026-07-30, at commit `e61914ba`.
## Core engine (`src/dusk/`)
| Subsystem | Maturity | Notes |
|------------|------------------------------------|-------|
| asset | Mature, fully wired | Model loading's "async" path is actually synchronous (`assetmodelloader.h`) -- only real stub found in core. |
| script | Mature for its current scope | Registered modules: `modulePlatform`, `moduleComponent`, `moduleEntity`, `moduleScene` only. No typed per-component JS wrappers (all components go through the generic `Component`). No unit tests. |
| entity | Mature | Engine-level prefab lists are empty sentinels; all real prefabs live in `duskrpg`. |
| scene | Mature | Same prefab-delegation pattern as entity. No JSON serialize/deserialize (removed by design). |
| save | Mature, but undocumented | Slot-based, yyjson + CRC32, platform stream hooks. Not covered in `CLAUDE.md`, no tests. |
| network | Connection-state layer only | HTTP client + connection state machine; no multiplayer/replication protocol (expected -- that's roadmap items 8-17). Not covered in `CLAUDE.md`, has HTTP tests only. |
| physics | Mature, recently churned | Recent revert/re-disable of "old ent code" suggests component wiring around physics isn't fully settled. Well tested. |
| animation | Early/mid-stage | Keyframes + easing only, no blend trees or state machines. Terse commit history ("ANIM") suggests still iterating. |
| display | Most mature/battle-tested | Backbone of the engine; dominated by platform optimization commits. |
| ui | Actively churning | Widget framework has had features added and ripped out repeatedly (story/battle UI added then removed). Rendering path is the likely root cause of roadmap item 4 (see below). No tests at all. |
| console | Small, finished for its scope | Already has the cached-mesh optimization pattern the rest of `ui/` lacks. |
| event | Clean, small, finished | Pub/sub, rebuilt to replace the old input system. |
| game | Intentionally header-only | Real implementation lives in `duskrpg/game/game.c`. |
### UI rendering performance (roadmap item 4)
Confirmed root-cause candidate: `src/dusk/ui/debug/uiconsole.c` caches a
persistent mesh and only rebuilds on dirty/scroll change. The rest of the
widget framework (`uiframe.c`, `uilabel.c`, buttons, menus, settings
screens) still goes through `spriteBatchBuffer`/`spriteBatchFlush` and
re-uploads vertex data via `meshFlush` every frame, with a full flush
forced on every shader/material change. This is almost certainly what
"tanks framerate" on PSP. Fix direction: extend the console's cached-mesh
pattern to the general widget path (rebuild only on dirty, not every
frame).
## Game layer (`src/duskrpg/`)
Actively maintained, not orphaned (despite an old "remove rpg" commit deep
in history) -- last touched the same day as this survey.
- **cutscene/** -- actively developed, matches `CLAUDE.md`'s documented
recipe exactly. 16 registered item types.
- **entity/, scene/** -- overworld player/camera/interactable components
and prefabs, active.
- **item/** -- `item.c`/`inventory.c`/`backpack.c` built via a working
`item.json` -> `itemdef.h` codegen pipeline. `itemgive.c/h` exist on
disk but are explicitly excluded from the CMake build pending textbox
UI restoration -- **that UI (`ui/textbox/`) is already restored**, so
this looks like an overdue follow-up, not a real blocker.
- **input/** -- headers only, no implementation. Contains the one
genuine TODO found in the whole `duskrpg` tree: `// TODO: Wiimote, USB
Keyboard, probably more.`
- **ui/** -- textbox restored and built; `uitestlabel.c/h` is an
intentional smoke-test scaffold, not dead code.
## Platform layers
| Platform | Status |
|--------------|--------|
| duskgl / dusksdl2 | Complete, shared by Linux/Knulli/PSP, no gaps found. |
| dusklinux | Complete, well-trodden. |
| duskpsp | Complete for current design. The historical dialog/tearing bug (see memory `project_psp_dialog_tearing` etc.) was **not fixed -- the dialog-based connect UI was removed entirely** (commit `d7982599`, "Simplified PSP network") in favor of a silent profile-based connect. Revisit if the dialog UX is still wanted. |
| duskdolphin (GameCube/Wii) | Functional, not a stub -- real GX-based display/mesh/shader/texture. Wii input uses only the GameCube `PAD_*` library; no WPAD/Wiimote support (`inputdolphin.h` has `#error "Wii not implemented"` gated behind macros that are never defined, so currently dormant, not a live build break). `networkdolphin.c` hardcodes a static IP as an explicit temporary workaround for a suspected DHCP-related memory-corruption bug in `if_config()` -- root cause still open. |
| vita | **Referenced by `scripts/build-vita.sh` and `docker/vita/` but no `cmake/targets/vita.cmake` exists** -- the build target is broken/unfinished at the CMake level. |
### CI coverage gap
`.github/workflows/test.yml` only builds+tests Linux, on PRs to `main`.
`build.yml` builds all other platforms (PSP, Knulli, GameCube, Wii +
ISO variants) but **only on tag push** (release time). Vita and Dolphin
aren't in CI at all. Net effect: regressions on 4+ platforms can land
silently until a release tag is cut.
## Test coverage gaps
Core `src/dusk/` subsystems with **zero** unit tests: `console`,
`engine`, `event`, `game`, `input`, `log`, `save`, `script` (+ all JS
module bindings), `system`, `ui` (entire widget framework).
`src/duskrpg/` has almost no test coverage: `test/item/test_inventory.c`
exists but **`add_subdirectory(item)` is commented out in
`test/CMakeLists.txt`**, so even that one test never runs. `cutscene`,
`entity`, `game`, `input`, `scene`, `ui` under `duskrpg` have no tests at
all.
No stale tests were found referencing deleted systems (old JSON
serialize/deserialize, old event/cutscene modules) -- the test suite is
internally consistent with current code, just incomplete in coverage.
## Build/tooling gaps worth knowing about
- `assetsraw/` -> `assets/` (chunk JSON -> `.dcf`) is a manual/editor-only
step (`tools.asset.chunk`), not part of the CMake build -- committed
`.dcf` files can silently drift from their raw source.
- Several Python tool packages exist but aren't wired into any build:
`tools/color/csv/`, `tools/asset/chunk_json/`, `tools/asset/dmf/`,
`tools/asset/tiles/`, `tools/input/csv/`. Some may be superseded by
`tools/color.py`/`tools/item.py`; worth a pass to confirm which are
live vs leftover.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-21
View File
@@ -1,21 +0,0 @@
// Copyright (c) 2026 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
const platformNames = {
[System.PLATFORM_LINUX]: 'Linux',
[System.PLATFORM_KNULLI]: 'Knulli',
[System.PLATFORM_PSP]: 'PSP',
[System.PLATFORM_GAMECUBE]: 'GameCube',
[System.PLATFORM_WII]: 'Wii',
};
Console.print('Platform: ' + (platformNames[System.platform] || 'Unknown'));
UIFullboxOver.setColor(Color.BLACK);
requireAsync('testscene.js').then(Scene.set).catch(err => {
Console.print('Error loading scene: ' + err);
Engine.exit();
});
+49 -43
View File
@@ -10,51 +10,57 @@ msgid "ui.title"
msgstr ""
"Welcome"
#: ui/user.c:22
msgid "ui.greeting"
msgstr "Hello, %s!"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.general"
msgstr "General"
#: ui/files.c:40
msgid "ui.file_status"
msgstr "%s has %d files."
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.input"
msgstr "Input"
#: ui/cart.c:55
msgid "cart.item_count"
msgid_plural "cart.item_count"
msgstr[0] "%d item"
msgstr[1] "%d items (dual)"
msgstr[2] "%d items (few)"
msgstr[3] "%d items (many)"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.display"
msgstr "Display"
#: ui/notifications.c:71
msgid ""
"ui.multiline_help"
msgstr ""
"Line one of the help text.\n"
"Line two continues here.\n"
"Line three ends here."
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.audio"
msgstr "Audio"
#: ui/errors.c:90
msgid ""
"error.upload_failed.long"
msgstr ""
"Upload failed for file \"%s\".\n"
"Please try again later or contact support."
msgid "ui.settings.input.deadzone"
msgstr "Deadzone"
#: ui/messages.c:110
msgid ""
"user.invite_status"
msgid_plural ""
"user.invite_status"
msgstr[0] ""
"%s invited %d user.\n"
"Please review the request."
msgstr[1] ""
"%s invited %d users (dual).\n"
"Please review the requests."
msgstr[2] ""
"%s invited %d users (few).\n"
"Please review the requests."
msgstr[3] ""
"%s invited %d users (many).\n"
"Please review the requests."
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
msgid "ui.settings.general.language"
msgstr "Language"
msgid "ui.settings.general.language_detail"
msgstr "Takes effect after restarting the application."
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.apply"
msgstr "Apply"
#: src/dusk/ui/frame/uiconfirm.c
msgid "ui.confirm.discard_changes"
msgstr "Discard unsaved changes?"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.characters"
msgstr "Characters"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.items"
msgstr "Items"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.settings"
msgstr "Settings"
msgid "item.potion.name"
msgstr "Potion"
msgid "item.potato.name"
msgstr "Potato"
msgid "item.apple.name"
msgstr "Apple"
+70
View File
@@ -0,0 +1,70 @@
msgid ""
msgstr ""
"Project-Id-Version: ExampleApp 1.0\n"
"Language: es\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n==1 ? 0 : 1);\n"
#: ui/menu.c:10
msgid "ui.title"
msgstr ""
"Bienvenido"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.general"
msgstr "General"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.input"
msgstr "Entrada"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.display"
msgstr "Pantalla"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.audio"
msgstr "Audio"
msgid "ui.settings.input.deadzone"
msgstr "Deadzone"
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
msgid "ui.settings.general.language"
msgstr "Idioma"
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
msgid "ui.settings.general.language_detail"
msgstr "Se aplica después de reiniciar la aplicación."
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.apply"
msgstr "Aplicar"
#: src/dusk/ui/frame/uiconfirm.c
msgid "ui.confirm.discard_changes"
msgstr "¿Descartar los cambios no guardados?"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.characters"
msgstr "Personajes"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.items"
msgstr "Objetos"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.settings"
msgstr "Configuración"
#: src/dusk/rpg/item/item.json
msgid "item.potion.name"
msgstr "Poción"
#: src/dusk/rpg/item/item.json
msgid "item.potato.name"
msgstr "Papa"
#: src/dusk/rpg/item/item.json
msgid "item.apple.name"
msgstr "Manzana"
+70
View File
@@ -0,0 +1,70 @@
msgid ""
msgstr ""
"Project-Id-Version: ExampleApp 1.0\n"
"Language: ja\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=1; plural=(0);\n"
#: ui/menu.c:10
msgid "ui.title"
msgstr ""
"歓迎"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.general"
msgstr "一般"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.input"
msgstr "入力"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.display"
msgstr "表示"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.tabs.audio"
msgstr "オーディオ"
msgid "ui.settings.input.deadzone"
msgstr "デッドゾーン"
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
msgid "ui.settings.general.language"
msgstr "言語"
#: src/dusk/ui/frame/settings/uisettingsgeneral.c
msgid "ui.settings.general.language_detail"
msgstr "アプリケーションを再起動すると適用されます。"
#: src/dusk/ui/frame/settings/uisettings.c
msgid "ui.settings.apply"
msgstr "適用"
#: src/dusk/ui/frame/uiconfirm.c
msgid "ui.confirm.discard_changes"
msgstr "未保存の変更を破棄しますか?"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.characters"
msgstr "キャラクター"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.items"
msgstr "アイテム"
#: src/dusk/ui/frame/game/uigamemenu.c
msgid "ui.game_menu.settings"
msgstr "設定"
#: src/dusk/rpg/item/item.json
msgid "item.potion.name"
msgstr "ポーション"
#: src/dusk/rpg/item/item.json
msgid "item.potato.name"
msgstr "ジャガイモ"
#: src/dusk/rpg/item/item.json
msgid "item.apple.name"
msgstr "リンゴ"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_1_1.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_1_2.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_1_3.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_1_4.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_1_5.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_1_6.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_1_7.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_1_8.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_2_1.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_2_2.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_2_3.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_2_4.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_2_5.dmf",
"color": [255, 0, 255, 255]
}
+4
View File
@@ -0,0 +1,4 @@
{
"mesh": "meshes/buildings/house_2_6.dmf",
"color": [255, 0, 255, 255]
}

Some files were not shown because too many files have changed in this diff Show More