new method of pack loading, assume data or data.btw in root to point to all other

This commit is contained in:
veclav talica 2024-10-07 12:28:15 +03:00
parent 7bec9f6de6
commit bbf79ad442
5 changed files with 139 additions and 20 deletions

View File

@ -0,0 +1,3 @@
[[deps]]
source = "../../common-data" # where does it come from, might be an url
name = "common-data" # should be globally unique

11
apps/lua/data/twn.toml Normal file
View File

@ -0,0 +1,11 @@
[about]
title = "Lua Townengine!"
developer = "Somebody"
app_id = "twnlua"
dev_id = "somebody"
[game]
base_render_width = 640
base_render_height = 360
[engine]

15
docs/packaging.txt Normal file
View File

@ -0,0 +1,15 @@
assets are distributed by packs, which can come in archived or folder form (for development purposes)
one pack by the name of 'data' is always assumed to be present alongside game executable root,
whether in folder /data/ or /data.btw file, where precedence is taking over /data/
root 'data' should be used to point to other dependency packs in /packs/data.toml file
---
[[deps]]
source = "../../common-data" # where does it come from, might be an url
name = "common-data" # should be globally unique
---
they're mounted to / in the virtual file system by default, if same files are present in multiple packs,
only the one loaded first is visible

View File

@ -188,6 +188,96 @@ static void main_loop(void) {
} }
/* TODO: cache and deny duplicates */
/* TODO: ability to redefine mounting point for a dependency */
/* TODO: ability to load external sources over HTTP if url is given */
static void resolve_pack_dependencies(const char *pack_name) {
char *path;
if (SDL_asprintf(&path, "/packs/%s.toml", pack_name) == -1) {
CRY("resolve_pack_dependencies()", "Allocation error");
goto ERR_PACK_MANIFEST_PATH_ALLOC_FAIL;
}
if (!PHYSFS_exists(path))
/* no package manifest provided, abort */
goto OK_NO_MANIFEST;
char *manifest_file = file_to_str(path);
if (!manifest_file) {
CRY_PHYSFS("Pack manifest file loading failed");
goto ERR_PACK_MANIFEST_FILE_LOADING;
}
char errbuf[256]; /* tomlc99 example implies that this is enough... */
toml_table_t *manifest = toml_parse(manifest_file, errbuf, sizeof errbuf);
SDL_free(manifest_file);
if (!manifest) {
CRY("Pack manifest decoding failed", errbuf);
goto ERR_PACK_MANIFEST_DECODING;
}
toml_array_t *deps = toml_array_in(manifest, "deps");
if (!deps)
goto OK_NO_DEPS;
/* iterate over entries in [[deps]] array */
/* TODO: use sub procedures for failable loops? so that error mechanism cleans well */
toml_table_t *cur_dep = toml_table_at(deps, 0);
for (int idx = 0; cur_dep; ++idx, cur_dep = toml_table_at(deps, idx)) {
toml_datum_t dep_name = toml_string_in(cur_dep, "name");
if (!dep_name.ok) {
log_warn("No 'name' is present in pack dependency, skipping it");
continue;
}
char *dep_pack_name;
if (SDL_asprintf(&dep_pack_name, "%s.btw", dep_name.u.s) == -1) {
CRY("resolve_pack_dependencies()", "Allocation error");
SDL_free(dep_name.u.s);
goto ERR_DEP_PATH_ALLOC_FAIL;
}
/* try loading pack */
if (!PHYSFS_mount(dep_pack_name, "/", true)) {
/* if it failes, try going for source */
toml_datum_t dep_source = toml_string_in(cur_dep, "source");
if (!dep_source.ok) {
log_warn("No 'source' is present in pack %s, while %s.btw isn't present, skipping it", dep_name.u.s, dep_name.u.s);
SDL_free(dep_name.u.s);
SDL_free(dep_pack_name);
continue;
}
if (!PHYSFS_mount(dep_source.u.s, "/", true))
CRY("Cannot load pack", "Nothing is given to work with");
log_info("Pack loaded: %s\n", dep_source.u.s);
SDL_free(dep_source.u.s);
} else
log_info("Pack loaded: %s\n", dep_pack_name);
SDL_free(dep_pack_name);
/* recursive resolution */
resolve_pack_dependencies(dep_name.u.s);
SDL_free(dep_name.u.s);
}
ERR_DEP_PATH_ALLOC_FAIL:
OK_NO_DEPS:
toml_free(manifest);
ERR_PACK_MANIFEST_DECODING:
ERR_PACK_MANIFEST_FILE_LOADING:
OK_NO_MANIFEST:
SDL_free(path);
ERR_PACK_MANIFEST_PATH_ALLOC_FAIL:
return;
}
static bool initialize(void) { static bool initialize(void) {
if (SDL_Init(SDL_INIT_EVERYTHING & ~SDL_INIT_HAPTIC) == -1) { if (SDL_Init(SDL_INIT_EVERYTHING & ~SDL_INIT_HAPTIC) == -1) {
CRY_SDL("SDL initialization failed."); CRY_SDL("SDL initialization failed.");
@ -199,6 +289,9 @@ static bool initialize(void) {
/* that is why PhysicsFS is initialized before anything else */ /* that is why PhysicsFS is initialized before anything else */
toml_set_memutil(SDL_malloc, SDL_free); toml_set_memutil(SDL_malloc, SDL_free);
/* time to orderly resolve any dependencies present */
resolve_pack_dependencies("data");
/* load the config file into an opaque table */ /* load the config file into an opaque table */
{ {
char *config_file = file_to_str("/twn.toml"); char *config_file = file_to_str("/twn.toml");
@ -562,33 +655,16 @@ int enter_loop(int argc, char **argv) {
/* needs to be done before anything else so config can be loaded */ /* needs to be done before anything else so config can be loaded */
/* TODO: ANDROID: see the warning in physicsfs PHYSFS_init docs/header */ /* TODO: ANDROID: see the warning in physicsfs PHYSFS_init docs/header */
if (!PHYSFS_init(ctx.argv[0]) || !PHYSFS_mount(PHYSFS_getBaseDir(), NULL, true)) { if (!PHYSFS_init(ctx.argv[0])) {
CRY_PHYSFS("Filesystem initialization failed"); CRY_PHYSFS("Filesystem initialization failed");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* base dir is fine, but we'd like to look into all the data archives, too */
char **files_here = PHYSFS_enumerateFiles("/");
if (files_here == NULL) {
CRY_PHYSFS("Filesystem initialization failed");
return EXIT_FAILURE;
}
for (char **ptr = files_here; *ptr != NULL; ++ptr) {
char *file = *ptr;
if (!strends(file, "." PACKAGE_EXTENSION)) {
continue;
}
if (!PHYSFS_mount(file, "/", true)) {
CRY_PHYSFS("Filesystem initialization failed");
return EXIT_FAILURE;
}
}
PHYSFS_freeList(files_here);
/* process arguments */ /* process arguments */
bool force_debug = false; bool force_debug = false;
bool force_release = false; bool force_release = false;
bool data_dir_mounted = false;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
/* override data directory */ /* override data directory */
if (SDL_strcmp(argv[i], "--data-dir") == 0) { if (SDL_strcmp(argv[i], "--data-dir") == 0) {
@ -602,6 +678,8 @@ int enter_loop(int argc, char **argv) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
data_dir_mounted = true;
continue; continue;
} }
@ -618,6 +696,16 @@ int enter_loop(int argc, char **argv) {
} }
} }
/* data path not explicitly specified, look into convention defined places */
if (!data_dir_mounted) {
/* try mouning data folder first, relative to executable root */
if (!PHYSFS_mount("data", NULL, true)) {
if (!PHYSFS_mount("data.btw", NULL, true))
CRY_PHYSFS("Cannot find data.btw or data directory in root. Please create them or specify with --data-dir parameter.");
return EXIT_FAILURE;
}
}
if (!initialize()) if (!initialize())
return EXIT_FAILURE; return EXIT_FAILURE;

View File

@ -191,6 +191,8 @@ void textures_dump_atlases(void) {
SDL_SaveBMP_RW(ctx.texture_cache.atlas_surfaces[i], handle, true); SDL_SaveBMP_RW(ctx.texture_cache.atlas_surfaces[i], handle, true);
log_info("Dumped atlas %zu to %s", i, buf); log_info("Dumped atlas %zu to %s", i, buf);
SDL_free(buf);
} }
} }