Load MPQ file overrides without StormLib
Also logs the overrides in verbose mode.
This commit is contained in:
parent
5d53910127
commit
a97ffd1640
7 changed files with 57 additions and 64 deletions
|
|
@ -904,7 +904,6 @@ void DiabloInit()
|
|||
init_create_window();
|
||||
was_window_init = true;
|
||||
|
||||
SFileEnableDirectAccess(true);
|
||||
init_archives();
|
||||
was_archives_init = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ HANDLE LoadMPQ(const std::vector<std::string> &paths, const char *mpqName)
|
|||
mpqAbsPath = path + mpqName;
|
||||
if (SFileOpenArchive(mpqAbsPath.c_str(), 0, MPQ_OPEN_READ_ONLY, &archive)) {
|
||||
LogVerbose(" Found: {} in {}", mpqName, path);
|
||||
SFileSetBasePath(path);
|
||||
paths::SetMpqDir(path);
|
||||
return archive;
|
||||
}
|
||||
if (SErrGetLastError() != STORM_ERROR_FILE_NOT_FOUND) {
|
||||
|
|
|
|||
|
|
@ -30,9 +30,6 @@ extern "C" std::uint32_t GetLastError();
|
|||
namespace devilution {
|
||||
namespace {
|
||||
|
||||
bool directFileAccess = false;
|
||||
std::optional<std::string> SBasePath;
|
||||
|
||||
SdlMutex Mutex;
|
||||
|
||||
} // namespace
|
||||
|
|
@ -49,46 +46,10 @@ bool SFileCloseFileThreadSafe(HANDLE hFile)
|
|||
return SFileCloseFile(hFile);
|
||||
}
|
||||
|
||||
// Converts ASCII characters to lowercase
|
||||
// Converts slash (0x2F) / backslash (0x5C) to system file-separator
|
||||
unsigned char AsciiToLowerTable_Path[256] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
#ifdef _WIN32
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x5C,
|
||||
#else
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
#endif
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
#ifdef _WIN32
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
#else
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x2F, 0x5D, 0x5E, 0x5F,
|
||||
#endif
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
|
||||
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};
|
||||
|
||||
bool SFileOpenFile(const char *filename, HANDLE *phFile)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (directFileAccess && SBasePath) {
|
||||
std::string path = *SBasePath + filename;
|
||||
for (std::size_t i = SBasePath->size(); i < path.size(); ++i)
|
||||
path[i] = AsciiToLowerTable_Path[static_cast<unsigned char>(path[i])];
|
||||
result = SFileOpenFileEx((HANDLE) nullptr, path.c_str(), SFILE_OPEN_LOCAL_FILE, phFile);
|
||||
}
|
||||
|
||||
if (!result && font_mpq != nullptr) {
|
||||
result = SFileOpenFileEx((HANDLE)font_mpq, filename, SFILE_OPEN_FROM_MPQ, phFile);
|
||||
}
|
||||
|
|
@ -138,17 +99,6 @@ void SErrSetLastError(uint32_t dwErrCode)
|
|||
::SetLastError(dwErrCode);
|
||||
}
|
||||
|
||||
void SFileSetBasePath(string_view path)
|
||||
{
|
||||
SBasePath.emplace(path);
|
||||
}
|
||||
|
||||
bool SFileEnableDirectAccess(bool enable)
|
||||
{
|
||||
directFileAccess = enable;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
bool SFileOpenArchive(const char *szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE *phMpq)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -249,14 +249,12 @@ void SErrSetLastError(uint32_t dwErrCode);
|
|||
*/
|
||||
void SStrCopy(char *dest, const char *src, int max_length);
|
||||
|
||||
void SFileSetBasePath(string_view path);
|
||||
bool SNetGetOwnerTurnsWaiting(uint32_t *);
|
||||
bool SNetUnregisterEventHandler(event_type);
|
||||
bool SNetRegisterEventHandler(event_type, SEVTHANDLER);
|
||||
bool SNetSetBasePlayer(int);
|
||||
bool SNetInitializeProvider(uint32_t provider, struct GameData *gameData);
|
||||
void SNetGetProviderCaps(struct _SNETCAPS *);
|
||||
bool SFileEnableDirectAccess(bool enable);
|
||||
|
||||
#if defined(__GNUC__) || defined(__cplusplus)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "engine.h"
|
||||
#include "storm/storm.h"
|
||||
#include "utils/file_util.h"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/paths.h"
|
||||
|
||||
|
|
@ -100,24 +101,61 @@ SDL_RWops *SFileRw_FromStormHandle(HANDLE handle)
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
constexpr char PathSeparator = '\\';
|
||||
#else
|
||||
constexpr char PathSeparator = '/';
|
||||
#endif
|
||||
|
||||
// Converts ASCII characters to lowercase
|
||||
// Converts slash / backslash to system file-separator
|
||||
const char LowerCaseAsciiPathTable[256] {
|
||||
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F',
|
||||
'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', '\x1E', '\x1F',
|
||||
'\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', '\x28', '\x29', '\x2A', '\x2B', '\x2C', '\x2D', '\x2E', PathSeparator,
|
||||
'\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', '\x38', '\x39', '\x3A', '\x3B', '\x3C', '\x3D', '\x3E', '\x3F',
|
||||
'\x40', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', '\x69', '\x6A', '\x6B', '\x6C', '\x6D', '\x6E', '\x6F',
|
||||
'\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', '\x78', '\x79', '\x7A', '\x5B', PathSeparator, '\x5D', '\x5E', '\x5F',
|
||||
'\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', '\x69', '\x6A', '\x6B', '\x6C', '\x6D', '\x6E', '\x6F',
|
||||
'\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', '\x78', '\x79', '\x7A', '\x7B', '\x7C', '\x7D', '\x7E', '\x7F',
|
||||
'\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', '\x88', '\x89', '\x8A', '\x8B', '\x8C', '\x8D', '\x8E', '\x8F',
|
||||
'\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', '\x98', '\x99', '\x9A', '\x9B', '\x9C', '\x9D', '\x9E', '\x9F',
|
||||
'\xA0', '\xA1', '\xA2', '\xA3', '\xA4', '\xA5', '\xA6', '\xA7', '\xA8', '\xA9', '\xAA', '\xAB', '\xAC', '\xAD', '\xAE', '\xAF',
|
||||
'\xB0', '\xB1', '\xB2', '\xB3', '\xB4', '\xB5', '\xB6', '\xB7', '\xB8', '\xB9', '\xBA', '\xBB', '\xBC', '\xBD', '\xBE', '\xBF',
|
||||
'\xC0', '\xC1', '\xC2', '\xC3', '\xC4', '\xC5', '\xC6', '\xC7', '\xC8', '\xC9', '\xCA', '\xCB', '\xCC', '\xCD', '\xCE', '\xCF',
|
||||
'\xD0', '\xD1', '\xD2', '\xD3', '\xD4', '\xD5', '\xD6', '\xD7', '\xD8', '\xD9', '\xDA', '\xDB', '\xDC', '\xDD', '\xDE', '\xDF',
|
||||
'\xE0', '\xE1', '\xE2', '\xE3', '\xE4', '\xE5', '\xE6', '\xE7', '\xE8', '\xE9', '\xEA', '\xEB', '\xEC', '\xED', '\xEE', '\xEF',
|
||||
'\xF0', '\xF1', '\xF2', '\xF3', '\xF4', '\xF5', '\xF6', '\xF7', '\xF8', '\xF9', '\xFA', '\xFB', '\xFC', '\xFD', '\xFE', '\xFF'
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
SDL_RWops *SFileOpenRw(const char *filename)
|
||||
{
|
||||
std::string relativePath = filename;
|
||||
for (char &c : relativePath)
|
||||
c = LowerCaseAsciiPathTable[static_cast<unsigned char>(c)];
|
||||
|
||||
if (relativePath[0] == '/')
|
||||
return SDL_RWFromFile(relativePath.c_str(), "rb");
|
||||
|
||||
// Files next to the MPQ archives override MPQ contents.
|
||||
SDL_RWops *rwops;
|
||||
if (paths::MpqDir()) {
|
||||
const std::string path = *paths::MpqDir() + relativePath;
|
||||
// Avoid spamming DEBUG messages if the file does not exist.
|
||||
if ((FileExists(path.c_str())) && (rwops = SDL_RWFromFile(path.c_str(), "rb")) != nullptr) {
|
||||
LogVerbose("Loaded MPQ file override: {}", path);
|
||||
return rwops;
|
||||
}
|
||||
}
|
||||
|
||||
// Load from all the MPQ archives.
|
||||
HANDLE handle;
|
||||
if (SFileOpenFile(filename, &handle))
|
||||
return SFileRw_FromStormHandle(handle);
|
||||
|
||||
std::string relativePath = filename;
|
||||
#ifndef _WIN32
|
||||
std::replace(relativePath.begin(), relativePath.end(), '\\', '/');
|
||||
#endif
|
||||
|
||||
SDL_RWops *rwops;
|
||||
if (relativePath[0] == '/') {
|
||||
return SDL_RWFromFile(relativePath.c_str(), "rb");
|
||||
}
|
||||
|
||||
// Load from the `/assets` directory next to the devilutionx binary.
|
||||
const std::string path = paths::AssetsPath() + relativePath;
|
||||
if ((rwops = SDL_RWFromFile(path.c_str(), "rb")) != nullptr)
|
||||
return rwops;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include "utils/file_util.h"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/stdcompat/optional.hpp"
|
||||
#include "utils/sdl_ptrs.h"
|
||||
|
||||
#ifdef USE_SDL1
|
||||
|
|
@ -22,6 +21,7 @@ std::optional<std::string> basePath;
|
|||
std::optional<std::string> prefPath;
|
||||
std::optional<std::string> configPath;
|
||||
std::optional<std::string> assetsPath;
|
||||
std::optional<std::string> mpqDir;
|
||||
|
||||
void AddTrailingSlash(std::string &path)
|
||||
{
|
||||
|
|
@ -92,6 +92,11 @@ const std::string &AssetsPath()
|
|||
return *assetsPath;
|
||||
}
|
||||
|
||||
const std::optional<std::string> &MpqDir()
|
||||
{
|
||||
return mpqDir;
|
||||
}
|
||||
|
||||
void SetBasePath(const std::string &path)
|
||||
{
|
||||
basePath = path;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "utils/stdcompat/optional.hpp"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
namespace paths {
|
||||
|
|
@ -11,6 +13,7 @@ const std::string &BasePath();
|
|||
const std::string &PrefPath();
|
||||
const std::string &ConfigPath();
|
||||
const std::string &AssetsPath();
|
||||
const std::optional<std::string> &MpqDir();
|
||||
|
||||
void SetBasePath(const std::string &path);
|
||||
void SetPrefPath(const std::string &path);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue