From 2ee97ad4cedb5fc0190c002897a74171553b7c3f Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sun, 13 Sep 2026 15:18:57 -0500 Subject: [PATCH] Sunset the dedicated cutscene asset loader and the item pool Cutscenes now load through the generic ASSET_LOADER_TYPE_JSON loader and parse straight into fixed static buffers via new cutsceneParseDoc/ cutsceneParseItem/cutsceneCountItems helpers (cutscene.c), removing the bespoke ASSET_LOADER_TYPE_CUTSCENE pipeline entirely. Only one cutscene (plus one INSERT target) is ever resident, so each resolve locks, steals the parsed doc, unlocks, and force-reaps immediately - fixing a stale-cache-reuse bug where revisiting a cutscene name after a different one could return data from the shared buffer's previous occupant. ENTITY_WALK_TO and MAP_AREA_WAIT now store their waypoints/area ids in fixed-size arrays inline on their own item struct instead of a shared bump-allocated pool, so pool/poolOffset are gone from every item type's Load callback. cutscene_t.dataSize (and the CUTSCENE(...) macro's SIZE parameter) is removed along with it - it sized entries out of that same now-deleted pool and had no other reader. NPC #4's battletest cutscene and the main menu's cutscene now resolve their target by name on interact instead of eagerly at init, so a resolved-once pointer is never held past the point its backing buffer can be reused for something else. Co-Authored-By: Claude Sonnet 5 --- src/dusk/asset/loader/CMakeLists.txt | 1 - src/dusk/asset/loader/assetloader.c | 6 - src/dusk/asset/loader/assetloader.h | 5 - src/dusk/asset/loader/cutscene/CMakeLists.txt | 9 - .../loader/cutscene/assetcutsceneloader.c | 258 ------------------ .../loader/cutscene/assetcutsceneloader.h | 127 --------- src/dusk/audio/mixer/audiomixerchannel.h | 9 +- src/dusk/rpg/cutscene/CMakeLists.txt | 1 + src/dusk/rpg/cutscene/cutscene.c | 107 ++++++++ src/dusk/rpg/cutscene/cutscene.h | 61 ++++- src/dusk/rpg/cutscene/cutscenesystem.c | 49 ++-- src/dusk/rpg/cutscene/cutscenesystem.h | 85 +++--- .../cutscene/item/audio/cutsceneaudiofade.c | 4 +- .../cutscene/item/audio/cutsceneaudiofade.h | 6 +- .../item/audio/cutsceneaudiofadewait.c | 4 +- .../item/audio/cutsceneaudiofadewait.h | 6 +- .../cutscene/item/audio/cutsceneaudiopause.c | 4 +- .../cutscene/item/audio/cutsceneaudiopause.h | 6 +- .../cutscene/item/audio/cutsceneaudioplay.c | 4 +- .../cutscene/item/audio/cutsceneaudioplay.h | 6 +- .../cutscene/item/audio/cutsceneaudioresume.c | 4 +- .../cutscene/item/audio/cutsceneaudioresume.h | 6 +- .../cutscene/item/audio/cutsceneaudioset.c | 4 +- .../cutscene/item/audio/cutsceneaudioset.h | 6 +- .../item/audio/cutsceneaudiosetloop.c | 4 +- .../item/audio/cutsceneaudiosetloop.h | 6 +- .../cutscene/item/audio/cutsceneaudiosetpan.c | 4 +- .../cutscene/item/audio/cutsceneaudiosetpan.h | 6 +- .../cutscene/item/audio/cutsceneaudiostop.c | 4 +- .../cutscene/item/audio/cutsceneaudiostop.h | 6 +- .../item/battle/cutscenebattleforceaction.c | 4 +- .../item/battle/cutscenebattleforceaction.h | 6 +- .../item/battle/cutscenebattlewaitstate.c | 4 +- .../item/battle/cutscenebattlewaitstate.h | 6 +- .../item/battle/cutscenestartbattle.c | 4 +- .../item/battle/cutscenestartbattle.h | 6 +- .../cutscene/item/control/cutscenemarker.c | 4 +- .../cutscene/item/control/cutscenemarker.h | 6 +- .../rpg/cutscene/item/control/cutscenescene.c | 4 +- .../rpg/cutscene/item/control/cutscenescene.h | 6 +- .../cutscene/item/control/cutscenesetpause.c | 4 +- .../cutscene/item/control/cutscenesetpause.h | 6 +- .../rpg/cutscene/item/control/cutscenewait.c | 4 +- .../rpg/cutscene/item/control/cutscenewait.h | 6 +- src/dusk/rpg/cutscene/item/cutsceneitem.c | 84 ++++-- src/dusk/rpg/cutscene/item/cutsceneitem.h | 47 +--- src/dusk/rpg/cutscene/item/cutsceneitembase.c | 4 +- src/dusk/rpg/cutscene/item/cutsceneitembase.h | 6 +- src/dusk/rpg/cutscene/item/cutsceneprint.c | 4 +- src/dusk/rpg/cutscene/item/cutsceneprint.h | 6 +- .../cutscene/item/entity/cutsceneentityadd.c | 4 +- .../cutscene/item/entity/cutsceneentityadd.h | 6 +- .../item/entity/cutsceneentityremove.c | 4 +- .../item/entity/cutsceneentityremove.h | 6 +- .../item/entity/cutsceneentityteleport.c | 4 +- .../item/entity/cutsceneentityteleport.h | 6 +- .../cutscene/item/entity/cutsceneentityturn.c | 4 +- .../cutscene/item/entity/cutsceneentityturn.h | 6 +- .../item/entity/cutsceneentitywalkto.c | 32 +-- .../item/entity/cutsceneentitywalkto.h | 41 ++- .../item/entity/cutsceneentitywalktoentity.c | 4 +- .../item/entity/cutsceneentitywalktoentity.h | 6 +- .../rpg/cutscene/item/item/cutsceneitemgive.c | 4 +- .../rpg/cutscene/item/item/cutsceneitemgive.h | 6 +- .../rpg/cutscene/item/json/CMakeLists.txt | 1 - .../item/json/cutscenejsonpauseflags.h | 2 +- .../rpg/cutscene/item/json/cutscenejsonpool.c | 12 - .../rpg/cutscene/item/json/cutscenejsonpool.h | 19 -- .../item/maparea/cutscenemaparearemove.c | 4 +- .../item/maparea/cutscenemaparearemove.h | 6 +- .../item/maparea/cutscenemapareawait.c | 17 +- .../item/maparea/cutscenemapareawait.h | 21 +- .../item/save/cutscenesavedevicecheck.c | 4 +- .../item/save/cutscenesavedevicecheck.h | 6 +- .../item/save/cutscenesaveloadallslots.c | 4 +- .../item/save/cutscenesaveloadallslots.h | 6 +- src/dusk/rpg/cutscene/item/ui/cutsceneemoji.c | 4 +- src/dusk/rpg/cutscene/item/ui/cutsceneemoji.h | 6 +- src/dusk/rpg/cutscene/item/ui/cutscenefade.c | 4 +- src/dusk/rpg/cutscene/item/ui/cutscenefade.h | 6 +- src/dusk/rpg/cutscene/item/ui/cutscenemodal.c | 4 +- src/dusk/rpg/cutscene/item/ui/cutscenemodal.h | 6 +- .../item/ui/cutscenemodaloptionsmarkers.c | 4 +- .../item/ui/cutscenemodaloptionsmarkers.h | 6 +- src/dusk/rpg/cutscene/item/ui/cutsceneshake.c | 4 +- src/dusk/rpg/cutscene/item/ui/cutsceneshake.h | 6 +- src/dusk/rpg/cutscene/item/ui/cutscenetext.c | 4 +- src/dusk/rpg/cutscene/item/ui/cutscenetext.h | 6 +- .../rpg/cutscene/item/ui/cutscenetextmini.c | 4 +- .../rpg/cutscene/item/ui/cutscenetextmini.h | 6 +- .../cutscene/item/ui/cutscenetextminihide.c | 4 +- .../cutscene/item/ui/cutscenetextminihide.h | 6 +- .../rpg/cutscene/item/ui/cutsceneuishow.c | 4 +- .../rpg/cutscene/item/ui/cutsceneuishow.h | 6 +- src/dusk/rpg/cutscene/scene/testcutscene.h | 4 +- test/rpg/battle/test_battle.c | 3 +- test/rpg/cutscene/test_cutscenesystem.c | 36 +-- test/rpg/entity/test_entityinteract.c | 3 +- 98 files changed, 443 insertions(+), 957 deletions(-) delete mode 100644 src/dusk/asset/loader/cutscene/CMakeLists.txt delete mode 100644 src/dusk/asset/loader/cutscene/assetcutsceneloader.c delete mode 100644 src/dusk/asset/loader/cutscene/assetcutsceneloader.h create mode 100644 src/dusk/rpg/cutscene/cutscene.c delete mode 100644 src/dusk/rpg/cutscene/item/json/cutscenejsonpool.c delete mode 100644 src/dusk/rpg/cutscene/item/json/cutscenejsonpool.h diff --git a/src/dusk/asset/loader/CMakeLists.txt b/src/dusk/asset/loader/CMakeLists.txt index f59ac170..21932838 100644 --- a/src/dusk/asset/loader/CMakeLists.txt +++ b/src/dusk/asset/loader/CMakeLists.txt @@ -17,6 +17,5 @@ add_subdirectory(locale) add_subdirectory(json) add_subdirectory(chunk) add_subdirectory(dmf) -add_subdirectory(cutscene) add_subdirectory(wav) add_subdirectory(mp3) \ No newline at end of file diff --git a/src/dusk/asset/loader/assetloader.c b/src/dusk/asset/loader/assetloader.c index 87ce42c9..ad808032 100644 --- a/src/dusk/asset/loader/assetloader.c +++ b/src/dusk/asset/loader/assetloader.c @@ -52,12 +52,6 @@ assetloadercallbacks_t ASSET_LOADER_CALLBACKS[ASSET_LOADER_TYPE_COUNT] = { .dispose = assetChunkDispose }, - [ASSET_LOADER_TYPE_CUTSCENE] = { - .loadSync = assetCutsceneLoaderSync, - .loadAsync = assetCutsceneLoaderAsync, - .dispose = assetCutsceneDispose - }, - [ASSET_LOADER_TYPE_WAV] = { .loadSync = assetWavLoaderSync, .loadAsync = assetWavLoaderAsync, diff --git a/src/dusk/asset/loader/assetloader.h b/src/dusk/asset/loader/assetloader.h index 317a6519..c18c108f 100644 --- a/src/dusk/asset/loader/assetloader.h +++ b/src/dusk/asset/loader/assetloader.h @@ -13,7 +13,6 @@ #include "asset/loader/locale/assetlocaleloader.h" #include "asset/loader/json/assetjsonloader.h" #include "asset/loader/chunk/assetchunkloader.h" -#include "asset/loader/cutscene/assetcutsceneloader.h" #include "asset/loader/wav/assetwavloader.h" #include "asset/loader/mp3/assetmp3loader.h" @@ -27,7 +26,6 @@ typedef enum { ASSET_LOADER_TYPE_LOCALE, ASSET_LOADER_TYPE_JSON, ASSET_LOADER_TYPE_CHUNK, - ASSET_LOADER_TYPE_CUTSCENE, ASSET_LOADER_TYPE_WAV, ASSET_LOADER_TYPE_MP3, @@ -42,7 +40,6 @@ typedef union { assetlocaleloaderloading_t locale; assetjsonloaderloading_t json; assetchunkloaderloading_t chunk; - assetcutsceneloaderloading_t cutscene; assetwavloaderloading_t wav; assetmp3loaderloading_t mp3; } assetloaderloading_t; @@ -55,7 +52,6 @@ typedef union { assetlocaleoutput_t locale; assetjsonoutput_t json; assetchunkoutput_t chunk; - assetcutsceneoutput_t cutscene; assetwavoutput_t wav; assetmp3output_t mp3; } assetloaderoutput_t; @@ -66,7 +62,6 @@ typedef union { assetlocaleloaderinput_t locale; assetjsonloaderinput_t json; assetchunkloaderinput_t chunk; - assetcutsceneloaderinput_t cutscene; assetwavloaderinput_t wav; assetmp3loaderinput_t mp3; } assetloaderinput_t; diff --git a/src/dusk/asset/loader/cutscene/CMakeLists.txt b/src/dusk/asset/loader/cutscene/CMakeLists.txt deleted file mode 100644 index 04279174..00000000 --- a/src/dusk/asset/loader/cutscene/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - assetcutsceneloader.c -) diff --git a/src/dusk/asset/loader/cutscene/assetcutsceneloader.c b/src/dusk/asset/loader/cutscene/assetcutsceneloader.c deleted file mode 100644 index d86fe9f8..00000000 --- a/src/dusk/asset/loader/cutscene/assetcutsceneloader.c +++ /dev/null @@ -1,258 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "assetcutsceneloader.h" -#include "assert/assert.h" -#include "util/memory.h" -#include "util/string.h" -#include "asset/loader/assetloading.h" -#include "asset/loader/assetentry.h" -#include "asset/loader/assetloader.h" -#include "asset/asset.h" -#include "rpg/cutscene/item/json/cutscenejsonpauseflags.h" - -errorret_t assetCutsceneParseItem( - assetloading_t *loading, - yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset, - const uint8_t index -) { - if(!yyjson_is_obj(itemObj)) { - assetLoaderErrorThrow( - loading, - "Cutscene item %u is not an object", - (uint32_t)index - ); - } - - const char_t *typeName = yyjson_get_str(yyjson_obj_get(itemObj, "type")); - if(!cutsceneItemLookupType(typeName, &item->type)) { - assetLoaderErrorThrow( - loading, - "Cutscene item %u: missing/unsupported item type %s", - (uint32_t)index, - typeName - ); - } - - cutsceneitemloadcallback_t *load = CUTSCENE_ITEM_CALLBACKS[item->type].load; - if(load == NULL) { - assetLoaderErrorThrow( - loading, "Cutscene item %u: unhandled item type %u", (uint32_t)index, - (uint32_t)item->type - ); - } - - errorret_t result = load(itemObj, item, pool, poolOffset); - if(errorIsNotOk(result)) { - loading->entry->state = ASSET_ENTRY_STATE_ERROR; - errorChain(result); - } - - errorOk(); -} - -size_t assetCutsceneComputePoolSize(yyjson_val *itemsArr) { - size_t size = 0; - yyjson_arr_iter iter = yyjson_arr_iter_with(itemsArr); - yyjson_val *itemVal; - while((itemVal = yyjson_arr_iter_next(&iter)) != NULL) { - const char_t *typeName = yyjson_get_str(yyjson_obj_get(itemVal, "type")); - cutsceneitemtype_t type; - if(!cutsceneItemLookupType(typeName, &type)) continue; - - cutsceneitempoolsizecallback_t *poolSize = - CUTSCENE_ITEM_CALLBACKS[type].poolSize; - if(poolSize == NULL) continue; - - size = cutsceneJsonPoolAlign(size) + poolSize(itemVal); - } - return size; -} - -// Raw file-read scratch space - fixed-size (ASSET_CUTSCENE_FILE_SIZE_MAX is -// already a hard cap below) rather than malloc'd per load. Safe to share: -// ASSET only ever runs one async load at a time on its single load thread -// (see assetUpdateAsync), and yyjson_read copies everything it needs out -// of this buffer into the doc before this function returns, so it's free -// to be overwritten by the next load. -static uint8_t CUTSCENE_FILE_BUFFER[ASSET_CUTSCENE_FILE_SIZE_MAX]; - -errorret_t assetCutsceneLoaderAsync(assetloading_t *loading) { - assertNotNull(loading, "Loading cannot be NULL"); - assertNotMainThread("Should be called from an async thread."); - - if( - loading->loading.cutscene.state != ASSET_CUTSCENE_LOADING_STATE_READ_FILE - ) { - errorOk(); - } - - const assetcutsceneloaderinput_t *input = loading->entry->input != NULL - ? &loading->entry->input->cutscene - : NULL; - const bool_t toInsert = - input != NULL && input->dest == ASSET_CUTSCENE_LOAD_DEST_INSERT; - const char_t *filePath = (input != NULL && input->path[0] != '\0') - ? input->path - : loading->entry->name; - - cutsceneitem_t *targetItems = - toInsert ? CUTSCENE_INSERT_ITEMS : CUTSCENE_LOADED_ITEMS; - const size_t targetItemsMax = - toInsert ? CUTSCENE_INSERT_ITEMS_MAX : CUTSCENE_LOADED_ITEMS_MAX; - uint8_t *targetPool = toInsert ? CUTSCENE_INSERT_POOL : CUTSCENE_LOADED_POOL; - const size_t targetPoolMax = - toInsert ? CUTSCENE_INSERT_POOL_SIZE_MAX : CUTSCENE_LOADED_POOL_SIZE_MAX; - cutscene_t *targetScene = toInsert ? &CUTSCENE_INSERT_SCENE : &CUTSCENE_LOADED_SCENE; - - assetfile_t *file = &loading->loading.cutscene.file; - assetLoaderErrorChain(loading, - assetFileInit(file, filePath, NULL, NULL) - ); - - if(file->size > ASSET_CUTSCENE_FILE_SIZE_MAX) { - assetLoaderErrorThrow( - loading, "Cutscene JSON exceeds maximum allowed size" - ); - } - - size_t fileSize = (size_t)file->size; - assetLoaderErrorChain(loading, assetFileOpen(file)); - assetLoaderErrorChain( - loading, assetFileRead(file, CUTSCENE_FILE_BUFFER, fileSize) - ); - assertTrue( - file->lastRead == file->size, - "Failed to read entire cutscene file." - ); - assetLoaderErrorChain(loading, assetFileClose(file)); - assetLoaderErrorChain(loading, assetFileDispose(file)); - - // Parsing is pure CPU work with no main-thread dependency (every item - // type's load callback just parses fields - see cutsceneCutsceneLoad's - // doc comment for how CUTSCENE items avoid needing one), so it happens - // right here instead of bouncing to the sync phase. - yyjson_doc *doc = yyjson_read( - (char *)CUTSCENE_FILE_BUFFER, fileSize, - YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS - ); - if(doc == NULL) { - assetLoaderErrorThrow(loading, "Failed to parse cutscene JSON"); - } - - yyjson_val *root = yyjson_doc_get_root(doc); - yyjson_val *itemsArr = yyjson_obj_get(root, "items"); - if(!yyjson_is_arr(itemsArr)) { - yyjson_doc_free(doc); - assetLoaderErrorThrow(loading, "Cutscene JSON is missing an 'items' array"); - } - - size_t itemCount = yyjson_arr_size(itemsArr); - if(itemCount > targetItemsMax) { - yyjson_doc_free(doc); - assetLoaderErrorThrow( - loading, "Cutscene has more items than its target buffer allows" - ); - } - - cutscenepause_t pause = CUTSCENE_PAUSE_DEFAULT; - yyjson_val *pauseArr = yyjson_obj_get(root, "pause"); - if(yyjson_is_arr(pauseArr)) { - if(!cutsceneJsonParsePauseFlags(pauseArr, &pause)) { - yyjson_doc_free(doc); - assetLoaderErrorThrow( - loading, "Cutscene JSON has an invalid 'pause' flag" - ); - } - } - - size_t poolSize = assetCutsceneComputePoolSize(itemsArr); - if(poolSize > targetPoolMax) { - yyjson_doc_free(doc); - assetLoaderErrorThrow( - loading, "Cutscene needs more pool space than its target buffer allows" - ); - } - - // Everything structural has validated by this point, so it's safe to - // start overwriting the target's shared items/pool buffers - a per-item - // parse failure past this point still leaves them partially overwritten, - // but that's fine: any load failure here already sends the game into the - // fatal-error overlay (see cutsceneSystemLoad/cutsceneCutsceneResolve/ - // cutsceneInsertResolve), so nothing keeps running against stale data. - memoryZero(targetItems, itemCount * sizeof(cutsceneitem_t)); - - size_t poolOffset = 0; - yyjson_arr_iter itemIter = yyjson_arr_iter_with(itemsArr); - yyjson_val *itemVal; - uint8_t index = 0; - while((itemVal = yyjson_arr_iter_next(&itemIter)) != NULL) { - errorret_t itemResult = assetCutsceneParseItem( - loading, itemVal, &targetItems[index], - targetPool, &poolOffset, index - ); - if(errorIsNotOk(itemResult)) { - yyjson_doc_free(doc); - errorChain(itemResult); - } - index++; - } - - // Takes ownership of doc - marker/cutscene-reference name fields point - // directly into it (see cutsceneCutsceneRefLoad/cutsceneMarkerLoad), so - // it must outlive this load, replacing whatever the previously loaded - // cutscene left behind for this same destination. - if(toInsert) cutsceneInsertSetDoc(doc); - else cutsceneLoadedSetDoc(doc); - targetScene->itemCount = (uint8_t)itemCount; - targetScene->pause = pause; - targetScene->dataSize = 0; - - loading->loading.cutscene.state = ASSET_CUTSCENE_LOADING_STATE_PARSE; - loading->entry->state = ASSET_ENTRY_STATE_PENDING_SYNC; - errorOk(); -} - -errorret_t assetCutsceneLoaderSync(assetloading_t *loading) { - assertNotNull(loading, "Loading cannot be NULL"); - assertTrue(loading->type == ASSET_LOADER_TYPE_CUTSCENE, "Invalid type."); - assertIsMainThread("Must be called from the main thread."); - - if(loading->loading.cutscene.state == ASSET_CUTSCENE_LOADING_STATE_INITIAL) { - loading->loading.cutscene.state = ASSET_CUTSCENE_LOADING_STATE_READ_FILE; - loading->entry->state = ASSET_ENTRY_STATE_PENDING_ASYNC; - errorOk(); - } - - // Everything else already happened in the async phase - see - // assetCutsceneLoaderAsync. This flip still has to happen from here - // rather than the async phase setting LOADED directly, since - // assetUpdate() only fires an entry's onLoaded callback for entries - // that finish via this sync path. - assertTrue( - loading->loading.cutscene.state == ASSET_CUTSCENE_LOADING_STATE_PARSE, - "Unexpected cutscene loading state." - ); - loading->entry->state = ASSET_ENTRY_STATE_LOADED; - errorOk(); -} - -errorret_t assetCutsceneDispose(assetentry_t *entry) { - assertNotNull(entry, "Entry cannot be NULL"); - assertTrue(entry->type == ASSET_LOADER_TYPE_CUTSCENE, "Invalid type."); - assertIsMainThread("Must be called from the main thread."); - - // Nothing to free here - a loaded cutscene's data lives in the fixed, - // shared CUTSCENE_LOADED_SCENE/ITEMS/POOL globals (see cutscenesystem.h), - // not per-entry storage; this entry only ever drove the read+parse - // pipeline into them. - - errorOk(); -} diff --git a/src/dusk/asset/loader/cutscene/assetcutsceneloader.h b/src/dusk/asset/loader/cutscene/assetcutsceneloader.h deleted file mode 100644 index 7cb8e571..00000000 --- a/src/dusk/asset/loader/cutscene/assetcutsceneloader.h +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "asset/assetfile.h" -#include "rpg/cutscene/cutscene.h" -#include "rpg/cutscene/cutscenesystem.h" -#include "rpg/cutscene/item/cutsceneitem.h" -#include "rpg/cutscene/item/json/cutscenejsonpool.h" -#include "yyjson.h" - -#define ASSET_CUTSCENE_FILE_SIZE_MAX (1024 * 64) - -typedef struct assetloading_s assetloading_t; -typedef struct assetentry_s assetentry_t; - -// Which fixed, shared buffer set (see cutscenesystem.h) a load should -// parse into - MAIN for the one JSON-authored cutscene resident via -// cutsceneSystemLoad/cutsceneCutsceneResolve, INSERT for the one resident -// via cutsceneInsertResolve (see CUTSCENE_ITEM_TYPE_INSERT). -typedef enum { - ASSET_CUTSCENE_LOAD_DEST_MAIN, - ASSET_CUTSCENE_LOAD_DEST_INSERT -} assetcutsceneloaddest_t; - -typedef struct { - assetcutsceneloaddest_t dest; - - // Optional file path override, same trick as assetjsonloaderinput_t - - // when path[0] is non-zero this is read instead of loading->entry->name, - // so a synthetic cache key (e.g. "insert:cutscenes/foo.jsonc", used to - // avoid a single entry being shared - and its dest silently ignored - - // between two different logical loads of the same file, see - // asset.c/assetGetEntry's name-only dedup) can still point at the real - // file. - char_t path[ASSET_FILE_NAME_MAX]; -} assetcutsceneloaderinput_t; - -typedef enum { - ASSET_CUTSCENE_LOADING_STATE_INITIAL, - ASSET_CUTSCENE_LOADING_STATE_READ_FILE, - ASSET_CUTSCENE_LOADING_STATE_PARSE -} assetcutsceneloadingstate_t; - -typedef struct { - assetfile_t file; - assetcutsceneloadingstate_t state; -} assetcutsceneloaderloading_t; - -typedef struct { - // Nothing - a loaded cutscene's data lives entirely in the fixed, - // shared CUTSCENE_LOADED_SCENE/ITEMS/POOL globals (see cutscenesystem.h) - // that assetCutsceneLoaderAsync parses directly into, not per-entry - // storage. This entry only ever exists to drive the read+parse - // pipeline, and is unlocked (see cutsceneSystemLoad/ - // cutsceneCutsceneResolve) the instant that finishes. - uint8_t unused; -} assetcutsceneoutput_t; - -/** - * Parses one cutscene item object into item, writing any pool-backed - * array data (entityWalkTo positions, mapAreaWait areaIds) into pool at - * *poolOffset and advancing it. Every field/enum name is validated as - * real (untrusted, authored) file content - failures are real errors, not - * asserts. Dispatches to the matching type's Load callback (see - * CUTSCENE_ITEM_CALLBACKS in rpg/cutscene/item/cutsceneitem.h) - the - * per-type parsing logic itself lives there now, colocated with that - * type's runtime behavior. - * - * @param loading Loading information for the asset being loaded. - * @param itemObj The item's JSON object. - * @param item Destination item, already zeroed by the caller. - * @param pool Base pointer of the entry's pool allocation (may be NULL if - * assetCutsceneComputePoolSize returned 0). - * @param poolOffset In/out cursor into pool. - * @param index Index of this item within the cutscene, for error messages. - * @return Error code indicating success or failure of the parse. - */ -errorret_t assetCutsceneParseItem( - assetloading_t *loading, - yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset, - const uint8_t index -); - -/** - * Asynchronous loader for cutscene assets. Reads the raw JSONC file bytes - * and, in the same call, parses them directly into one of the fixed, - * shared buffer sets in cutscenesystem.h - CUTSCENE_LOADED_ITEMS/POOL by - * default, or CUTSCENE_INSERT_ITEMS/POOL when - * loading->entry->input->cutscene.dest is ASSET_CUTSCENE_LOAD_DEST_INSERT - - * no heap allocation at all, since only one cutscene is ever resident per - * destination. None of that work touches the main thread (every item - * type's load callback is pure parsing now; CUTSCENE items defer their - * nested asset resolution to cutsceneCutsceneStart), so doing it all here - * keeps a large cutscene from ever blocking a frame. - * - * @param loading Loading information for the asset being loaded. - * @return Error code indicating success or failure of the load operation. - */ -errorret_t assetCutsceneLoaderAsync(assetloading_t *loading); - -/** - * Synchronous loader for cutscene assets. All actual work already - * happened in the async phase - this only flips the entry to LOADED, - * which must happen through this sync callback (rather than the async - * phase setting it directly) so assetUpdate()'s onLoaded dispatch, which - * only fires for entries finishing via the sync path, still runs. - * - * @param loading Loading information for the asset being loaded. - * @return Error code indicating success or failure of the load operation. - */ -errorret_t assetCutsceneLoaderSync(assetloading_t *loading); - -/** - * Disposer for cutscene assets. - * - * @param entry Asset entry containing the cutscene data to dispose. - * @return Error code indicating success or failure of the dispose operation. - */ -errorret_t assetCutsceneDispose(assetentry_t *entry); diff --git a/src/dusk/audio/mixer/audiomixerchannel.h b/src/dusk/audio/mixer/audiomixerchannel.h index 5886ab02..dae2a35c 100644 --- a/src/dusk/audio/mixer/audiomixerchannel.h +++ b/src/dusk/audio/mixer/audiomixerchannel.h @@ -12,11 +12,10 @@ // Forward-declared rather than including asset/asset.h - this header only // ever needs a pointer to it, and pulling in the full asset module here -// creates a real include cycle for anything that reaches this header via -// asset/loader/cutscene/assetcutsceneloader.h (asset.h -> ... -> -// assetloader.h -> assetcutsceneloader.h -> cutscene.h -> cutsceneitem.h -// -> the audio cutscene items -> this header -> asset/asset.h again, -// mid-parse). audiomixerchannel.c itself still includes the full header. +// risks an include cycle for anything that reaches this header via a +// cutscene item (cutscene.h -> cutsceneitem.h -> the audio cutscene items +// -> this header -> asset/asset.h, mid-parse). audiomixerchannel.c itself +// still includes the full header. typedef struct assetentry_s assetentry_t; typedef struct audiostream_s audiostream_t; diff --git a/src/dusk/rpg/cutscene/CMakeLists.txt b/src/dusk/rpg/cutscene/CMakeLists.txt index ccecedc5..a7ced42c 100644 --- a/src/dusk/rpg/cutscene/CMakeLists.txt +++ b/src/dusk/rpg/cutscene/CMakeLists.txt @@ -6,6 +6,7 @@ # Sources target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC + cutscene.c cutscenesystem.c ) diff --git a/src/dusk/rpg/cutscene/cutscene.c b/src/dusk/rpg/cutscene/cutscene.c new file mode 100644 index 00000000..9827a379 --- /dev/null +++ b/src/dusk/rpg/cutscene/cutscene.c @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "cutscene.h" +#include "item/json/cutscenejsonpauseflags.h" +#include "util/memory.h" +#include "assert/assert.h" + +errorret_t cutsceneParseItem( + yyjson_val *itemObj, + cutsceneitem_t *item, + const uint8_t index +) { + assertNotNull(itemObj, "Item object cannot be NULL"); + assertNotNull(item, "Item cannot be NULL"); + + if(!yyjson_is_obj(itemObj)) { + errorThrow("Cutscene item %u is not an object", (uint32_t)index); + } + + const char_t *typeName = yyjson_get_str(yyjson_obj_get(itemObj, "type")); + if(!cutsceneItemLookupType(typeName, &item->type)) { + errorThrow( + "Cutscene item %u: missing/unsupported item type %s", + (uint32_t)index, typeName + ); + } + + cutsceneitemloadcallback_t *load = CUTSCENE_ITEM_CALLBACKS[item->type].load; + if(load == NULL) { + errorThrow( + "Cutscene item %u: unhandled item type %u", + (uint32_t)index, (uint32_t)item->type + ); + } + + errorret_t result = load(itemObj, item); + if(errorIsNotOk(result)) errorChain(result); + + errorOk(); +} + +size_t cutsceneCountItems(yyjson_doc *doc) { + assertNotNull(doc, "Doc cannot be NULL"); + + yyjson_val *root = yyjson_doc_get_root(doc); + yyjson_val *itemsArr = yyjson_obj_get(root, "items"); + if(!yyjson_is_arr(itemsArr)) return 0; + return yyjson_arr_size(itemsArr); +} + +errorret_t cutsceneParseDoc( + yyjson_doc *doc, + cutscene_t *scene, + cutsceneitem_t *items, + size_t itemsMax +) { + assertNotNull(doc, "Doc cannot be NULL"); + assertNotNull(scene, "Scene cannot be NULL"); + assertNotNull(items, "Items cannot be NULL"); + assertTrue(itemsMax > 0, "Items max cannot be 0"); + + yyjson_val *root = yyjson_doc_get_root(doc); + yyjson_val *itemsArr = yyjson_obj_get(root, "items"); + if(!yyjson_is_arr(itemsArr)) { + errorThrow("Cutscene JSON is missing an 'items' array"); + } + + size_t itemCount = yyjson_arr_size(itemsArr); + if(itemCount > itemsMax) { + errorThrow("Cutscene has more items than its target buffer allows"); + } + + cutscenepause_t pause = CUTSCENE_PAUSE_DEFAULT; + yyjson_val *pauseArr = yyjson_obj_get(root, "pause"); + if(yyjson_is_arr(pauseArr)) { + if(!cutsceneJsonParsePauseFlags(pauseArr, &pause)) { + errorThrow("Cutscene JSON has an invalid 'pause' flag"); + } + } + + // Everything structural has validated by this point, so it's safe to + // start overwriting items - a per-item parse failure past this point + // still leaves it partially overwritten, but that's fine: any load + // failure here already sends the game into the fatal-error overlay + // (see cutsceneSystemLoad/cutsceneCutsceneResolve/cutsceneInsertResolve), + // so nothing keeps running against stale data. + memoryZero(items, itemCount * sizeof(cutsceneitem_t)); + + yyjson_arr_iter itemIter = yyjson_arr_iter_with(itemsArr); + yyjson_val *itemVal; + uint8_t index = 0; + while((itemVal = yyjson_arr_iter_next(&itemIter)) != NULL) { + errorret_t itemResult = cutsceneParseItem(itemVal, &items[index], index); + if(errorIsNotOk(itemResult)) errorChain(itemResult); + index++; + } + + scene->itemCount = (uint8_t)itemCount; + scene->pause = pause; + + errorOk(); +} diff --git a/src/dusk/rpg/cutscene/cutscene.h b/src/dusk/rpg/cutscene/cutscene.h index 402b4c7f..07149fc7 100644 --- a/src/dusk/rpg/cutscene/cutscene.h +++ b/src/dusk/rpg/cutscene/cutscene.h @@ -13,10 +13,6 @@ typedef struct cutscene_s { const cutsceneitem_t *items; uint8_t itemCount; cutscenepause_t pause; - - // Size in bytes of this cutscene's custom user data, carved out of - // CUTSCENE_SYSTEM.data while the cutscene is running. - size_t dataSize; } cutscene_t; /** @@ -25,19 +21,16 @@ typedef struct cutscene_s { * * @param NAME Suffix for the generated CUTSCENE_##NAME cutscene/items * statics. - * @param SIZE Bytes of custom user data this cutscene needs, carved out - * of CUTSCENE_SYSTEM.data while it runs. * @param PAUSE_TYPE Suffix of the CUTSCENE_PAUSE_* flag(s) to apply * while this cutscene runs (e.g. NONE, ALL). * @param ... The cutscene's cutsceneitem_t entries, in order. */ -#define CUTSCENE(NAME, SIZE, PAUSE_TYPE, ...) \ +#define CUTSCENE(NAME, PAUSE_TYPE, ...) \ static const cutsceneitem_t CUTSCENE_##NAME##_ITEMS[] = { __VA_ARGS__ }; \ static const cutscene_t CUTSCENE_##NAME = { \ .items = CUTSCENE_##NAME##_ITEMS, \ .itemCount = sizeof(CUTSCENE_##NAME##_ITEMS) / sizeof(cutsceneitem_t), \ .pause = CUTSCENE_PAUSE_##PAUSE_TYPE, \ - .dataSize = SIZE \ }; /** @@ -79,3 +72,55 @@ typedef struct cutscene_s { .type = CUTSCENE_ITEM_TYPE_INSERT, \ .insert = { .cutscene = CUTSCENE_REFERENCE(CUTSCENE), .name = NULL } \ } + +/** + * Parses one cutscene item object into item. Every field/enum name is + * validated as real (untrusted, authored) file content - failures are + * real errors, not asserts. Dispatches to the matching type's Load + * callback (see CUTSCENE_ITEM_CALLBACKS in item/cutsceneitem.h) - the + * per-type parsing logic itself lives there, colocated with that type's + * runtime behavior. + * + * @param itemObj The item's JSON object. + * @param item Destination item, already zeroed by the caller. + * @param index Index of this item within the cutscene, for error messages. + * @return Error code indicating success or failure of the parse. + */ +errorret_t cutsceneParseItem( + yyjson_val *itemObj, + cutsceneitem_t *item, + const uint8_t index +); + +/** + * Counts how many entries are in doc's top-level "items" array, without + * parsing any of them - e.g. so a caller that wants to malloc its own + * items array instead of using a fixed one could size it first (we don't + * do that ourselves, but the option stays open). + * + * @param doc Already-parsed JSON document. + * @return Number of entries in "items", or 0 if it's missing/not an array. + */ +size_t cutsceneCountItems(yyjson_doc *doc); + +/** + * Parses doc's "items" (and optional "pause") into items, and updates + * scene's itemCount/pause - scene->items is left untouched, since the + * caller already points it at items. Purely a parser: doesn't touch the + * asset system, doesn't lock/load anything, and doesn't take ownership of + * doc - the caller is responsible for both loading doc beforehand and for + * its lifetime afterward (name/string fields written into items point + * directly into it, so it must outlive items' use). + * + * @param doc Already-parsed JSON document to read from. + * @param scene Destination scene - itemCount/pause are overwritten. + * @param items Destination item array, capacity itemsMax. + * @param itemsMax Capacity of items. + * @return Error code indicating success or failure of the parse. + */ +errorret_t cutsceneParseDoc( + yyjson_doc *doc, + cutscene_t *scene, + cutsceneitem_t *items, + size_t itemsMax +); diff --git a/src/dusk/rpg/cutscene/cutscenesystem.c b/src/dusk/rpg/cutscene/cutscenesystem.c index 6813ea9f..928046ec 100644 --- a/src/dusk/rpg/cutscene/cutscenesystem.c +++ b/src/dusk/rpg/cutscene/cutscenesystem.c @@ -11,17 +11,16 @@ #include "util/string.h" #include "assert/assert.h" #include "asset/asset.h" +#include "asset/loader/assetloader.h" #include "ui/overlay/uifatalerror.h" cutscenesystem_t CUTSCENE_SYSTEM; cutsceneitem_t CUTSCENE_LOADED_ITEMS[CUTSCENE_LOADED_ITEMS_MAX]; -uint8_t CUTSCENE_LOADED_POOL[CUTSCENE_LOADED_POOL_SIZE_MAX]; cutscene_t CUTSCENE_LOADED_SCENE = { .items = CUTSCENE_LOADED_ITEMS, .itemCount = 0, - .pause = CUTSCENE_PAUSE_NONE, - .dataSize = 0 + .pause = CUTSCENE_PAUSE_NONE }; static yyjson_doc *CUTSCENE_LOADED_DOC = NULL; @@ -31,12 +30,10 @@ void cutsceneLoadedSetDoc(yyjson_doc *doc) { } cutsceneitem_t CUTSCENE_INSERT_ITEMS[CUTSCENE_INSERT_ITEMS_MAX]; -uint8_t CUTSCENE_INSERT_POOL[CUTSCENE_INSERT_POOL_SIZE_MAX]; cutscene_t CUTSCENE_INSERT_SCENE = { .items = CUTSCENE_INSERT_ITEMS, .itemCount = 0, - .pause = CUTSCENE_PAUSE_NONE, - .dataSize = 0 + .pause = CUTSCENE_PAUSE_NONE }; static yyjson_doc *CUTSCENE_INSERT_DOC = NULL; @@ -54,11 +51,6 @@ void cutsceneSystemPrepare( entity_t *interact, entity_t *interacted ) { - assertTrue( - cutscene->dataSize < CUTSCENE_SYSTEM_SIZE_MAX, - "Cutscene data size exceeds CUTSCENE_SYSTEM_SIZE_MAX" - ); - CUTSCENE_SYSTEM.scene = cutscene; CUTSCENE_SYSTEM.pause = cutscene->pause; CUTSCENE_SYSTEM.entityInteract = interact; @@ -98,19 +90,42 @@ void cutsceneSystemLoad(const char_t *file) { char_t path[ASSET_FILE_NAME_MAX]; stringFormat(path, sizeof(path), "cutscenes/%s", file); - assetentry_t *entry = assetLock(path, ASSET_LOADER_TYPE_CUTSCENE, NULL); + assetentry_t *entry = assetLock(path, ASSET_LOADER_TYPE_JSON, NULL); errorret_t result = assetRequireLoaded(entry); - // Released the instant loading finishes - the loader already parsed - // everything we need into CUTSCENE_LOADED_SCENE/ITEMS/POOL, so nothing - // further depends on this entry (see cutscenesystem.h's doc comment on - // CUTSCENE_LOADED_ITEMS_MAX for why only one cutscene stays resident). - assetUnlockEntry(entry); if(errorIsNotOk(result)) { + assetUnlockEntry(entry); errorCatch(errorPrint(result)); uiFatalErrorOpen(NULL); return; } + // Steal the parsed doc before unlocking - assetJsonDispose would + // otherwise free it out from under CUTSCENE_LOADED_ITEMS' name pointers + // the moment this entry gets reaped. + yyjson_doc *doc = entry->data.json; + entry->data.json = NULL; + assetUnlockEntry(entry); + // Force this now-zero-ref entry to actually go away right away, rather + // than leaving it languishing as LOADED until something else happens to + // trigger a reap - assetRequireLoaded treats an already-LOADED entry as + // an instant cache hit with no reparsing, so a stale leftover entry for + // this same path would otherwise make a later load of it wrongly skip + // reloading, still returning CUTSCENE_LOADED_SCENE even after some + // other cutscene has since overwritten it. + assetReapUnused(); + + errorret_t parseResult = cutsceneParseDoc( + doc, &CUTSCENE_LOADED_SCENE, CUTSCENE_LOADED_ITEMS, + CUTSCENE_LOADED_ITEMS_MAX + ); + if(errorIsNotOk(parseResult)) { + yyjson_doc_free(doc); + errorCatch(errorPrint(parseResult)); + uiFatalErrorOpen(NULL); + return; + } + + cutsceneLoadedSetDoc(doc); cutsceneSystemStartCutscene(&CUTSCENE_LOADED_SCENE); } diff --git a/src/dusk/rpg/cutscene/cutscenesystem.h b/src/dusk/rpg/cutscene/cutscenesystem.h index 9b585f87..387b87a4 100644 --- a/src/dusk/rpg/cutscene/cutscenesystem.h +++ b/src/dusk/rpg/cutscene/cutscenesystem.h @@ -17,8 +17,8 @@ typedef struct entity_s entity_t; #define CUTSCENE_AREA_LAST_CREATED ((uint8_t)0xFF) #define CUTSCENE_TEXT_MINI_LAST_CREATED ((uint8_t)0xFA) -// Maximum number of bytes a running cutscene may request via -// cutscene_t.dataSize. +// Size in bytes of cutscenesystem_t.userData, the running cutscene's +// scratch space. #define CUTSCENE_SYSTEM_SIZE_MAX 8192 // Size of CUTSCENE_SYSTEM.textCache - keep >= UI_KEYBOARD_TEXT_MAX (see @@ -30,61 +30,59 @@ typedef struct entity_s entity_t; // CUTSCENE item hands control off completely (see cutsceneCutsceneStart) // and cutsceneSystemLoad/cutsceneCutsceneResolve release their asset lock // the instant loading finishes - so there's no benefit to malloc'ing a -// fresh items/pool buffer per load. Instead the asset loader -// (assetCutsceneLoaderAsync) parses directly into these fixed, static -// buffers. Bump these if a real cutscene ever needs more; C-authored -// cutscenes (the CUTSCENE(...) macro) don't use these at all - they're -// compiled directly into their own static const arrays. +// fresh items buffer per load. Instead those functions parse directly +// into this fixed, static buffer via cutsceneParseDoc (see cutscene.h), +// once the raw JSON itself has been read+parsed via the generic +// ASSET_LOADER_TYPE_JSON asset loader. Bump this if a real cutscene ever +// needs more; C-authored cutscenes (the CUTSCENE(...) macro) don't use +// this at all - they're compiled directly into their own static const +// arrays. #define CUTSCENE_LOADED_ITEMS_MAX 128 -#define CUTSCENE_LOADED_POOL_SIZE_MAX 4096 extern cutsceneitem_t CUTSCENE_LOADED_ITEMS[CUTSCENE_LOADED_ITEMS_MAX]; -extern uint8_t CUTSCENE_LOADED_POOL[CUTSCENE_LOADED_POOL_SIZE_MAX]; -// The cutscene_t for whatever was last parsed into CUTSCENE_LOADED_ITEMS/ -// CUTSCENE_LOADED_POOL - .items always points at CUTSCENE_LOADED_ITEMS; -// itemCount/pause/dataSize are overwritten by the loader on each load. +// The cutscene_t for whatever was last parsed into CUTSCENE_LOADED_ITEMS - +// .items always points at CUTSCENE_LOADED_ITEMS; itemCount/pause are +// overwritten by the loader on each load. extern cutscene_t CUTSCENE_LOADED_SCENE; /** * Frees whatever yyjson_doc currently backs CUTSCENE_LOADED_ITEMS' string * fields (marker/cutscene-reference names point directly into it - see * cutsceneCutsceneRefLoad/cutsceneMarkerLoad) and takes ownership of doc - * instead. Called by the cutscene asset loader once a fresh parse into - * CUTSCENE_LOADED_ITEMS/CUTSCENE_LOADED_POOL completes successfully, and - * from cutsceneSystemDispose to release the last one at shutdown. + * instead. Called by cutsceneSystemLoad/cutsceneCutsceneResolve once a + * fresh parse into CUTSCENE_LOADED_ITEMS completes successfully, and from + * cutsceneSystemDispose to release the last one at shutdown. * * @param doc The new doc to take ownership of (NULL just frees/clears the * current one). */ void cutsceneLoadedSetDoc(yyjson_doc *doc); -// A second, much smaller buffer set dedicated to CUTSCENE_ITEM_TYPE_INSERT +// A second, much smaller buffer dedicated to CUTSCENE_ITEM_TYPE_INSERT // (see cutsceneSystemInsertCutscene) - kept entirely separate from -// CUTSCENE_LOADED_ITEMS/POOL so that a JSON-authored INSERT item resolving -// its target by name (via cutsceneInsertResolve) never overwrites the -// buffer the currently-running outer cutscene's own items live in. Sized -// small deliberately - an inserted snippet is meant to be a short splice, -// not a full cutscene. +// CUTSCENE_LOADED_ITEMS so that a JSON-authored INSERT item resolving its +// target by name (via cutsceneInsertResolve) never overwrites the buffer +// the currently-running outer cutscene's own items live in. Sized small +// deliberately - an inserted snippet is meant to be a short splice, not a +// full cutscene. #define CUTSCENE_INSERT_ITEMS_MAX 16 -#define CUTSCENE_INSERT_POOL_SIZE_MAX 512 extern cutsceneitem_t CUTSCENE_INSERT_ITEMS[CUTSCENE_INSERT_ITEMS_MAX]; -extern uint8_t CUTSCENE_INSERT_POOL[CUTSCENE_INSERT_POOL_SIZE_MAX]; -// The cutscene_t for whatever was last parsed into CUTSCENE_INSERT_ITEMS/ -// CUTSCENE_INSERT_POOL - .items always points at CUTSCENE_INSERT_ITEMS. -// Only one JSON-authored INSERT target is ever resident at a time, same -// restriction as CUTSCENE_LOADED_SCENE - a JSON-authored INSERT whose -// target itself contains a JSON-authored INSERT would overwrite this out -// from under itself, so that isn't supported (compile-time CUTSCENE_INSERT -// nesting is unaffected, since it never touches asset loading). +// The cutscene_t for whatever was last parsed into CUTSCENE_INSERT_ITEMS - +// .items always points at CUTSCENE_INSERT_ITEMS. Only one JSON-authored +// INSERT target is ever resident at a time, same restriction as +// CUTSCENE_LOADED_SCENE - a JSON-authored INSERT whose target itself +// contains a JSON-authored INSERT would overwrite this out from under +// itself, so that isn't supported (compile-time CUTSCENE_INSERT nesting is +// unaffected, since it never touches asset loading). extern cutscene_t CUTSCENE_INSERT_SCENE; /** * Same as cutsceneLoadedSetDoc, but for whatever yyjson_doc currently - * backs CUTSCENE_INSERT_ITEMS' string fields. Called by the cutscene asset - * loader once a fresh parse into CUTSCENE_INSERT_ITEMS/CUTSCENE_INSERT_POOL + * backs CUTSCENE_INSERT_ITEMS' string fields. Called by + * cutsceneInsertResolve once a fresh parse into CUTSCENE_INSERT_ITEMS * completes successfully, and from cutsceneSystemDispose to release the * last one at shutdown. * @@ -125,8 +123,7 @@ typedef struct { // Data (used by the current item). cutsceneitemdata_t data; - // Custom user data for the running cutscene, sized per-scene by - // cutscene_t.dataSize. + // Custom user data for the running cutscene. uint8_t userData[CUTSCENE_SYSTEM_SIZE_MAX]; // See cutsceneSystemSetOnComplete. @@ -192,7 +189,7 @@ void cutsceneSystemStartCutsceneAndGoToMarker( * "last created" state, the text cache or userData - those all keep * whatever the outer cutscene set, since this is meant to feel like * pasting cutscene's items in place rather than starting an independent - * cutscene. Because of this, cutscene's own .pause/.dataSize are ignored. + * cutscene. Because of this, cutscene's own .pause is ignored. * Asserts if no cutscene is currently running, or if inserts are already * nested CUTSCENE_INSERT_STACK_MAX deep. * @@ -206,15 +203,15 @@ void cutsceneSystemStartCutsceneAndGoToMarker( void cutsceneSystemInsertCutscene(const cutscene_t *cutscene); /** - * Locks, loads and immediately starts a cutscene asset by file name, - * e.g. cutsceneSystemLoad("main_menu.jsonc") loads and starts - * assets/cutscenes/main_menu.jsonc - same lock/assetRequireLoaded/start - * sequence as sceneInitialInit's INITIAL_CUTSCENE_ENTRY. The entry is - * locked forever (never unlocked), same lifetime convention as - * LOCALE.entry - it's fine to call this again later for the same file, - * it'll just resolve to the same already-loaded entry. Opens the fatal - * error overlay (see uiFatalErrorOpen) instead of starting anything if - * the asset fails to load. + * Loads and immediately starts a cutscene asset by file name, e.g. + * cutsceneSystemLoad("main_menu.jsonc") loads and starts + * assets/cutscenes/main_menu.jsonc, parsing it into + * CUTSCENE_LOADED_SCENE/ITEMS - the underlying JSON asset entry is + * unlocked and reaped immediately once that's done (see + * CUTSCENE_LOADED_ITEMS_MAX's doc comment for why), so it's always + * re-read+re-parsed fresh, never assumed still resident from a previous + * call. Opens the fatal error overlay (see uiFatalErrorOpen) instead of + * starting anything if the asset fails to load. * * @param file Cutscene file name (with .jsonc extension), relative to * assets/cutscenes/. diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofade.c b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofade.c index a8a3be57..fbacb232 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofade.c +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofade.c @@ -33,9 +33,7 @@ bool_t cutsceneAudioFadeUpdate( errorret_t cutsceneAudioFadeLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { audiomixerchannel_t channelValue; if(!cutsceneJsonLookupAudioChannel( diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofade.h b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofade.h index e26ae42d..ea64f3b1 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofade.h +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofade.h @@ -92,13 +92,9 @@ bool_t cutsceneAudioFadeUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (AUDIO_FADE needs no pool storage). - * @param poolOffset Unused (AUDIO_FADE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneAudioFadeLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofadewait.c b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofadewait.c index 4b056b29..fd8a0912 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofadewait.c +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofadewait.c @@ -18,9 +18,7 @@ bool_t cutsceneAudioFadeWaitUpdate( errorret_t cutsceneAudioFadeWaitLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { return cutsceneJsonLoadAudioChannelOnly(itemObj, &item->audioFadeWaitChannel); } diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofadewait.h b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofadewait.h index 5a2cf04f..9fd4e406 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofadewait.h +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiofadewait.h @@ -37,13 +37,9 @@ bool_t cutsceneAudioFadeWaitUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (AUDIO_FADE_WAIT needs no pool storage). - * @param poolOffset Unused (AUDIO_FADE_WAIT needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneAudioFadeWaitLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiopause.c b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiopause.c index 896e3299..7b098c3c 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiopause.c +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiopause.c @@ -25,9 +25,7 @@ bool_t cutsceneAudioPauseUpdate( errorret_t cutsceneAudioPauseLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { return cutsceneJsonLoadAudioChannelOnly(itemObj, &item->audioPauseChannel); } diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiopause.h b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiopause.h index 64c28f4b..a3da736c 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiopause.h +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiopause.h @@ -45,13 +45,9 @@ bool_t cutsceneAudioPauseUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (AUDIO_PAUSE needs no pool storage). - * @param poolOffset Unused (AUDIO_PAUSE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneAudioPauseLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioplay.c b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioplay.c index 158c6020..e742a20b 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioplay.c +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioplay.c @@ -34,9 +34,7 @@ bool_t cutsceneAudioPlayUpdate( errorret_t cutsceneAudioPlayLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(!cutsceneJsonCopyString( itemObj, "file", NULL, item->audioPlay.file, AUDIO_PATH_MAX diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioplay.h b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioplay.h index df193c1d..26e5da61 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioplay.h +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioplay.h @@ -99,13 +99,9 @@ bool_t cutsceneAudioPlayUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (AUDIO_PLAY needs no pool storage). - * @param poolOffset Unused (AUDIO_PLAY needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneAudioPlayLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioresume.c b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioresume.c index 480b314c..c6ab25dc 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioresume.c +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioresume.c @@ -25,9 +25,7 @@ bool_t cutsceneAudioResumeUpdate( errorret_t cutsceneAudioResumeLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { return cutsceneJsonLoadAudioChannelOnly(itemObj, &item->audioResumeChannel); } diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioresume.h b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioresume.h index 551c5837..42fbef81 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioresume.h +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioresume.h @@ -45,13 +45,9 @@ bool_t cutsceneAudioResumeUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (AUDIO_RESUME needs no pool storage). - * @param poolOffset Unused (AUDIO_RESUME needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneAudioResumeLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioset.c b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioset.c index 7278b6d3..2e6ef12a 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioset.c +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioset.c @@ -33,9 +33,7 @@ bool_t cutsceneAudioSetUpdate( errorret_t cutsceneAudioSetLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { audiomixerchannel_t channelValue; if(!cutsceneJsonLookupAudioChannel( diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioset.h b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioset.h index 3f13fca1..bc10f42b 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudioset.h +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudioset.h @@ -73,13 +73,9 @@ bool_t cutsceneAudioSetUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (AUDIO_SET needs no pool storage). - * @param poolOffset Unused (AUDIO_SET needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneAudioSetLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetloop.c b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetloop.c index 74876402..101c563b 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetloop.c +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetloop.c @@ -32,9 +32,7 @@ bool_t cutsceneAudioSetLoopUpdate( errorret_t cutsceneAudioSetLoopLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { audiomixerchannel_t channelValue; if(!cutsceneJsonLookupAudioChannel( diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetloop.h b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetloop.h index 689fb3e0..366db2b7 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetloop.h +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetloop.h @@ -67,13 +67,9 @@ bool_t cutsceneAudioSetLoopUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (AUDIO_SET_LOOP needs no pool storage). - * @param poolOffset Unused (AUDIO_SET_LOOP needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneAudioSetLoopLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetpan.c b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetpan.c index 02270a96..04cef26d 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetpan.c +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetpan.c @@ -26,9 +26,7 @@ bool_t cutsceneAudioSetPanUpdate( errorret_t cutsceneAudioSetPanLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { audiomixerchannel_t channelValue; if(!cutsceneJsonLookupAudioChannel( diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetpan.h b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetpan.h index 72abf8fd..779e0460 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetpan.h +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiosetpan.h @@ -54,13 +54,9 @@ bool_t cutsceneAudioSetPanUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (AUDIO_SET_PAN needs no pool storage). - * @param poolOffset Unused (AUDIO_SET_PAN needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneAudioSetPanLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiostop.c b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiostop.c index 76cf0cde..0666a89d 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiostop.c +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiostop.c @@ -25,9 +25,7 @@ bool_t cutsceneAudioStopUpdate( errorret_t cutsceneAudioStopLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { return cutsceneJsonLoadAudioChannelOnly(itemObj, &item->audioStopChannel); } diff --git a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiostop.h b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiostop.h index a5515c63..35c2c579 100644 --- a/src/dusk/rpg/cutscene/item/audio/cutsceneaudiostop.h +++ b/src/dusk/rpg/cutscene/item/audio/cutsceneaudiostop.h @@ -45,13 +45,9 @@ bool_t cutsceneAudioStopUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (AUDIO_STOP needs no pool storage). - * @param poolOffset Unused (AUDIO_STOP needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneAudioStopLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/battle/cutscenebattleforceaction.c b/src/dusk/rpg/cutscene/item/battle/cutscenebattleforceaction.c index ceee7c32..34a497fe 100644 --- a/src/dusk/rpg/cutscene/item/battle/cutscenebattleforceaction.c +++ b/src/dusk/rpg/cutscene/item/battle/cutscenebattleforceaction.c @@ -26,9 +26,7 @@ bool_t cutsceneBattleForceActionUpdate( errorret_t cutsceneBattleForceActionLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { item->battleForceAction.fighterIndex = (uint8_t)yyjson_get_int(yyjson_obj_get(itemObj, "fighterIndex")); diff --git a/src/dusk/rpg/cutscene/item/battle/cutscenebattleforceaction.h b/src/dusk/rpg/cutscene/item/battle/cutscenebattleforceaction.h index 033cb1df..4a05a91c 100644 --- a/src/dusk/rpg/cutscene/item/battle/cutscenebattleforceaction.h +++ b/src/dusk/rpg/cutscene/item/battle/cutscenebattleforceaction.h @@ -56,13 +56,9 @@ bool_t cutsceneBattleForceActionUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (BATTLE_FORCE_ACTION needs no pool storage). - * @param poolOffset Unused (BATTLE_FORCE_ACTION needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneBattleForceActionLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/battle/cutscenebattlewaitstate.c b/src/dusk/rpg/cutscene/item/battle/cutscenebattlewaitstate.c index acc098c5..77b29035 100644 --- a/src/dusk/rpg/cutscene/item/battle/cutscenebattlewaitstate.c +++ b/src/dusk/rpg/cutscene/item/battle/cutscenebattlewaitstate.c @@ -17,9 +17,7 @@ bool_t cutsceneBattleWaitStateUpdate( errorret_t cutsceneBattleWaitStateLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { battlestate_t stateValue; if(!cutsceneJsonLookupBattleState( diff --git a/src/dusk/rpg/cutscene/item/battle/cutscenebattlewaitstate.h b/src/dusk/rpg/cutscene/item/battle/cutscenebattlewaitstate.h index 1e6618fc..f04d0283 100644 --- a/src/dusk/rpg/cutscene/item/battle/cutscenebattlewaitstate.h +++ b/src/dusk/rpg/cutscene/item/battle/cutscenebattlewaitstate.h @@ -47,13 +47,9 @@ bool_t cutsceneBattleWaitStateUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (BATTLE_WAIT_STATE needs no pool storage). - * @param poolOffset Unused (BATTLE_WAIT_STATE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneBattleWaitStateLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/battle/cutscenestartbattle.c b/src/dusk/rpg/cutscene/item/battle/cutscenestartbattle.c index 73ee5843..3cd12e7b 100644 --- a/src/dusk/rpg/cutscene/item/battle/cutscenestartbattle.c +++ b/src/dusk/rpg/cutscene/item/battle/cutscenestartbattle.c @@ -84,9 +84,7 @@ bool_t cutsceneStartBattleUpdate( errorret_t cutsceneStartBattleLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { battleencountertype_t encounterValue; if(!cutsceneJsonLookupBattleEncounter( diff --git a/src/dusk/rpg/cutscene/item/battle/cutscenestartbattle.h b/src/dusk/rpg/cutscene/item/battle/cutscenestartbattle.h index 007f16d3..405cbfbd 100644 --- a/src/dusk/rpg/cutscene/item/battle/cutscenestartbattle.h +++ b/src/dusk/rpg/cutscene/item/battle/cutscenestartbattle.h @@ -64,13 +64,9 @@ bool_t cutsceneStartBattleUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (START_BATTLE needs no pool storage). - * @param poolOffset Unused (START_BATTLE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneStartBattleLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/control/cutscenemarker.c b/src/dusk/rpg/cutscene/item/control/cutscenemarker.c index fddc305f..1e25da51 100644 --- a/src/dusk/rpg/cutscene/item/control/cutscenemarker.c +++ b/src/dusk/rpg/cutscene/item/control/cutscenemarker.c @@ -22,9 +22,7 @@ bool_t cutsceneMarkerUpdate( errorret_t cutsceneMarkerLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { const char_t *name = yyjson_get_str(yyjson_obj_get(itemObj, "name")); if(name == NULL) { diff --git a/src/dusk/rpg/cutscene/item/control/cutscenemarker.h b/src/dusk/rpg/cutscene/item/control/cutscenemarker.h index 4ea74dba..8034d901 100644 --- a/src/dusk/rpg/cutscene/item/control/cutscenemarker.h +++ b/src/dusk/rpg/cutscene/item/control/cutscenemarker.h @@ -52,13 +52,9 @@ bool_t cutsceneMarkerUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (MARKER needs no pool storage). - * @param poolOffset Unused (MARKER needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneMarkerLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/control/cutscenescene.c b/src/dusk/rpg/cutscene/item/control/cutscenescene.c index ce491fc2..57c92249 100644 --- a/src/dusk/rpg/cutscene/item/control/cutscenescene.c +++ b/src/dusk/rpg/cutscene/item/control/cutscenescene.c @@ -25,9 +25,7 @@ bool_t cutsceneSceneUpdate( errorret_t cutsceneSceneLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { scenetype_t sceneValue; if(!cutsceneJsonLookupSceneType( diff --git a/src/dusk/rpg/cutscene/item/control/cutscenescene.h b/src/dusk/rpg/cutscene/item/control/cutscenescene.h index 0cd0de69..663eacb1 100644 --- a/src/dusk/rpg/cutscene/item/control/cutscenescene.h +++ b/src/dusk/rpg/cutscene/item/control/cutscenescene.h @@ -56,13 +56,9 @@ bool_t cutsceneSceneUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (SCENE needs no pool storage). - * @param poolOffset Unused (SCENE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneSceneLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/control/cutscenesetpause.c b/src/dusk/rpg/cutscene/item/control/cutscenesetpause.c index e0b8db7b..e434a73d 100644 --- a/src/dusk/rpg/cutscene/item/control/cutscenesetpause.c +++ b/src/dusk/rpg/cutscene/item/control/cutscenesetpause.c @@ -25,9 +25,7 @@ bool_t cutsceneSetPauseUpdate( errorret_t cutsceneSetPauseLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { yyjson_val *flags = yyjson_obj_get(itemObj, "flags"); cutscenepause_t value; diff --git a/src/dusk/rpg/cutscene/item/control/cutscenesetpause.h b/src/dusk/rpg/cutscene/item/control/cutscenesetpause.h index d17416ad..85fdc035 100644 --- a/src/dusk/rpg/cutscene/item/control/cutscenesetpause.h +++ b/src/dusk/rpg/cutscene/item/control/cutscenesetpause.h @@ -45,13 +45,9 @@ bool_t cutsceneSetPauseUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (SET_PAUSE needs no pool storage). - * @param poolOffset Unused (SET_PAUSE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneSetPauseLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/control/cutscenewait.c b/src/dusk/rpg/cutscene/item/control/cutscenewait.c index b44ecb35..be5b84f6 100644 --- a/src/dusk/rpg/cutscene/item/control/cutscenewait.c +++ b/src/dusk/rpg/cutscene/item/control/cutscenewait.c @@ -26,9 +26,7 @@ bool_t cutsceneWaitUpdate( errorret_t cutsceneWaitLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { item->wait = cutsceneJsonGetFloat(itemObj, "seconds", 0.0f); diff --git a/src/dusk/rpg/cutscene/item/control/cutscenewait.h b/src/dusk/rpg/cutscene/item/control/cutscenewait.h index 528e9a3a..c8de04c6 100644 --- a/src/dusk/rpg/cutscene/item/control/cutscenewait.h +++ b/src/dusk/rpg/cutscene/item/control/cutscenewait.h @@ -47,13 +47,9 @@ bool_t cutsceneWaitUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (WAIT needs no pool storage). - * @param poolOffset Unused (WAIT needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneWaitLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); \ No newline at end of file diff --git a/src/dusk/rpg/cutscene/item/cutsceneitem.c b/src/dusk/rpg/cutscene/item/cutsceneitem.c index 48df4f61..4085cce6 100644 --- a/src/dusk/rpg/cutscene/item/cutsceneitem.c +++ b/src/dusk/rpg/cutscene/item/cutsceneitem.c @@ -68,8 +68,7 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = { .init = cutsceneEntityWalkToStart, .update = cutsceneEntityWalkToUpdate, .jsonName = "ENTITY_WALK_TO", - .load = cutsceneEntityWalkToLoad, - .poolSize = cutsceneEntityWalkToPoolSize + .load = cutsceneEntityWalkToLoad }, [CUTSCENE_ITEM_TYPE_FADE] = { @@ -142,8 +141,7 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = { .init = cutsceneMapAreaWaitStart, .update = cutsceneMapAreaWaitUpdate, .jsonName = "MAP_AREA_WAIT", - .load = cutsceneMapAreaWaitLoad, - .poolSize = cutsceneMapAreaWaitPoolSize + .load = cutsceneMapAreaWaitLoad }, [CUTSCENE_ITEM_TYPE_START_BATTLE] = { @@ -403,25 +401,48 @@ const cutscene_t * cutsceneCutsceneResolve(const char_t *name) { char_t path[ASSET_FILE_NAME_MAX]; stringFormat(path, sizeof(path), "cutscenes/%s.jsonc", name); - assetentry_t *entry = assetLock(path, ASSET_LOADER_TYPE_CUTSCENE, NULL); + assetentry_t *entry = assetLock(path, ASSET_LOADER_TYPE_JSON, NULL); errorret_t result = assetRequireLoaded(entry); - // Released the instant loading finishes - see cutsceneSystemLoad's doc - // comment for why nothing further depends on this entry once loaded. - assetUnlockEntry(entry); if(errorIsNotOk(result)) { + assetUnlockEntry(entry); errorCatch(errorPrint(result)); uiFatalErrorOpen(NULL); return NULL; } + // Steal the parsed doc before unlocking - assetJsonDispose would + // otherwise free it out from under CUTSCENE_LOADED_ITEMS' name pointers + // the moment this entry gets reaped. + yyjson_doc *doc = entry->data.json; + entry->data.json = NULL; + assetUnlockEntry(entry); + // Force this now-zero-ref entry to actually go away right away, rather + // than leaving it languishing as LOADED until something else happens to + // trigger a reap - assetRequireLoaded treats an already-LOADED entry as + // an instant cache hit with no reparsing, so a stale leftover entry for + // this same path would otherwise make a later resolve of it wrongly + // skip loading, still returning CUTSCENE_LOADED_SCENE even after some + // other cutscene has since overwritten it. + assetReapUnused(); + + errorret_t parseResult = cutsceneParseDoc( + doc, &CUTSCENE_LOADED_SCENE, CUTSCENE_LOADED_ITEMS, + CUTSCENE_LOADED_ITEMS_MAX + ); + if(errorIsNotOk(parseResult)) { + yyjson_doc_free(doc); + errorCatch(errorPrint(parseResult)); + uiFatalErrorOpen(NULL); + return NULL; + } + + cutsceneLoadedSetDoc(doc); return &CUTSCENE_LOADED_SCENE; } errorret_t cutsceneCutsceneLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { return cutsceneCutsceneRefLoad(itemObj, &item->cutsceneRef, "CUTSCENE"); } @@ -477,33 +498,44 @@ const cutscene_t * cutsceneInsertResolve(const char_t *name) { char_t path[ASSET_FILE_NAME_MAX]; stringFormat(path, sizeof(path), "cutscenes/%s.jsonc", name); - char_t key[ASSET_FILE_NAME_MAX]; - stringFormat(key, sizeof(key), "insert:%s", path); - - assetloaderinput_t input; - memoryZero(&input, sizeof(input)); - input.cutscene.dest = ASSET_CUTSCENE_LOAD_DEST_INSERT; - stringCopy(input.cutscene.path, path, ASSET_FILE_NAME_MAX); - - assetentry_t *entry = assetLock(key, ASSET_LOADER_TYPE_CUTSCENE, &input); + assetentry_t *entry = assetLock(path, ASSET_LOADER_TYPE_JSON, NULL); errorret_t result = assetRequireLoaded(entry); - // Released the instant loading finishes - see cutsceneSystemLoad's doc - // comment for why nothing further depends on this entry once loaded. - assetUnlockEntry(entry); if(errorIsNotOk(result)) { + assetUnlockEntry(entry); errorCatch(errorPrint(result)); uiFatalErrorOpen(NULL); return NULL; } + // Steal the parsed doc before unlocking - assetJsonDispose would + // otherwise free it out from under CUTSCENE_INSERT_ITEMS' name pointers + // the moment this entry gets reaped. + yyjson_doc *doc = entry->data.json; + entry->data.json = NULL; + assetUnlockEntry(entry); + // See cutsceneCutsceneResolve's matching comment - forces a stale + // leftover entry for this same path out immediately, so a later resolve + // never wrongly skips reloading it. + assetReapUnused(); + + errorret_t parseResult = cutsceneParseDoc( + doc, &CUTSCENE_INSERT_SCENE, CUTSCENE_INSERT_ITEMS, + CUTSCENE_INSERT_ITEMS_MAX + ); + if(errorIsNotOk(parseResult)) { + yyjson_doc_free(doc); + errorCatch(errorPrint(parseResult)); + uiFatalErrorOpen(NULL); + return NULL; + } + + cutsceneInsertSetDoc(doc); return &CUTSCENE_INSERT_SCENE; } errorret_t cutsceneInsertLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { return cutsceneCutsceneRefLoad(itemObj, &item->insert, "INSERT"); } diff --git a/src/dusk/rpg/cutscene/item/cutsceneitem.h b/src/dusk/rpg/cutscene/item/cutsceneitem.h index 36f42e2c..d3d338f6 100644 --- a/src/dusk/rpg/cutscene/item/cutsceneitem.h +++ b/src/dusk/rpg/cutscene/item/cutsceneitem.h @@ -150,22 +150,14 @@ typedef bool_t (cutsceneitemupdatecallback_t)( typedef errorret_t (cutsceneitemloadcallback_t)( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); -// Returns how many pool bytes (see cutsceneJsonPoolAlign) this JSON item -// needs - only ENTITY_WALK_TO/MAP_AREA_WAIT need this; every other type's -// poolSize is NULL (0 bytes). -typedef size_t (cutsceneitempoolsizecallback_t)(yyjson_val *itemObj); - typedef struct { cutsceneiteminitcallback_t *init; cutsceneitemupdatecallback_t *update; - const char_t *jsonName; // NULL if not JSON-authorable - cutsceneitemloadcallback_t *load; // NULL if not JSON-authorable - cutsceneitempoolsizecallback_t *poolSize; // NULL if this type needs no pool + const char_t *jsonName; // NULL if not JSON-authorable + cutsceneitemloadcallback_t *load; // NULL if not JSON-authorable } cutsceneitemcallbacks_t; extern cutsceneitemcallbacks_t @@ -264,15 +256,11 @@ bool_t cutsceneCutsceneUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (CUTSCENE needs no pool storage). - * @param poolOffset Unused (CUTSCENE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneCutsceneLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); /** @@ -301,8 +289,8 @@ errorret_t cutsceneCutsceneRefLoad( * been resolved yet (a JSON-authored reference, only known by name so * far), resolves it first via cutsceneInsertResolve - not * cutsceneCutsceneResolve, so the referenced cutscene lands in the - * dedicated CUTSCENE_INSERT_ITEMS/POOL buffer rather than overwriting - * CUTSCENE_LOADED_ITEMS/POOL out from under whatever outer cutscene is + * dedicated CUTSCENE_INSERT_ITEMS buffer rather than overwriting + * CUTSCENE_LOADED_ITEMS out from under whatever outer cutscene is * currently running (see cutscenesystem.h's CUTSCENE_INSERT_ITEMS_MAX doc * comment). Not cached back into item, same reasoning as * cutsceneCutsceneStart. @@ -316,15 +304,14 @@ void cutsceneInsertStart( ); /** - * Resolves a JSON-authored INSERT item's referenced cutscene by name, - * locking (under a synthetic "insert:cutscenes/.jsonc" cache key, - * distinct from the plain "cutscenes/.jsonc" key cutsceneCutsceneResolve - * uses for the same file, so a load driven by an INSERT item is never - * silently shared with - or overwritten by - a load driven by a CUTSCENE - * item, or vice versa - see assetGetEntry's name-only dedup) and blocking - * on assets/cutscenes/.jsonc, parsed into CUTSCENE_INSERT_ITEMS/POOL - * rather than CUTSCENE_LOADED_ITEMS/POOL. On failure, opens the fatal - * error overlay and returns NULL. + * Resolves a JSON-authored INSERT item's referenced cutscene by name - + * locks+loads assets/cutscenes/.jsonc (as a plain + * ASSET_LOADER_TYPE_JSON asset, same path/key convention as + * cutsceneCutsceneResolve - which destination buffer it lands in is + * decided purely by which resolve function is called, not stored on the + * asset entry itself), then parses it into CUTSCENE_INSERT_ITEMS rather + * than CUTSCENE_LOADED_ITEMS. On failure, opens the fatal error overlay + * and returns NULL. * * @param name Bare cutscene name (without "cutscenes/" prefix or * ".jsonc" suffix). @@ -350,13 +337,9 @@ bool_t cutsceneInsertUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (INSERT needs no pool storage). - * @param poolOffset Unused (INSERT needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneInsertLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/cutsceneitembase.c b/src/dusk/rpg/cutscene/item/cutsceneitembase.c index 5412dd5a..11cb848e 100644 --- a/src/dusk/rpg/cutscene/item/cutsceneitembase.c +++ b/src/dusk/rpg/cutscene/item/cutsceneitembase.c @@ -9,9 +9,7 @@ errorret_t cutsceneItemLoadNoop( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { errorOk(); } diff --git a/src/dusk/rpg/cutscene/item/cutsceneitembase.h b/src/dusk/rpg/cutscene/item/cutsceneitembase.h index 97764ade..8670749e 100644 --- a/src/dusk/rpg/cutscene/item/cutsceneitembase.h +++ b/src/dusk/rpg/cutscene/item/cutsceneitembase.h @@ -90,13 +90,9 @@ typedef enum { * * @param itemObj The item's JSON object (unused). * @param item Destination item (unused). - * @param pool Unused. - * @param poolOffset Unused. * @return Always errorOk(). */ errorret_t cutsceneItemLoadNoop( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/cutsceneprint.c b/src/dusk/rpg/cutscene/item/cutsceneprint.c index 98fc1594..45b084cf 100644 --- a/src/dusk/rpg/cutscene/item/cutsceneprint.c +++ b/src/dusk/rpg/cutscene/item/cutsceneprint.c @@ -25,9 +25,7 @@ bool_t cutscenePrintUpdate( errorret_t cutscenePrintLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(!cutsceneJsonCopyString( itemObj, "text", NULL, item->print.text, CUTSCENE_PRINT_MAX_CHARS diff --git a/src/dusk/rpg/cutscene/item/cutsceneprint.h b/src/dusk/rpg/cutscene/item/cutsceneprint.h index a60aabcd..202dac87 100644 --- a/src/dusk/rpg/cutscene/item/cutsceneprint.h +++ b/src/dusk/rpg/cutscene/item/cutsceneprint.h @@ -50,13 +50,9 @@ bool_t cutscenePrintUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (PRINT needs no pool storage). - * @param poolOffset Unused (PRINT needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutscenePrintLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.c b/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.c index d3c905a5..75992fe6 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.c +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.c @@ -38,9 +38,7 @@ bool_t cutsceneEntityAddUpdate( errorret_t cutsceneEntityAddLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { entitytype_t entityTypeValue; if(!cutsceneJsonLookupEntityType( diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.h b/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.h index dc193d16..b7690061 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.h +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentityadd.h @@ -56,13 +56,9 @@ bool_t cutsceneEntityAddUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (ENTITY_ADD needs no pool storage). - * @param poolOffset Unused (ENTITY_ADD needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneEntityAddLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentityremove.c b/src/dusk/rpg/cutscene/item/entity/cutsceneentityremove.c index 10b77b4a..3a1a02c2 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentityremove.c +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentityremove.c @@ -29,9 +29,7 @@ bool_t cutsceneEntityRemoveUpdate( errorret_t cutsceneEntityRemoveLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(!cutsceneJsonGetEntityIndex( yyjson_obj_get(itemObj, "entityIndex"), &item->entityRemove.entityIndex diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentityremove.h b/src/dusk/rpg/cutscene/item/entity/cutsceneentityremove.h index 88c3b8bd..f3efe576 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentityremove.h +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentityremove.h @@ -50,13 +50,9 @@ bool_t cutsceneEntityRemoveUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (ENTITY_REMOVE needs no pool storage). - * @param poolOffset Unused (ENTITY_REMOVE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneEntityRemoveLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentityteleport.c b/src/dusk/rpg/cutscene/item/entity/cutsceneentityteleport.c index c35e52f6..b63608fb 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentityteleport.c +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentityteleport.c @@ -30,9 +30,7 @@ bool_t cutsceneEntityTeleportUpdate( errorret_t cutsceneEntityTeleportLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(!cutsceneJsonGetEntityIndex( yyjson_obj_get(itemObj, "entityIndex"), diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentityteleport.h b/src/dusk/rpg/cutscene/item/entity/cutsceneentityteleport.h index fc724023..4a790756 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentityteleport.h +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentityteleport.h @@ -55,13 +55,9 @@ bool_t cutsceneEntityTeleportUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (ENTITY_TELEPORT needs no pool storage). - * @param poolOffset Unused (ENTITY_TELEPORT needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneEntityTeleportLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentityturn.c b/src/dusk/rpg/cutscene/item/entity/cutsceneentityturn.c index 37f412b8..00b7f7cb 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentityturn.c +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentityturn.c @@ -33,9 +33,7 @@ bool_t cutsceneEntityTurnUpdate( errorret_t cutsceneEntityTurnLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(!cutsceneJsonGetEntityIndex( yyjson_obj_get(itemObj, "entityIndex"), &item->entityTurn.entityIndex diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentityturn.h b/src/dusk/rpg/cutscene/item/entity/cutsceneentityturn.h index 57a65839..ee62f97d 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentityturn.h +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentityturn.h @@ -55,13 +55,9 @@ bool_t cutsceneEntityTurnUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (ENTITY_TURN needs no pool storage). - * @param poolOffset Unused (ENTITY_TURN needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneEntityTurnLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalkto.c b/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalkto.c index 3f5241e6..16a82a08 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalkto.c +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalkto.c @@ -10,12 +10,16 @@ #include "rpg/entity/entitypathstep.h" #include "rpg/cutscene/item/json/cutscenejsonentityindex.h" #include "rpg/cutscene/item/json/cutscenejsonfield.h" -#include "rpg/cutscene/item/json/cutscenejsonpool.h" +#include "assert/assert.h" void cutsceneEntityWalkToStart( const cutsceneitem_t *item, cutsceneitemdata_t *data ) { + assertTrue( + item->entityWalkTo.count <= CUTSCENE_ENTITY_WALK_TO_MAX, + "Too many waypoints in CUTSCENE_ENTITY_WALK_TO" + ); data->entityWalkTo.currentIndex = 0; } @@ -40,9 +44,7 @@ bool_t cutsceneEntityWalkToUpdate( errorret_t cutsceneEntityWalkToLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(!cutsceneJsonGetEntityIndex( yyjson_obj_get(itemObj, "entityIndex"), &item->entityWalkTo.entityIndex @@ -54,20 +56,22 @@ errorret_t cutsceneEntityWalkToLoad( yyjson_val *positions = yyjson_obj_get(itemObj, "positions"); size_t count = yyjson_arr_size(positions); - if(!yyjson_is_arr(positions) || count == 0 || count > UINT8_MAX) { + if( + !yyjson_is_arr(positions) || count == 0 || + count > CUTSCENE_ENTITY_WALK_TO_MAX + ) { errorThrow( - "Cutscene item (ENTITY_WALK_TO): 'positions' must be a non-empty " - "array of [x, y, z]" + "Cutscene item (ENTITY_WALK_TO): 'positions' must have 1-%u entries " + "of [x, y, z]", + (uint32_t)CUTSCENE_ENTITY_WALK_TO_MAX ); } - *poolOffset = cutsceneJsonPoolAlign(*poolOffset); - worldpos_t *dest = (worldpos_t *)(pool + *poolOffset); yyjson_arr_iter iter = yyjson_arr_iter_with(positions); yyjson_val *posVal; size_t i = 0; while((posVal = yyjson_arr_iter_next(&iter)) != NULL) { - if(!cutsceneJsonReadWorldPos(posVal, &dest[i])) { + if(!cutsceneJsonReadWorldPos(posVal, &item->entityWalkTo.positions[i])) { errorThrow( "Cutscene item (ENTITY_WALK_TO): position %u must be [x, y, z]", (uint32_t)i @@ -75,15 +79,7 @@ errorret_t cutsceneEntityWalkToLoad( } i++; } - item->entityWalkTo.positions = dest; item->entityWalkTo.count = (uint8_t)count; - *poolOffset += count * sizeof(worldpos_t); errorOk(); } - -size_t cutsceneEntityWalkToPoolSize(yyjson_val *itemObj) { - yyjson_val *positions = yyjson_obj_get(itemObj, "positions"); - if(!yyjson_is_arr(positions)) return 0; - return yyjson_arr_size(positions) * sizeof(worldpos_t); -} diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalkto.h b/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalkto.h index 25a2aac8..75035baa 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalkto.h +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalkto.h @@ -9,9 +9,14 @@ #include "rpg/overworld/worldpos.h" #include "rpg/cutscene/item/cutsceneitembase.h" +// Maximum number of waypoints a single ENTITY_WALK_TO/ +// CUTSCENE_ENTITY_WALK_PATH may hold - generous relative to every current +// asset/C-authored cutscene (none use more than a couple waypoints). +#define CUTSCENE_ENTITY_WALK_TO_MAX 16 + typedef struct { uint8_t entityIndex; - const worldpos_t *positions; + worldpos_t positions[CUTSCENE_ENTITY_WALK_TO_MAX]; uint8_t count; bool_t walkAround; } cutsceneentitywalkto_t; @@ -32,29 +37,29 @@ typedef struct { #define CUTSCENE_ENTITY_WALK_TO(ENTITY_INDEX, X, Y, Z) \ CUTSCENE_ITEM(CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO, entityWalkTo, { \ .entityIndex = ENTITY_INDEX, \ - .positions = (const worldpos_t[]){ { X, Y, Z } }, \ + .positions = { { X, Y, Z } }, \ .count = 1, \ .walkAround = true \ }) /** * Declares a standalone, named cutsceneitem_t (not a list entry) that - * walks an entity through a fixed sequence of waypoints. + * walks an entity through a fixed sequence of waypoints. ... must not + * exceed CUTSCENE_ENTITY_WALK_TO_MAX entries - the compiler rejects the + * initializer with "excess elements in array initializer" if it does. * - * @param NAME Suffix for the generated CUTSCENE_##NAME item/positions - * statics. + * @param NAME Suffix for the generated CUTSCENE_##NAME static. * @param ENTITY_INDEX Entity index to move. * @param ... One or more worldpos_t-shaped waypoint initializers, e.g. - * { X, Y, Z }, { X2, Y2, Z2 }. + * { X, Y, Z }, { X2, Y2, Z2 } - at most CUTSCENE_ENTITY_WALK_TO_MAX. */ #define CUTSCENE_ENTITY_WALK_PATH(NAME, ENTITY_INDEX, ...) \ - static const worldpos_t CUTSCENE_##NAME##_POSITIONS[] = { __VA_ARGS__ }; \ static const cutsceneitem_t CUTSCENE_##NAME = { \ .type = CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO, \ .entityWalkTo = { \ .entityIndex = ENTITY_INDEX, \ - .positions = CUTSCENE_##NAME##_POSITIONS, \ - .count = sizeof(CUTSCENE_##NAME##_POSITIONS) / sizeof(worldpos_t), \ + .positions = { __VA_ARGS__ }, \ + .count = sizeof((const worldpos_t[]){ __VA_ARGS__ }) / sizeof(worldpos_t), \ .walkAround = true \ } \ }; @@ -84,26 +89,14 @@ bool_t cutsceneEntityWalkToUpdate( /** * Parses an ENTITY_WALK_TO cutscene item's JSON fields into item, writing - * its "positions" array into pool at *poolOffset and advancing it. + * its "positions" array directly into item->entityWalkTo.positions (at + * most CUTSCENE_ENTITY_WALK_TO_MAX entries). * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Base pointer of the entry's pool allocation. - * @param poolOffset In/out cursor into pool. * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneEntityWalkToLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); - -/** - * Computes how many pool bytes this ENTITY_WALK_TO item's "positions" - * array will need. - * - * @param itemObj The item's JSON object. - * @return Pool bytes required (0 if "positions" is missing/not an array). - */ -size_t cutsceneEntityWalkToPoolSize(yyjson_val *itemObj); diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalktoentity.c b/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalktoentity.c index 0adb0425..208beea7 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalktoentity.c +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalktoentity.c @@ -43,9 +43,7 @@ bool_t cutsceneEntityWalkToEntityUpdate( errorret_t cutsceneEntityWalkToEntityLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(!cutsceneJsonGetEntityIndex( yyjson_obj_get(itemObj, "entityIndex"), diff --git a/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalktoentity.h b/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalktoentity.h index 114fe4d8..d1b7ebf1 100644 --- a/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalktoentity.h +++ b/src/dusk/rpg/cutscene/item/entity/cutsceneentitywalktoentity.h @@ -69,13 +69,9 @@ bool_t cutsceneEntityWalkToEntityUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (ENTITY_WALK_TO_ENTITY needs no pool storage). - * @param poolOffset Unused (ENTITY_WALK_TO_ENTITY needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneEntityWalkToEntityLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.c b/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.c index ddb2d147..975aada8 100644 --- a/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.c +++ b/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.c @@ -25,9 +25,7 @@ bool_t cutsceneItemGiveUpdate( errorret_t cutsceneItemGiveLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { item->itemGive.item = (itemid_t)yyjson_get_int(yyjson_obj_get(itemObj, "item")); diff --git a/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.h b/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.h index e5587a8a..b731be8c 100644 --- a/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.h +++ b/src/dusk/rpg/cutscene/item/item/cutsceneitemgive.h @@ -53,13 +53,9 @@ bool_t cutsceneItemGiveUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (ITEM_GIVE needs no pool storage). - * @param poolOffset Unused (ITEM_GIVE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneItemGiveLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/json/CMakeLists.txt b/src/dusk/rpg/cutscene/item/json/CMakeLists.txt index 2afa3112..b69ad77a 100644 --- a/src/dusk/rpg/cutscene/item/json/CMakeLists.txt +++ b/src/dusk/rpg/cutscene/item/json/CMakeLists.txt @@ -9,7 +9,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} cutscenejsonfield.c cutscenejsonentityindex.c cutscenejsonareaid.c - cutscenejsonpool.c cutscenejsonpauseflags.c cutscenejsoneasing.c cutscenejsonemoji.c diff --git a/src/dusk/rpg/cutscene/item/json/cutscenejsonpauseflags.h b/src/dusk/rpg/cutscene/item/json/cutscenejsonpauseflags.h index dafe95ea..b6bccb6b 100644 --- a/src/dusk/rpg/cutscene/item/json/cutscenejsonpauseflags.h +++ b/src/dusk/rpg/cutscene/item/json/cutscenejsonpauseflags.h @@ -12,7 +12,7 @@ /** * Parses a JSON array of pause flag name strings, OR-ing each into out. - * Shared by the top-level "pause" field (assetCutsceneLoaderSync) and the + * Shared by the top-level "pause" field (cutsceneParseDoc) and the * SET_PAUSE item's "flags" field - both authored as the same shape. * * @param arr JSON array of pause flag name strings. diff --git a/src/dusk/rpg/cutscene/item/json/cutscenejsonpool.c b/src/dusk/rpg/cutscene/item/json/cutscenejsonpool.c deleted file mode 100644 index ca8928c4..00000000 --- a/src/dusk/rpg/cutscene/item/json/cutscenejsonpool.c +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "cutscenejsonpool.h" - -size_t cutsceneJsonPoolAlign(const size_t size) { - return (size + 3) & ~((size_t)3); -} diff --git a/src/dusk/rpg/cutscene/item/json/cutscenejsonpool.h b/src/dusk/rpg/cutscene/item/json/cutscenejsonpool.h deleted file mode 100644 index 39bae091..00000000 --- a/src/dusk/rpg/cutscene/item/json/cutscenejsonpool.h +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" - -/** - * Rounds size up to the next multiple of 4 - every pool entry starts - * 4-byte aligned so worldpos_t/multi-byte reads out of it never trap on - * alignment-sensitive hardware (e.g. PSP's MIPS core). - * - * @param size Size to round up. - * @return size rounded up to the next multiple of 4. - */ -size_t cutsceneJsonPoolAlign(const size_t size); diff --git a/src/dusk/rpg/cutscene/item/maparea/cutscenemaparearemove.c b/src/dusk/rpg/cutscene/item/maparea/cutscenemaparearemove.c index 84b0c77c..47a0065d 100644 --- a/src/dusk/rpg/cutscene/item/maparea/cutscenemaparearemove.c +++ b/src/dusk/rpg/cutscene/item/maparea/cutscenemaparearemove.c @@ -26,9 +26,7 @@ bool_t cutsceneMapAreaRemoveUpdate( errorret_t cutsceneMapAreaRemoveLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(!cutsceneJsonGetAreaId( yyjson_obj_get(itemObj, "areaId"), &item->mapAreaRemove.areaId diff --git a/src/dusk/rpg/cutscene/item/maparea/cutscenemaparearemove.h b/src/dusk/rpg/cutscene/item/maparea/cutscenemaparearemove.h index 45d38599..e5385ce2 100644 --- a/src/dusk/rpg/cutscene/item/maparea/cutscenemaparearemove.h +++ b/src/dusk/rpg/cutscene/item/maparea/cutscenemaparearemove.h @@ -52,13 +52,9 @@ bool_t cutsceneMapAreaRemoveUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (MAP_AREA_REMOVE needs no pool storage). - * @param poolOffset Unused (MAP_AREA_REMOVE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneMapAreaRemoveLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/maparea/cutscenemapareawait.c b/src/dusk/rpg/cutscene/item/maparea/cutscenemapareawait.c index af94ab3c..1acbb963 100644 --- a/src/dusk/rpg/cutscene/item/maparea/cutscenemapareawait.c +++ b/src/dusk/rpg/cutscene/item/maparea/cutscenemapareawait.c @@ -10,7 +10,6 @@ #include "rpg/overworld/maparea.h" #include "assert/assert.h" #include "rpg/cutscene/item/json/cutscenejsonareaid.h" -#include "rpg/cutscene/item/json/cutscenejsonpool.h" void cutsceneMapAreaWaitStart( const cutsceneitem_t *item, @@ -43,9 +42,7 @@ bool_t cutsceneMapAreaWaitUpdate( errorret_t cutsceneMapAreaWaitLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { yyjson_val *areaIds = yyjson_obj_get(itemObj, "areaIds"); size_t count = yyjson_arr_size(areaIds); @@ -58,28 +55,18 @@ errorret_t cutsceneMapAreaWaitLoad( (uint32_t)CUTSCENE_MAP_AREA_WAIT_MAX ); } - *poolOffset = cutsceneJsonPoolAlign(*poolOffset); - uint8_t *dest = pool + *poolOffset; yyjson_arr_iter iter = yyjson_arr_iter_with(areaIds); yyjson_val *idVal; size_t i = 0; while((idVal = yyjson_arr_iter_next(&iter)) != NULL) { - if(!cutsceneJsonGetAreaId(idVal, &dest[i])) { + if(!cutsceneJsonGetAreaId(idVal, &item->mapAreaWait.areaIds[i])) { errorThrow( "Cutscene item (MAP_AREA_WAIT): areaIds[%u] is invalid", (uint32_t)i ); } i++; } - item->mapAreaWait.areaIds = dest; item->mapAreaWait.count = (uint8_t)count; - *poolOffset += count; errorOk(); } - -size_t cutsceneMapAreaWaitPoolSize(yyjson_val *itemObj) { - yyjson_val *areaIds = yyjson_obj_get(itemObj, "areaIds"); - if(!yyjson_is_arr(areaIds)) return 0; - return yyjson_arr_size(areaIds); -} diff --git a/src/dusk/rpg/cutscene/item/maparea/cutscenemapareawait.h b/src/dusk/rpg/cutscene/item/maparea/cutscenemapareawait.h index 575b023c..4c89b284 100644 --- a/src/dusk/rpg/cutscene/item/maparea/cutscenemapareawait.h +++ b/src/dusk/rpg/cutscene/item/maparea/cutscenemapareawait.h @@ -12,7 +12,7 @@ #define CUTSCENE_MAP_AREA_WAIT_MAX 4 typedef struct { - const uint8_t *areaIds; + uint8_t areaIds[CUTSCENE_MAP_AREA_WAIT_MAX]; uint8_t count; } cutscenemapareawait_t; @@ -28,7 +28,7 @@ typedef struct { */ #define CUTSCENE_MAP_AREA_WAIT(...) \ CUTSCENE_ITEM(CUTSCENE_ITEM_TYPE_MAP_AREA_WAIT, mapAreaWait, { \ - .areaIds = (const uint8_t[]){ __VA_ARGS__ }, \ + .areaIds = { __VA_ARGS__ }, \ .count = (uint8_t)( \ sizeof((const uint8_t[]){ __VA_ARGS__ }) / sizeof(uint8_t) \ ) \ @@ -61,26 +61,13 @@ bool_t cutsceneMapAreaWaitUpdate( /** * Parses a MAP_AREA_WAIT cutscene item's JSON fields into item, writing its - * "areaIds" array into pool at *poolOffset and advancing it. + * "areaIds" array directly into item->mapAreaWait.areaIds. * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Base pointer of the entry's pool allocation. - * @param poolOffset In/out cursor into pool. * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneMapAreaWaitLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); - -/** - * Computes how many pool bytes this MAP_AREA_WAIT item's "areaIds" array - * will need. - * - * @param itemObj The item's JSON object. - * @return Pool bytes required (0 if "areaIds" is missing/not an array). - */ -size_t cutsceneMapAreaWaitPoolSize(yyjson_val *itemObj); diff --git a/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.c b/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.c index 4a4204ff..374710d9 100644 --- a/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.c +++ b/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.c @@ -34,9 +34,7 @@ bool_t cutsceneSaveDeviceCheckUpdate( errorret_t cutsceneSaveDeviceCheckLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { const char_t *successMarker = yyjson_get_str(yyjson_obj_get(itemObj, "successMarker")); diff --git a/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.h b/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.h index 24c21c42..6b1bfcd6 100644 --- a/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.h +++ b/src/dusk/rpg/cutscene/item/save/cutscenesavedevicecheck.h @@ -62,13 +62,9 @@ bool_t cutsceneSaveDeviceCheckUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (SAVE_DEVICE_CHECK needs no pool storage). - * @param poolOffset Unused (SAVE_DEVICE_CHECK needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneSaveDeviceCheckLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.c b/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.c index 743f2b83..483e8073 100644 --- a/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.c +++ b/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.c @@ -32,9 +32,7 @@ bool_t cutsceneSaveLoadAllSlotsUpdate( errorret_t cutsceneSaveLoadAllSlotsLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { const char_t *successMarker = yyjson_get_str(yyjson_obj_get(itemObj, "successMarker")); diff --git a/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.h b/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.h index e1aeac2e..0523426c 100644 --- a/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.h +++ b/src/dusk/rpg/cutscene/item/save/cutscenesaveloadallslots.h @@ -61,13 +61,9 @@ bool_t cutsceneSaveLoadAllSlotsUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (SAVE_LOAD_ALL_SLOTS needs no pool storage). - * @param poolOffset Unused (SAVE_LOAD_ALL_SLOTS needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneSaveLoadAllSlotsLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/ui/cutsceneemoji.c b/src/dusk/rpg/cutscene/item/ui/cutsceneemoji.c index 3d41fe7f..43b4466f 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutsceneemoji.c +++ b/src/dusk/rpg/cutscene/item/ui/cutsceneemoji.c @@ -29,9 +29,7 @@ bool_t cutsceneEmojiUpdate( errorret_t cutsceneEmojiLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(!cutsceneJsonGetEntityIndex( yyjson_obj_get(itemObj, "entityIndex"), &item->emoji.entityIndex diff --git a/src/dusk/rpg/cutscene/item/ui/cutsceneemoji.h b/src/dusk/rpg/cutscene/item/ui/cutsceneemoji.h index 5467bc68..b7c517d8 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutsceneemoji.h +++ b/src/dusk/rpg/cutscene/item/ui/cutsceneemoji.h @@ -59,13 +59,9 @@ bool_t cutsceneEmojiUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (EMOJI needs no pool storage). - * @param poolOffset Unused (EMOJI needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneEmojiLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenefade.c b/src/dusk/rpg/cutscene/item/ui/cutscenefade.c index f52e4fe2..3b796b10 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenefade.c +++ b/src/dusk/rpg/cutscene/item/ui/cutscenefade.c @@ -35,9 +35,7 @@ bool_t cutsceneFadeUpdate( errorret_t cutsceneFadeLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { yyjson_val *from = yyjson_obj_get(itemObj, "from"); yyjson_val *to = yyjson_obj_get(itemObj, "to"); diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenefade.h b/src/dusk/rpg/cutscene/item/ui/cutscenefade.h index 952acd46..31e420b0 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenefade.h +++ b/src/dusk/rpg/cutscene/item/ui/cutscenefade.h @@ -91,13 +91,9 @@ bool_t cutsceneFadeUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (FADE needs no pool storage). - * @param poolOffset Unused (FADE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneFadeLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenemodal.c b/src/dusk/rpg/cutscene/item/ui/cutscenemodal.c index 4d2e5848..b019f589 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenemodal.c +++ b/src/dusk/rpg/cutscene/item/ui/cutscenemodal.c @@ -55,9 +55,7 @@ bool_t cutsceneModalCloseUpdate( errorret_t cutsceneModalLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(yyjson_obj_get(itemObj, "options") != NULL) { errorThrow( diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenemodal.h b/src/dusk/rpg/cutscene/item/ui/cutscenemodal.h index 2e6b7547..497358d3 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenemodal.h +++ b/src/dusk/rpg/cutscene/item/ui/cutscenemodal.h @@ -137,15 +137,11 @@ bool_t cutsceneModalUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (MODAL needs no pool storage). - * @param poolOffset Unused (MODAL needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneModalLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); /** diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.c b/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.c index 41c1e76e..af742cc2 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.c +++ b/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.c @@ -52,9 +52,7 @@ bool_t cutsceneModalOptionsMarkersUpdate( errorret_t cutsceneModalOptionsMarkersLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { cutsceneJsonCopyString( itemObj, "title", "", item->modalOptionsMarkers.title, diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.h b/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.h index 895e1af8..2bc2f500 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.h +++ b/src/dusk/rpg/cutscene/item/ui/cutscenemodaloptionsmarkers.h @@ -102,13 +102,9 @@ bool_t cutsceneModalOptionsMarkersUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (MODAL_OPTIONS_MARKERS needs no pool storage). - * @param poolOffset Unused (MODAL_OPTIONS_MARKERS needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneModalOptionsMarkersLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/ui/cutsceneshake.c b/src/dusk/rpg/cutscene/item/ui/cutsceneshake.c index b5d570f3..674286f2 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutsceneshake.c +++ b/src/dusk/rpg/cutscene/item/ui/cutsceneshake.c @@ -25,9 +25,7 @@ bool_t cutsceneShakeUpdate( errorret_t cutsceneShakeLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { item->shake.amount = (uint8_t)cutsceneJsonGetInt(itemObj, "amount", 0); item->shake.duration = cutsceneJsonGetFloat(itemObj, "duration", 0.0f); diff --git a/src/dusk/rpg/cutscene/item/ui/cutsceneshake.h b/src/dusk/rpg/cutscene/item/ui/cutsceneshake.h index cc94d2ba..715e7068 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutsceneshake.h +++ b/src/dusk/rpg/cutscene/item/ui/cutsceneshake.h @@ -54,13 +54,9 @@ bool_t cutsceneShakeUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (SHAKE needs no pool storage). - * @param poolOffset Unused (SHAKE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneShakeLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenetext.c b/src/dusk/rpg/cutscene/item/ui/cutscenetext.c index aadd0d9e..8dc5c70a 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenetext.c +++ b/src/dusk/rpg/cutscene/item/ui/cutscenetext.c @@ -25,9 +25,7 @@ bool_t cutsceneTextUpdate( errorret_t cutsceneTextLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(!cutsceneJsonCopyString( itemObj, "text", NULL, item->text.text, CUTSCENE_TEXT_MAX_CHARS diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenetext.h b/src/dusk/rpg/cutscene/item/ui/cutscenetext.h index eb4aa62f..c040c27a 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenetext.h +++ b/src/dusk/rpg/cutscene/item/ui/cutscenetext.h @@ -50,13 +50,9 @@ bool_t cutsceneTextUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (TEXT needs no pool storage). - * @param poolOffset Unused (TEXT needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneTextLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); \ No newline at end of file diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c b/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c index 783d4499..53e511b4 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c +++ b/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.c @@ -35,9 +35,7 @@ bool_t cutsceneTextMiniUpdate( errorret_t cutsceneTextMiniLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { if(!cutsceneJsonCopyString( itemObj, "text", NULL, item->textMini.text, CUTSCENE_TEXT_MINI_MAX_CHARS diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.h b/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.h index 50750f82..b0ccd4a7 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.h +++ b/src/dusk/rpg/cutscene/item/ui/cutscenetextmini.h @@ -62,13 +62,9 @@ bool_t cutsceneTextMiniUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (TEXT_MINI needs no pool storage). - * @param poolOffset Unused (TEXT_MINI needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneTextMiniLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.c b/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.c index 5041d026..b4df6066 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.c +++ b/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.c @@ -26,9 +26,7 @@ bool_t cutsceneTextMiniHideUpdate( errorret_t cutsceneTextMiniHideLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { item->textMiniHide.index = (uint8_t)yyjson_get_int(yyjson_obj_get(itemObj, "index")); diff --git a/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.h b/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.h index db8826f8..8c63ee4f 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.h +++ b/src/dusk/rpg/cutscene/item/ui/cutscenetextminihide.h @@ -50,13 +50,9 @@ bool_t cutsceneTextMiniHideUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (TEXT_MINI_HIDE needs no pool storage). - * @param poolOffset Unused (TEXT_MINI_HIDE needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneTextMiniHideLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/item/ui/cutsceneuishow.c b/src/dusk/rpg/cutscene/item/ui/cutsceneuishow.c index 1cc8b74d..3ec69432 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutsceneuishow.c +++ b/src/dusk/rpg/cutscene/item/ui/cutsceneuishow.c @@ -29,9 +29,7 @@ bool_t cutsceneUIShowUpdate( errorret_t cutsceneUIShowLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ) { uiscreentype_t screenValue; if(!cutsceneJsonLookupUiScreenType( diff --git a/src/dusk/rpg/cutscene/item/ui/cutsceneuishow.h b/src/dusk/rpg/cutscene/item/ui/cutsceneuishow.h index 54a8c513..1f848f7a 100644 --- a/src/dusk/rpg/cutscene/item/ui/cutsceneuishow.h +++ b/src/dusk/rpg/cutscene/item/ui/cutsceneuishow.h @@ -58,13 +58,9 @@ bool_t cutsceneUIShowUpdate( * * @param itemObj The item's JSON object. * @param item Destination item, already zeroed by the caller. - * @param pool Unused (UI_SHOW needs no pool storage). - * @param poolOffset Unused (UI_SHOW needs no pool storage). * @return Error code indicating success or failure of the parse. */ errorret_t cutsceneUIShowLoad( yyjson_val *itemObj, - cutsceneitem_t *item, - uint8_t *pool, - size_t *poolOffset + cutsceneitem_t *item ); diff --git a/src/dusk/rpg/cutscene/scene/testcutscene.h b/src/dusk/rpg/cutscene/scene/testcutscene.h index 10f7ba5f..2dbf5723 100755 --- a/src/dusk/rpg/cutscene/scene/testcutscene.h +++ b/src/dusk/rpg/cutscene/scene/testcutscene.h @@ -9,11 +9,11 @@ #include "rpg/cutscene/cutscene.h" #include "rpg/cutscene/cutscenesystem.h" -CUTSCENE(TEST_ONE, 0, DEFAULT, +CUTSCENE(TEST_ONE, DEFAULT, CUTSCENE_TEXT("Test One."), ); -CUTSCENE(TEST_TWO, 0, DEFAULT, +CUTSCENE(TEST_TWO, DEFAULT, CUTSCENE_TEXT("Test Two."), CUTSCENE_ENTITY_ADD(ENTITY_TYPE_NPC, 4, 4, 0), CUTSCENE_TEXT_MINI("Hello!", 4, 4, 0, 3.0f), diff --git a/test/rpg/battle/test_battle.c b/test/rpg/battle/test_battle.c index c2731b43..4f00f972 100644 --- a/test/rpg/battle/test_battle.c +++ b/test/rpg/battle/test_battle.c @@ -24,8 +24,7 @@ static const cutsceneitem_t CUTSCENE_TEST_SCRATCH_ITEMS[] = { static const cutscene_t CUTSCENE_TEST_SCRATCH = { .items = CUTSCENE_TEST_SCRATCH_ITEMS, .itemCount = sizeof(CUTSCENE_TEST_SCRATCH_ITEMS) / sizeof(cutsceneitem_t), - .pause = CUTSCENE_PAUSE_NONE, - .dataSize = 0 + .pause = CUTSCENE_PAUSE_NONE }; static battlefighter_t *addFighter( diff --git a/test/rpg/cutscene/test_cutscenesystem.c b/test/rpg/cutscene/test_cutscenesystem.c index 2e6def8b..f5a46c64 100644 --- a/test/rpg/cutscene/test_cutscenesystem.c +++ b/test/rpg/cutscene/test_cutscenesystem.c @@ -20,11 +20,11 @@ static void recordCallback(void *userData) { // the "nested cutscene is a one-way jump" behavior: cutsceneCutsceneStart // replaces CUTSCENE_SYSTEM.scene outright, and the callback item's effect // fires in Start, not Update, so it fires the same frame the jump happens. -CUTSCENE(TEST_INNER, 0, NONE, +CUTSCENE(TEST_INNER, NONE, CUTSCENE_CALLBACK(recordCallback) ); -CUTSCENE(TEST_OUTER, 0, DEFAULT, +CUTSCENE(TEST_OUTER, DEFAULT, CUTSCENE_WAIT(0.5f), CUTSCENE_CUTSCENE(TEST_INNER) ); @@ -75,7 +75,7 @@ static void test_cutsceneSystemUpdateIsNoopWithNoActiveCutscene(void **state) { assert_null(CUTSCENE_SYSTEM.scene); } -CUTSCENE(TEST_SINGLE_WAIT, 0, NONE, +CUTSCENE(TEST_SINGLE_WAIT, NONE, CUTSCENE_WAIT(1.0f) ); @@ -188,13 +188,13 @@ static void recordOrder2(void *userData) { insertOrderLog[insertOrderLogCount++] static void recordOrderA(void *userData) { insertOrderLog[insertOrderLogCount++] = 3; } static void recordOrderB(void *userData) { insertOrderLog[insertOrderLogCount++] = 4; } -CUTSCENE(TEST_INSERT_SNIPPET, 0, NONE, +CUTSCENE(TEST_INSERT_SNIPPET, NONE, CUTSCENE_CALLBACK(recordOrderA), CUTSCENE_WAIT(2.0f), CUTSCENE_CALLBACK(recordOrderB) ); -CUTSCENE(TEST_INSERT_OUTER, 0, NONE, +CUTSCENE(TEST_INSERT_OUTER, NONE, CUTSCENE_CALLBACK(recordOrder0), CUTSCENE_WAIT(1.0f), CUTSCENE_CALLBACK(recordOrder1), @@ -230,11 +230,11 @@ static void test_cutsceneInsertSplicesItemsInPlaceThenResumes(void **state) { assert_memory_equal(insertOrderLog, expected, sizeof(expected)); } -CUTSCENE(TEST_INSERT_AS_LAST_ITEM_SNIPPET, 0, NONE, +CUTSCENE(TEST_INSERT_AS_LAST_ITEM_SNIPPET, NONE, CUTSCENE_CALLBACK(recordOrderA) ); -CUTSCENE(TEST_INSERT_AS_LAST_ITEM_OUTER, 0, NONE, +CUTSCENE(TEST_INSERT_AS_LAST_ITEM_OUTER, NONE, CUTSCENE_CALLBACK(recordOrder0), CUTSCENE_INSERT(TEST_INSERT_AS_LAST_ITEM_SNIPPET) ); @@ -263,19 +263,19 @@ static void test_cutsceneInsertAsLastItemEndsCutsceneNaturally( assert_memory_equal(insertOrderLog, expected, sizeof(expected)); } -CUTSCENE(TEST_INSERT_NESTED_INNER, 0, NONE, +CUTSCENE(TEST_INSERT_NESTED_INNER, NONE, CUTSCENE_CALLBACK(recordOrderA) ); // INSERT is MID's first item, so entering MID (from OUTER) cascades // straight through into INNER within the same Start chain, one level // deeper than a single insert. -CUTSCENE(TEST_INSERT_NESTED_MID, 0, NONE, +CUTSCENE(TEST_INSERT_NESTED_MID, NONE, CUTSCENE_INSERT(TEST_INSERT_NESTED_INNER), CUTSCENE_CALLBACK(recordOrderB) ); -CUTSCENE(TEST_INSERT_NESTED_OUTER, 0, NONE, +CUTSCENE(TEST_INSERT_NESTED_OUTER, NONE, CUTSCENE_CALLBACK(recordOrder0), CUTSCENE_INSERT(TEST_INSERT_NESTED_MID), CUTSCENE_CALLBACK(recordOrder2) @@ -306,22 +306,22 @@ static void test_cutsceneInsertNestsThroughMultipleLevels(void **state) { assert_memory_equal(insertOrderLog, expected, sizeof(expected)); } -CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL5, 0, NONE, +CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL5, NONE, CUTSCENE_CALLBACK(recordOrderA) ); -CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL4, 0, NONE, +CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL4, NONE, CUTSCENE_INSERT(TEST_INSERT_OVERFLOW_LEVEL5) ); -CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL3, 0, NONE, +CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL3, NONE, CUTSCENE_INSERT(TEST_INSERT_OVERFLOW_LEVEL4) ); -CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL2, 0, NONE, +CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL2, NONE, CUTSCENE_INSERT(TEST_INSERT_OVERFLOW_LEVEL3) ); -CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL1, 0, NONE, +CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL1, NONE, CUTSCENE_INSERT(TEST_INSERT_OVERFLOW_LEVEL2) ); -CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL0, 0, NONE, +CUTSCENE(TEST_INSERT_OVERFLOW_LEVEL0, NONE, CUTSCENE_INSERT(TEST_INSERT_OVERFLOW_LEVEL1) ); @@ -341,11 +341,11 @@ static void test_cutsceneInsertAssertsWhenNestingExceedsStackMax( static void noopInsertCallback(void *userData) {} -CUTSCENE(TEST_INSERT_PERSIST_SNIPPET, 0, ALL, +CUTSCENE(TEST_INSERT_PERSIST_SNIPPET, ALL, CUTSCENE_CALLBACK(noopInsertCallback) ); -CUTSCENE(TEST_INSERT_PERSIST_OUTER, 0, NPC, +CUTSCENE(TEST_INSERT_PERSIST_OUTER, NPC, CUTSCENE_INSERT(TEST_INSERT_PERSIST_SNIPPET) ); diff --git a/test/rpg/entity/test_entityinteract.c b/test/rpg/entity/test_entityinteract.c index 2e8f1dd3..85ed9e5f 100644 --- a/test/rpg/entity/test_entityinteract.c +++ b/test/rpg/entity/test_entityinteract.c @@ -17,8 +17,7 @@ static const cutsceneitem_t CUTSCENE_TEST_INTERACT_ITEMS[] = { static const cutscene_t CUTSCENE_TEST_INTERACT = { .items = CUTSCENE_TEST_INTERACT_ITEMS, .itemCount = 1, - .pause = CUTSCENE_PAUSE_NONE, - .dataSize = 0 + .pause = CUTSCENE_PAUSE_NONE }; static entity_t *player;