ab2b778f44
build / build (push) Successful in 3m36s
Extends the MDL system beyond text overrides: bitmaps/<label>.json names a model/scale and resource list, and mdlp extracts each resource's frames, runs them through an ONNX Runtime CPU upscaler baked into mdlp-image, re-quantizes to the game's palette, and writes the result back - same build-time pipeline as message overrides. Adds animgallery, a standalone viewer that renders any data directory's animated resources as an HTML/GIF gallery with a checkbox-driven MDL JSON generator, and -only-changed to preview just what a mod overrides against the base game. Fixes a real data race in hacked's ChangeNotifier.hashAll() (found via go build -race causing non-deterministic resource counts), via a new numbered patch rather than editing the vendored source. Adds engine-patches/, a general-fixes counterpart to android/engine-patches/ now staged and applied to the desktop builds too (previously unpatched): a real GL_UNPACK_ROW_LENGTH stride bug, an audio error-logging improvement, and two critter-rendering fixes - mod art was losing to the base game's own re-opened resource files, and critters rendered at the wrong size/position once that was fixed, both from how the billboard renderer derives on-screen size and placement straight from bitmap pixel dimensions. Updates README.md and AGENTS.md to document engine-patches/.
99 lines
3.9 KiB
Diff
99 lines
3.9 KiB
Diff
--- a/src/MacSrc/Modding.c 2026-07-19 13:11:51.000000000 +0200
|
|
+++ b/src/MacSrc/Modding.c 2026-09-27 19:44:24.718059783 +0200
|
|
@@ -27,6 +27,11 @@
|
|
char *modding_additional_files[MAX_MOD_FILES];
|
|
int num_mod_files;
|
|
|
|
+// One filenum per modding_additional_files[] entry, or -1 if not open yet -
|
|
+// lets LoadModFiles() close a mod file's previous handle before reopening it
|
|
+// (see LoadModFiles() below for why it needs to be called more than once).
|
|
+static int32_t modding_loaded_filenum[MAX_MOD_FILES];
|
|
+
|
|
int StringEndsWith(char *src, char *dst) {
|
|
char *s = strrchr(src, '.');
|
|
|
|
@@ -86,6 +91,7 @@
|
|
modding_archive_override = NULL;
|
|
for (int i = 0; i < MAX_MOD_FILES; i++) {
|
|
modding_additional_files[i] = NULL;
|
|
+ modding_loaded_filenum[i] = -1;
|
|
}
|
|
|
|
// Now go process args
|
|
@@ -135,10 +141,24 @@
|
|
}
|
|
|
|
int LoadModFiles() {
|
|
+ // Called again by obj_set_secondary_properties() (objsim.c) after it
|
|
+ // re-opens the base game's own object art files, which would otherwise
|
|
+ // silently reclaim any resource ID a mod file already overrode here (see
|
|
+ // ResReadDirEntries() in resfile.c - opening a file re-registers every
|
|
+ // resource ID it contains, last one in wins, with no check for whether
|
|
+ // an ID is already claimed). Re-registering means actually re-opening
|
|
+ // (there is no "just re-register" primitive), so a mod file already open
|
|
+ // from an earlier call is closed first - one open handle per mod file at
|
|
+ // a time, rather than leaking a fresh resFile[] slot on every repeat call
|
|
+ // (new game, load game - object_data_load() can run more than once per
|
|
+ // process).
|
|
for (int i = 0; i < num_mod_files; i++) {
|
|
if (modding_additional_files[i] != NULL) {
|
|
+ if (modding_loaded_filenum[i] >= 0) {
|
|
+ ResCloseFile(modding_loaded_filenum[i]);
|
|
+ }
|
|
printf("Loading mod file %s\n", modding_additional_files[i]);
|
|
- ResOpenFile(modding_additional_files[i]);
|
|
+ modding_loaded_filenum[i] = ResOpenFile(modding_additional_files[i]);
|
|
}
|
|
}
|
|
|
|
--- a/src/GameSrc/objsim.c 2026-07-19 13:11:51.000000000 +0200
|
|
+++ b/src/GameSrc/objsim.c 2026-09-27 19:44:17.014441306 +0200
|
|
@@ -43,6 +43,7 @@
|
|
#include "gettmaps.h"
|
|
#include "lvldata.h"
|
|
#include "mapflags.h"
|
|
+#include "Modding.h"
|
|
#include "objart2.h"
|
|
#include "objart3.h"
|
|
#include "objects.h"
|
|
@@ -1877,6 +1878,13 @@
|
|
// Warning(("Problem opening object art cache!\n"));
|
|
return (ERR_NOEFFECT);
|
|
}
|
|
+ // The two opens above re-register every resource ID objart2.res/
|
|
+ // objart3.res contain, reclaiming any of them a mod file already
|
|
+ // overrode (see LoadModFiles() in Modding.c) - restore mod priority
|
|
+ // for the reftable reads below. load_dynamic_memory() (cybmem.c) reopens
|
|
+ // these same two files again later, persistently, for actual rendering -
|
|
+ // restoring priority there too.
|
|
+ LoadModFiles();
|
|
|
|
// Now go and set specific computed data, like frame counts
|
|
for (i = 0; i < NUM_CRITTER; i++) {
|
|
--- a/src/GameSrc/cybmem.c 2026-07-19 13:11:51.000000000 +0200
|
|
+++ b/src/GameSrc/cybmem.c 2026-09-27 19:44:24.718059783 +0200
|
|
@@ -33,6 +33,7 @@
|
|
#include "textmaps.h"
|
|
#include "objcrit.h"
|
|
#include "dynmem.h"
|
|
+#include "Modding.h"
|
|
#include "Shock.h"
|
|
#include "sideicon.h"
|
|
#include "criterr.h"
|
|
@@ -120,6 +121,15 @@
|
|
critical_error(CRITERR_RES | 8);
|
|
}
|
|
|
|
+ // The four opens above re-register every resource ID their files
|
|
+ // contain, reclaiming any of them a mod file already overrode (see
|
|
+ // LoadModFiles() in Modding.c) - these are the persistent handles
|
|
+ // actual gameplay renders from (unlike obj_set_secondary_properties()'s
|
|
+ // own transient open/close of objart2.res/objart3.res for reading
|
|
+ // frame-count metadata), so this is the last point mod priority needs
|
|
+ // restoring before rendering.
|
|
+ LoadModFiles();
|
|
+
|
|
loadcount |= mask;
|
|
}
|
|
|