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();
was_window_init = true;
SFileEnableDirectAccess(true);
init_archives();
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;
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) {

50
Source/storm/storm.cpp

@ -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)
{

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 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)
}

56
Source/storm/storm_sdl_rw.cpp

@ -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)
{
HANDLE handle;
if (SFileOpenFile(filename, &handle))
return SFileRw_FromStormHandle(handle);
std::string relativePath = filename;
#ifndef _WIN32
std::replace(relativePath.begin(), relativePath.end(), '\\', '/');
#endif
for (char &c : relativePath)
c = LowerCaseAsciiPathTable[static_cast<unsigned char>(c)];
SDL_RWops *rwops;
if (relativePath[0] == '/') {
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);
// 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;

7
Source/utils/paths.cpp

@ -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;

3
Source/utils/paths.h

@ -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…
Cancel
Save