From 828aca2c8e770cb05a3ca459006578519226cb7c Mon Sep 17 00:00:00 2001 From: Misa Date: Wed, 30 Mar 2022 13:09:15 -0700 Subject: [PATCH] Load zips using real dir instead of filename This fixes a limitation where the level filename had to be the exact same name as the name of the zip, because the game used the name of the level to identify the zip of which to load assets, and this also made it impossible to use assets for more than one level in a zip. Instead, we just look up where the level came from, so we can always load its assets regardless of its filename. Additionally, the zip structure checks can go away too, simplifying the code further. --- desktop_version/src/FileSystemUtils.cpp | 176 ++---------------------- 1 file changed, 14 insertions(+), 162 deletions(-) diff --git a/desktop_version/src/FileSystemUtils.cpp b/desktop_version/src/FileSystemUtils.cpp index 88f39d57..ea87ef89 100644 --- a/desktop_version/src/FileSystemUtils.cpp +++ b/desktop_version/src/FileSystemUtils.cpp @@ -352,157 +352,10 @@ static bool FILESYSTEM_mountAssetsFrom(const char *fname) return true; } -struct ArchiveState -{ - const char* filename; - bool has_extension; - bool other_level_files; -}; - -static PHYSFS_EnumerateCallbackResult zipCheckCallback( - void* data, - const char* origdir, - const char* filename -) { - struct ArchiveState* state = (struct ArchiveState*) data; - const bool has_extension = endsWith(filename, ".vvvvvv"); - UNUSED(origdir); - - if (!state->has_extension) - { - state->has_extension = has_extension; - } - if (!state->other_level_files && has_extension) - { - state->other_level_files = SDL_strcmp( - state->filename, - filename - ) != 0; - } - - if (state->has_extension && state->other_level_files) - { - /* We don't need to check any more files. */ - return PHYSFS_ENUM_STOP; - } - return PHYSFS_ENUM_OK; -} - -/* For technical reasons, the level file inside a zip named LEVELNAME.zip must - * be named LEVELNAME.vvvvvv, else its custom assets won't work; - * if there are .vvvvvv files other than LEVELNAME.vvvvvv, they would be loaded - * too but they won't load any assets - * - * For user-friendliness, we check this upfront and reject all zips that don't - * conform to this (regardless of them containing assets or not) - otherwise a - * level zip with assets can be played but its assets mysteriously won't work - */ -static bool checkZipStructure(const char* filename) -{ - const char* real_dir = PHYSFS_getRealDir(filename); - char base_name[MAX_PATH]; - char base_name_suffixed[MAX_PATH]; - char real_path[MAX_PATH]; - char mount_path[MAX_PATH]; - char check_path[MAX_PATH]; - char random_str[6 + 1]; - bool success; - bool file_exists; - struct ArchiveState zip_state; - - if (real_dir == NULL) - { - vlog_error( - "Could not check %s: real directory doesn't exist", - filename - ); - return false; - } - - SDL_snprintf(real_path, sizeof(real_path), "%s/%s", real_dir, filename); - - generateBase36(random_str, sizeof(random_str)); - SDL_snprintf(mount_path, sizeof(mount_path), ".vvv-mnt-temp-%s/", random_str); - - if (!PHYSFS_mount(real_path, mount_path, 1)) - { - vlog_error( - "Error mounting and checking %s: %s", - filename, - PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()) - ); - return false; - } - - VVV_between(filename, "levels/", base_name, ".zip"); - - SDL_snprintf( - base_name_suffixed, - sizeof(base_name_suffixed), - "%s.vvvvvv", - base_name - ); - - SDL_snprintf( - check_path, - sizeof(check_path), - "%s%s", - mount_path, - base_name_suffixed - ); - - file_exists = PHYSFS_exists(check_path); - success = file_exists; - - SDL_zero(zip_state); - zip_state.filename = base_name_suffixed; - - PHYSFS_enumerate(mount_path, zipCheckCallback, (void*) &zip_state); - - /* If no .vvvvvv files in zip, don't print warning. */ - if (!success && zip_state.has_extension) - { - setLevelDirError( - "%s.zip is not structured correctly! It is missing %s.vvvvvv.", - base_name, - base_name - ); - } - - success &= !zip_state.other_level_files; - - /* ...But if other .vvvvvv file(s), do print warning. */ - /* This message is redundant if the correct file already DOESN'T exist. */ - if (file_exists && zip_state.other_level_files) - { - setLevelDirError( - "%s.zip is not structured correctly! It has .vvvvvv file(s) other than %s.vvvvvv.", - base_name, - base_name - ); - } - - if (!PHYSFS_unmount(real_path)) - { - vlog_error( - "Could not unmount %s: %s", - mount_path, - PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()) - ); - } - - return success; -} - void FILESYSTEM_loadZip(const char* filename) { PHYSFS_File* zip = PHYSFS_openRead(filename); - if (!checkZipStructure(filename)) - { - return; - } - if (!PHYSFS_mountHandle(zip, filename, "levels", 1)) { vlog_error( @@ -517,23 +370,16 @@ void FILESYSTEM_unmountAssets(void); bool FILESYSTEM_mountAssets(const char* path) { - char filename[MAX_PATH]; - char virtual_path[MAX_PATH]; + const char* real_dir = PHYSFS_getRealDir(path); - VVV_between(path, "levels/", filename, ".vvvvvv"); - - SDL_snprintf( - virtual_path, - sizeof(virtual_path), - "levels/%s.zip", - filename - ); - if (FILESYSTEM_exists(virtual_path)) + if (real_dir != NULL && + SDL_strncmp(real_dir, "levels/", sizeof("levels/") - 1) == 0 && + endsWith(real_dir, ".zip")) { - /* This is a full zipped-up level including assets */ - vlog_info("Asset directory is .zip at %s", virtual_path); + /* This is a level zip */ + vlog_info("Asset directory is .zip at %s", real_dir); - if (!FILESYSTEM_mountAssetsFrom(virtual_path)) + if (!FILESYSTEM_mountAssetsFrom(real_dir)) { return false; } @@ -542,13 +388,19 @@ bool FILESYSTEM_mountAssets(const char* path) } else { - /* If it's not a level, look for a level folder */ + /* If it's not a zip, look for a level folder */ + char filename[MAX_PATH]; + char virtual_path[MAX_PATH]; + + VVV_between(path, "levels/", filename, ".vvvvvv"); + SDL_snprintf( virtual_path, sizeof(virtual_path), "levels/%s/", filename ); + if (FILESYSTEM_exists(virtual_path)) { vlog_info("Asset directory exists at %s", virtual_path);