From 7d91bc461ad91d5a6e4d641322037fcd1949083b Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Sat, 23 Oct 2021 09:15:59 +0100 Subject: [PATCH] Improve asset file opening Avoid wrapping asset files via StormLib, open them directly via SDL instead. --- Source/init.cpp | 1 - Source/storm/storm.cpp | 22 ---------------------- Source/storm/storm.h | 1 - Source/storm/storm_sdl_rw.cpp | 24 ++++++++++++++++++------ Source/utils/paths.cpp | 13 +++++++++++++ Source/utils/paths.h | 2 ++ test/pack_test.cpp | 10 ---------- 7 files changed, 33 insertions(+), 40 deletions(-) diff --git a/Source/init.cpp b/Source/init.cpp index 7e44d1261..4221955d1 100644 --- a/Source/init.cpp +++ b/Source/init.cpp @@ -174,7 +174,6 @@ void init_archives() // Load devilutionx.mpq first to get the font file for error messages devilutionx_mpq = LoadMPQ(paths, "devilutionx.mpq"); font_mpq = LoadMPQ(paths, "fonts.mpq"); // Extra fonts - SFileSetAssetsPath(paths::AppPath() + "assets/"); if (strcasecmp("en", sgOptions.Language.szCode) != 0 || strlen(sgOptions.Language.szCode) != 2) { char langMpqName[9] = {}; diff --git a/Source/storm/storm.cpp b/Source/storm/storm.cpp index 4ffc9af79..64a1be1c4 100644 --- a/Source/storm/storm.cpp +++ b/Source/storm/storm.cpp @@ -32,7 +32,6 @@ namespace { bool directFileAccess = false; std::optional SBasePath; -std::optional AssetsPath; SdlMutex Mutex; @@ -126,22 +125,6 @@ bool SFileOpenFile(const char *filename, HANDLE *phFile) result = SFileOpenFileEx((HANDLE)diabdat_mpq, filename, SFILE_OPEN_FROM_MPQ, phFile); } - // As last fallback always search app content folder - if (!result && AssetsPath) { - std::string path = *AssetsPath + filename; - for (std::size_t i = AssetsPath->size(); i < path.size(); ++i) - path[i] = AsciiToLowerTable_Path[static_cast(path[i])]; - result = SFileOpenFileEx((HANDLE) nullptr, path.c_str(), SFILE_OPEN_LOCAL_FILE, phFile); - } - - if (!result || (*phFile == nullptr)) { - const auto error = SErrGetLastError(); - if (error == STORM_ERROR_FILE_NOT_FOUND) { - LogVerbose("{}(\"{}\") File not found", __FUNCTION__, filename); - } else { - LogError("{}(\"{}\") Failed with error code {}", __FUNCTION__, filename, error); - } - } return result; } @@ -160,11 +143,6 @@ void SFileSetBasePath(string_view path) SBasePath.emplace(path); } -void SFileSetAssetsPath(string_view path) -{ - AssetsPath.emplace(path); -} - bool SFileEnableDirectAccess(bool enable) { directFileAccess = enable; diff --git a/Source/storm/storm.h b/Source/storm/storm.h index 927c746d4..cd7bf4cfa 100644 --- a/Source/storm/storm.h +++ b/Source/storm/storm.h @@ -250,7 +250,6 @@ void SErrSetLastError(uint32_t dwErrCode); void SStrCopy(char *dest, const char *src, int max_length); void SFileSetBasePath(string_view path); -void SFileSetAssetsPath(string_view path); bool SNetGetOwnerTurnsWaiting(uint32_t *); bool SNetUnregisterEventHandler(event_type); bool SNetRegisterEventHandler(event_type, SEVTHANDLER); diff --git a/Source/storm/storm_sdl_rw.cpp b/Source/storm/storm_sdl_rw.cpp index 779210a6e..f8ff5a25e 100644 --- a/Source/storm/storm_sdl_rw.cpp +++ b/Source/storm/storm_sdl_rw.cpp @@ -1,11 +1,13 @@ #include "storm/storm_sdl_rw.h" +#include #include #include #include "engine.h" #include "storm/storm.h" #include "utils/log.hpp" +#include "utils/paths.h" namespace devilution { @@ -106,14 +108,24 @@ SDL_RWops *SFileOpenRw(const char *filename) if (SFileOpenFile(filename, &handle)) return SFileRw_FromStormHandle(handle); -#ifdef __ANDROID__ std::string relativePath = filename; - for (std::size_t i = 0; i < relativePath.size(); ++i) { - if (relativePath[i] == '\\') - relativePath[i] = '/'; +#ifndef _WIN32 + std::replace(relativePath.begin(), relativePath.end(), '\\', '/'); +#endif + + SDL_RWops *rwops; + if (relativePath[0] == '/') { + return SDL_RWFromFile(relativePath.c_str(), "rb"); } - SDL_RWops *rwops = SDL_RWFromFile(relativePath.c_str(), "rb"); - if (rwops != nullptr) + + const std::string path = paths::AssetsPath() + relativePath; + if ((rwops = SDL_RWFromFile(path.c_str(), "rb")) != nullptr) + return rwops; + +#ifdef __ANDROID__ + // On Android, fall back to the APK's assets. + // This is handled by SDL when we pass a relative path. + if (!paths::AssetsPath().empty() && (rwops = SDL_RWFromFile(relativePath.c_str(), "rb"))) return rwops; #endif diff --git a/Source/utils/paths.cpp b/Source/utils/paths.cpp index 9874ee5bf..d41fc5a5e 100644 --- a/Source/utils/paths.cpp +++ b/Source/utils/paths.cpp @@ -21,6 +21,7 @@ std::optional appPath; std::optional basePath; std::optional prefPath; std::optional configPath; +std::optional assetsPath; void AddTrailingSlash(std::string &path) { @@ -84,6 +85,13 @@ const std::string &ConfigPath() return *configPath; } +const std::string &AssetsPath() +{ + if (!assetsPath) + assetsPath.emplace(AppPath() + "assets/"); + return *assetsPath; +} + void SetBasePath(const std::string &path) { basePath = path; @@ -102,6 +110,11 @@ void SetConfigPath(const std::string &path) AddTrailingSlash(*configPath); } +void SetMpqDir(const std::string &path) +{ + mpqDir = std::string(path); +} + } // namespace paths } // namespace devilution diff --git a/Source/utils/paths.h b/Source/utils/paths.h index 071096fc8..e43450e32 100644 --- a/Source/utils/paths.h +++ b/Source/utils/paths.h @@ -10,10 +10,12 @@ const std::string &AppPath(); const std::string &BasePath(); const std::string &PrefPath(); const std::string &ConfigPath(); +const std::string &AssetsPath(); void SetBasePath(const std::string &path); void SetPrefPath(const std::string &path); void SetConfigPath(const std::string &path); +void SetMpqDir(const std::string &path); } // namespace paths diff --git a/test/pack_test.cpp b/test/pack_test.cpp index 38e4ac696..338d3d40e 100644 --- a/test/pack_test.cpp +++ b/test/pack_test.cpp @@ -333,8 +333,6 @@ TEST(pack, UnPackItem_diablo) Item id; ItemPack is; - SFileSetAssetsPath(devilution::paths::AppPath() + "assets/"); - gbIsHellfire = false; gbIsMultiplayer = false; gbIsSpawn = false; @@ -356,8 +354,6 @@ TEST(pack, UnPackItem_diablo_unique_bug) ItemPack pkItemBug = { 6, 911, 14, 5, 60, 60, 0, 0, 0, 0 }; // Veil of Steel - with morph bug ItemPack pkItem = { 6, 655, 14, 5, 60, 60, 0, 0, 0, 0 }; // Veil of Steel - fixed - SFileSetAssetsPath(devilution::paths::AppPath() + "assets/"); - gbIsHellfire = false; gbIsMultiplayer = false; gbIsSpawn = false; @@ -408,8 +404,6 @@ TEST(pack, UnPackItem_spawn) Item id; ItemPack is; - SFileSetAssetsPath(devilution::paths::AppPath() + "assets/"); - gbIsHellfire = false; gbIsMultiplayer = false; gbIsSpawn = true; @@ -454,8 +448,6 @@ TEST(pack, UnPackItem_diablo_multiplayer) Item id; ItemPack is; - SFileSetAssetsPath(devilution::paths::AppPath() + "assets/"); - gbIsHellfire = false; gbIsMultiplayer = true; gbIsSpawn = false; @@ -665,8 +657,6 @@ TEST(pack, UnPackItem_hellfire) Item id; ItemPack is; - SFileSetAssetsPath(devilution::paths::AppPath() + "assets/"); - gbIsHellfire = true; gbIsMultiplayer = false; gbIsSpawn = false;