Browse Source

Load MPQ file overrides without StormLib

Also logs the overrides in verbose mode.
pull/3238/head
Gleb Mazovetskiy 4 years ago
parent
commit
a97ffd1640
  1. 1
      Source/diablo.cpp
  2. 2
      Source/init.cpp
  3. 50
      Source/storm/storm.cpp
  4. 2
      Source/storm/storm.h
  5. 56
      Source/storm/storm_sdl_rw.cpp
  6. 7
      Source/utils/paths.cpp
  7. 3
      Source/utils/paths.h

1
Source/diablo.cpp

@ -904,7 +904,6 @@ void DiabloInit()
init_create_window(); init_create_window();
was_window_init = true; was_window_init = true;
SFileEnableDirectAccess(true);
init_archives(); init_archives();
was_archives_init = true; was_archives_init = true;

2
Source/init.cpp

@ -65,7 +65,7 @@ HANDLE LoadMPQ(const std::vector<std::string> &paths, const char *mpqName)
mpqAbsPath = path + mpqName; mpqAbsPath = path + mpqName;
if (SFileOpenArchive(mpqAbsPath.c_str(), 0, MPQ_OPEN_READ_ONLY, &archive)) { if (SFileOpenArchive(mpqAbsPath.c_str(), 0, MPQ_OPEN_READ_ONLY, &archive)) {
LogVerbose(" Found: {} in {}", mpqName, path); LogVerbose(" Found: {} in {}", mpqName, path);
SFileSetBasePath(path); paths::SetMpqDir(path);
return archive; return archive;
} }
if (SErrGetLastError() != STORM_ERROR_FILE_NOT_FOUND) { if (SErrGetLastError() != STORM_ERROR_FILE_NOT_FOUND) {

50
Source/storm/storm.cpp

@ -30,9 +30,6 @@ extern "C" std::uint32_t GetLastError();
namespace devilution { namespace devilution {
namespace { namespace {
bool directFileAccess = false;
std::optional<std::string> SBasePath;
SdlMutex Mutex; SdlMutex Mutex;
} // namespace } // namespace
@ -49,46 +46,10 @@ bool SFileCloseFileThreadSafe(HANDLE hFile)
return SFileCloseFile(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 SFileOpenFile(const char *filename, HANDLE *phFile)
{ {
bool result = false; 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) { if (!result && font_mpq != nullptr) {
result = SFileOpenFileEx((HANDLE)font_mpq, filename, SFILE_OPEN_FROM_MPQ, phFile); result = SFileOpenFileEx((HANDLE)font_mpq, filename, SFILE_OPEN_FROM_MPQ, phFile);
} }
@ -138,17 +99,6 @@ void SErrSetLastError(uint32_t dwErrCode)
::SetLastError(dwErrCode); ::SetLastError(dwErrCode);
} }
void SFileSetBasePath(string_view path)
{
SBasePath.emplace(path);
}
bool SFileEnableDirectAccess(bool enable)
{
directFileAccess = enable;
return true;
}
#if defined(_WIN64) || defined(_WIN32) #if defined(_WIN64) || defined(_WIN32)
bool SFileOpenArchive(const char *szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE *phMpq) bool SFileOpenArchive(const char *szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE *phMpq)
{ {

2
Source/storm/storm.h

@ -249,14 +249,12 @@ void SErrSetLastError(uint32_t dwErrCode);
*/ */
void SStrCopy(char *dest, const char *src, int max_length); void SStrCopy(char *dest, const char *src, int max_length);
void SFileSetBasePath(string_view path);
bool SNetGetOwnerTurnsWaiting(uint32_t *); bool SNetGetOwnerTurnsWaiting(uint32_t *);
bool SNetUnregisterEventHandler(event_type); bool SNetUnregisterEventHandler(event_type);
bool SNetRegisterEventHandler(event_type, SEVTHANDLER); bool SNetRegisterEventHandler(event_type, SEVTHANDLER);
bool SNetSetBasePlayer(int); bool SNetSetBasePlayer(int);
bool SNetInitializeProvider(uint32_t provider, struct GameData *gameData); bool SNetInitializeProvider(uint32_t provider, struct GameData *gameData);
void SNetGetProviderCaps(struct _SNETCAPS *); void SNetGetProviderCaps(struct _SNETCAPS *);
bool SFileEnableDirectAccess(bool enable);
#if defined(__GNUC__) || defined(__cplusplus) #if defined(__GNUC__) || defined(__cplusplus)
} }

56
Source/storm/storm_sdl_rw.cpp

@ -6,6 +6,7 @@
#include "engine.h" #include "engine.h"
#include "storm/storm.h" #include "storm/storm.h"
#include "utils/file_util.h"
#include "utils/log.hpp" #include "utils/log.hpp"
#include "utils/paths.h" #include "utils/paths.h"
@ -100,24 +101,61 @@ SDL_RWops *SFileRw_FromStormHandle(HANDLE handle)
return result; 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 } // namespace
SDL_RWops *SFileOpenRw(const char *filename) SDL_RWops *SFileOpenRw(const char *filename)
{ {
HANDLE handle;
if (SFileOpenFile(filename, &handle))
return SFileRw_FromStormHandle(handle);
std::string relativePath = filename; std::string relativePath = filename;
#ifndef _WIN32 for (char &c : relativePath)
std::replace(relativePath.begin(), relativePath.end(), '\\', '/'); c = LowerCaseAsciiPathTable[static_cast<unsigned char>(c)];
#endif
SDL_RWops *rwops; if (relativePath[0] == '/')
if (relativePath[0] == '/') {
return SDL_RWFromFile(relativePath.c_str(), "rb"); 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);
// Load from the `/assets` directory next to the devilutionx binary.
const std::string path = paths::AssetsPath() + relativePath; const std::string path = paths::AssetsPath() + relativePath;
if ((rwops = SDL_RWFromFile(path.c_str(), "rb")) != nullptr) if ((rwops = SDL_RWFromFile(path.c_str(), "rb")) != nullptr)
return rwops; return rwops;

7
Source/utils/paths.cpp

@ -4,7 +4,6 @@
#include "utils/file_util.h" #include "utils/file_util.h"
#include "utils/log.hpp" #include "utils/log.hpp"
#include "utils/stdcompat/optional.hpp"
#include "utils/sdl_ptrs.h" #include "utils/sdl_ptrs.h"
#ifdef USE_SDL1 #ifdef USE_SDL1
@ -22,6 +21,7 @@ std::optional<std::string> basePath;
std::optional<std::string> prefPath; std::optional<std::string> prefPath;
std::optional<std::string> configPath; std::optional<std::string> configPath;
std::optional<std::string> assetsPath; std::optional<std::string> assetsPath;
std::optional<std::string> mpqDir;
void AddTrailingSlash(std::string &path) void AddTrailingSlash(std::string &path)
{ {
@ -92,6 +92,11 @@ const std::string &AssetsPath()
return *assetsPath; return *assetsPath;
} }
const std::optional<std::string> &MpqDir()
{
return mpqDir;
}
void SetBasePath(const std::string &path) void SetBasePath(const std::string &path)
{ {
basePath = path; basePath = path;

3
Source/utils/paths.h

@ -2,6 +2,8 @@
#include <string> #include <string>
#include "utils/stdcompat/optional.hpp"
namespace devilution { namespace devilution {
namespace paths { namespace paths {
@ -11,6 +13,7 @@ const std::string &BasePath();
const std::string &PrefPath(); const std::string &PrefPath();
const std::string &ConfigPath(); const std::string &ConfigPath();
const std::string &AssetsPath(); const std::string &AssetsPath();
const std::optional<std::string> &MpqDir();
void SetBasePath(const std::string &path); void SetBasePath(const std::string &path);
void SetPrefPath(const std::string &path); void SetPrefPath(const std::string &path);

Loading…
Cancel
Save