mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-12-12 03:02:30 +00:00
feat(build): add StormLib (#4)
* feat(app): add StormLib * feat(app): add OpenArchives * feat(util): update SFile to work with StormLib * feat(app): update SFile * feat(util): update SFile with logging (Windows only) * feat(ui): implemented termination w/o notice * chore(build): update StormLib * chore(util): replace std::string with SStr* functions * fix(stormlib): dwFlags argument for SFileOpenPatchArchive * chore(ui): add Script_* stubs * chore(util): clean up SFile::OpenEx * chore(build): update StormLib --------- Co-authored-by: Phaneron <superp00t@tutanota.com>
This commit is contained in:
parent
c5e0034604
commit
f86f6d6d09
323 changed files with 73232 additions and 75 deletions
|
|
@ -15,6 +15,7 @@
|
|||
#include "ui/FrameScript.hpp"
|
||||
#include "ui/FrameXML.hpp"
|
||||
#include "world/World.hpp"
|
||||
#include "util/Filesystem.hpp"
|
||||
#include <bc/Debug.hpp>
|
||||
#include <common/Prop.hpp>
|
||||
#include <storm/Error.hpp>
|
||||
|
|
@ -174,6 +175,8 @@ int32_t InitializeGlobal() {
|
|||
|
||||
// ClientServices::LoadCDKey();
|
||||
|
||||
OpenArchives();
|
||||
|
||||
SetPaths();
|
||||
|
||||
ConsoleInitializeClientCommand();
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ struct lua_State;
|
|||
#define NUM_SCRIPT_FUNCTIONS_GLUE_SCRIPT_EVENTS 113
|
||||
#define NUM_SCRIPT_FUNCTIONS_REALM_LIST 14
|
||||
#define NUM_SCRIPT_FUNCTIONS_SIMPLE_FRAME 7
|
||||
#define NUM_SCRIPT_FUNCTIONS_SYSTEM 7
|
||||
#define NUM_SCRIPT_FUNCTIONS_SYSTEM 13
|
||||
|
||||
namespace FrameScript {
|
||||
extern FrameScript_Method s_ScriptFunctions_CharCreate[NUM_SCRIPT_FUNCTIONS_CHAR_CREATE];
|
||||
|
|
@ -210,5 +210,6 @@ int32_t Script_GetTime(lua_State*);
|
|||
int32_t Script_GetGameTime(lua_State*);
|
||||
int32_t Script_ConsoleExec(lua_State*);
|
||||
int32_t Script_AccessDenied(lua_State*);
|
||||
int32_t Script_GetCurrentResolution(lua_State*);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -154,7 +154,9 @@ int32_t Script_ShowTerminationWithoutNoticeNotice(lua_State* L) {
|
|||
}
|
||||
|
||||
int32_t Script_TerminationWithoutNoticeAccepted(lua_State* L) {
|
||||
WHOA_UNIMPLEMENTED(0);
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
//WHOA_UNIMPLEMENTED(0);
|
||||
}
|
||||
|
||||
int32_t Script_AcceptTerminationWithoutNotice(lua_State* L) {
|
||||
|
|
|
|||
|
|
@ -24,12 +24,42 @@ int32_t Script_AccessDenied(lua_State* L) {
|
|||
return luaL_error(L, "Access Denied");
|
||||
}
|
||||
|
||||
int32_t Script_GetCurrentResolution(lua_State* L) {
|
||||
WHOA_UNIMPLEMENTED(0);
|
||||
}
|
||||
|
||||
int32_t Script_GetScreenResolutions(lua_State* L) {
|
||||
WHOA_UNIMPLEMENTED(0);
|
||||
}
|
||||
|
||||
int32_t Script_GetRefreshRates(lua_State* L) {
|
||||
WHOA_UNIMPLEMENTED(0);
|
||||
}
|
||||
|
||||
int32_t Script_GetCurrentMultisampleFormat(lua_State* L) {
|
||||
WHOA_UNIMPLEMENTED(0);
|
||||
}
|
||||
|
||||
int32_t Script_GetMultisampleFormats(lua_State* L) {
|
||||
WHOA_UNIMPLEMENTED(0);
|
||||
}
|
||||
|
||||
int32_t Script_IsStereoVideoAvailable(lua_State* L) {
|
||||
WHOA_UNIMPLEMENTED(0);
|
||||
}
|
||||
|
||||
FrameScript_Method FrameScript::s_ScriptFunctions_System[NUM_SCRIPT_FUNCTIONS_SYSTEM] = {
|
||||
{ "GetTime", &Script_GetTime },
|
||||
{ "GetGameTime", &Script_GetGameTime },
|
||||
{ "ConsoleExec", &Script_ConsoleExec },
|
||||
{ "ReadFile", &Script_AccessDenied },
|
||||
{ "DeleteFile", &Script_AccessDenied },
|
||||
{ "AppendToFile", &Script_AccessDenied },
|
||||
{ "GetAccountExpansionLevel", &Script_GetAccountExpansionLevel }
|
||||
{ "GetTime", &Script_GetTime },
|
||||
{ "GetGameTime", &Script_GetGameTime },
|
||||
{ "ConsoleExec", &Script_ConsoleExec },
|
||||
{ "ReadFile", &Script_AccessDenied },
|
||||
{ "DeleteFile", &Script_AccessDenied },
|
||||
{ "AppendToFile", &Script_AccessDenied },
|
||||
{ "GetAccountExpansionLevel", &Script_GetAccountExpansionLevel },
|
||||
{ "GetCurrentResolution", &Script_GetCurrentResolution },
|
||||
{ "GetScreenResolutions", &Script_GetScreenResolutions },
|
||||
{ "GetRefreshRates", &Script_GetRefreshRates },
|
||||
{ "GetCurrentMultisampleFormat", &Script_GetCurrentMultisampleFormat },
|
||||
{ "GetMultisampleFormats", &Script_GetMultisampleFormats },
|
||||
{ "IsStereoVideoAvailable", &Script_IsStereoVideoAvailable },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ target_link_libraries(util
|
|||
PUBLIC
|
||||
freetype-2.0
|
||||
lua-5.1
|
||||
stormlib-9
|
||||
bc
|
||||
common
|
||||
storm
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
#include "util/Filesystem.hpp"
|
||||
#include <cstring>
|
||||
#include <sys/stat.h>
|
||||
#include <storm/String.hpp>
|
||||
#include <StormLib.h>
|
||||
|
||||
void* g_mpqHandle = nullptr;
|
||||
|
||||
void OsBuildFontFilePath(const char* fileName, char* buffer, size_t size) {
|
||||
SStrPrintf(buffer, size, "%s\\%s", "Fonts", fileName);
|
||||
|
|
@ -24,3 +28,134 @@ char* OsPathFindExtensionWithDot(char* pathName) {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
void OsFileToNativeSlashes(char* path, size_t size) {
|
||||
#ifdef WHOA_SYSTEM_WIN
|
||||
OsFileToBackSlashes(path, size);
|
||||
#else
|
||||
OsFileToForwardSlashes(path, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OsFileToForwardSlashes(char* path, size_t size) {
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
if (!path[i])
|
||||
return;
|
||||
|
||||
if (path[i] == '\\')
|
||||
path[i] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
void OsFileToBackSlashes(char* path, size_t size) {
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
if (!path[i])
|
||||
return;
|
||||
|
||||
if (path[i] == '/')
|
||||
path[i] = '\\';
|
||||
}
|
||||
}
|
||||
|
||||
void OpenExtraArchives(const char* basePath, const char* language, const char* fileNamePrefix) {
|
||||
char path[STORM_MAX_PATH] = { 0 };
|
||||
|
||||
for (unsigned int i = 1; i < 20; ++i) {
|
||||
if (language) {
|
||||
if (i > 1) {
|
||||
SStrPrintf(path, sizeof(path), "%s/%s-%s-%u.MPQ", basePath, fileNamePrefix, language, i);
|
||||
} else {
|
||||
SStrPrintf(path, sizeof(path), "%s/%s-%s.MPQ", basePath, fileNamePrefix, language);
|
||||
}
|
||||
} else {
|
||||
if (i > 1) {
|
||||
SStrPrintf(path, sizeof(path), "%s/%s-%u.MPQ", basePath, fileNamePrefix, i);
|
||||
} else {
|
||||
SStrPrintf(path, sizeof(path), "%s/%s.MPQ", basePath, fileNamePrefix);
|
||||
}
|
||||
}
|
||||
|
||||
OsFileToNativeSlashes(path);
|
||||
if (!SFileOpenPatchArchive(g_mpqHandle, path, nullptr, MPQ_OPEN_NO_LISTFILE))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenArchives()
|
||||
{
|
||||
struct stat info = { 0 };
|
||||
|
||||
const char* languages[] = {
|
||||
"enUS", "enGB", "enTW", "zhTW", "esES",
|
||||
"ruRU", "koKR", "ptPT", "esMX", "itIT",
|
||||
"deDE", "frFR", "enCN", "zhCN", "ptBR"
|
||||
};
|
||||
|
||||
const char* baseFiles[] = {
|
||||
"common.MPQ",
|
||||
"common-2.MPQ",
|
||||
"expansion.MPQ",
|
||||
"lichking.MPQ"
|
||||
};
|
||||
|
||||
const char* extraFiles[] = {
|
||||
"locale",
|
||||
"speech",
|
||||
"expansion-locale",
|
||||
"lichking-locale",
|
||||
"expansion-speech",
|
||||
"lichking-speech",
|
||||
"patch"
|
||||
};
|
||||
|
||||
char path[STORM_MAX_PATH] = { 0 };
|
||||
|
||||
SStrCopy(path, "Data", sizeof(path));
|
||||
if (stat(path, &info) != 0 || (info.st_mode & S_IFDIR) == 0)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < sizeof(baseFiles) / sizeof(baseFiles[0]); ++i) {
|
||||
SStrCopy(path, "Data/", sizeof(path));
|
||||
SStrPack(path, baseFiles[i], sizeof(path));
|
||||
OsFileToNativeSlashes(path);
|
||||
|
||||
if (i == 0) {
|
||||
if (!SFileOpenArchive(path, 0, MPQ_OPEN_NO_LISTFILE, &g_mpqHandle))
|
||||
return;
|
||||
} else if (!SFileOpenPatchArchive(g_mpqHandle, path, nullptr, MPQ_OPEN_NO_LISTFILE)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const char* language = nullptr;
|
||||
for (size_t i = 0; i < sizeof(languages) / sizeof(languages[0]); ++i) {
|
||||
SStrCopy(path, "Data/", sizeof(path));
|
||||
SStrPack(path, languages[i], sizeof(path));
|
||||
OsFileToNativeSlashes(path);
|
||||
|
||||
if (stat(path, &info) == 0 && (info.st_mode & S_IFDIR) != 0) {
|
||||
language = languages[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (language) {
|
||||
SStrCopy(path, "Data/", sizeof(path));
|
||||
SStrPack(path, language, sizeof(path));
|
||||
|
||||
for (size_t i = 0; i < sizeof(extraFiles) / sizeof(extraFiles[0]); ++i)
|
||||
OpenExtraArchives(path, language, extraFiles[i]);
|
||||
|
||||
// Special case
|
||||
OpenExtraArchives(path, nullptr, "patch");
|
||||
}
|
||||
|
||||
SStrCopy(path, "Data", sizeof(path));
|
||||
OpenExtraArchives(path, nullptr, "patch");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,4 +8,12 @@ void OsBuildFontFilePath(const char*, char*, size_t);
|
|||
|
||||
char* OsPathFindExtensionWithDot(char*);
|
||||
|
||||
void OsFileToNativeSlashes(char* path, size_t size = (size_t) -1);
|
||||
void OsFileToForwardSlashes(char* path, size_t size = (size_t) -1);
|
||||
void OsFileToBackSlashes(char* path, size_t size = (size_t) -1);
|
||||
|
||||
void OpenArchives();
|
||||
|
||||
extern void* g_mpqHandle;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,27 +1,31 @@
|
|||
#include "util/SFile.hpp"
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <StormLib.h>
|
||||
#include <storm/Memory.hpp>
|
||||
#include <storm/String.hpp>
|
||||
#include <bc/file/File.hpp>
|
||||
#include "util/Filesystem.hpp"
|
||||
|
||||
static char s_basepath[STORM_MAX_PATH] = {0};
|
||||
static char s_datapath[STORM_MAX_PATH] = {0};
|
||||
|
||||
// TODO Proper implementation
|
||||
int32_t SFile::Close(SFile* file) {
|
||||
delete file->m_filename;
|
||||
|
||||
Blizzard::File::Close(file->m_stream);
|
||||
|
||||
SFileCloseFile(file->m_handle);
|
||||
delete file;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO Proper implementation
|
||||
size_t SFile::GetFileSize(SFile* file, size_t* filesizeHigh) {
|
||||
return file->m_size;
|
||||
uint32_t SFile::GetFileSize(SFile* file, uint32_t* filesizeHigh) {
|
||||
DWORD high = 0;
|
||||
DWORD low = SFileGetFileSize(file->m_handle, &high);
|
||||
|
||||
if (filesizeHigh) {
|
||||
*filesizeHigh = high;
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
int32_t SFile::IsStreamingMode() {
|
||||
|
|
@ -31,39 +35,47 @@ int32_t SFile::IsStreamingMode() {
|
|||
|
||||
// TODO Proper implementation
|
||||
int32_t SFile::Load(SArchive* archive, const char* filename, void** buffer, size_t* bytes, size_t extraBytes, uint32_t flags, SOVERLAPPED* overlapped) {
|
||||
auto pathLen = SStrLen(filename);
|
||||
char path[STORM_MAX_PATH];
|
||||
SStrCopy(path, filename, sizeof(path));
|
||||
|
||||
uint32_t openflags = BC_FILE_OPEN_MUST_EXIST | BC_FILE_OPEN_SHARE_READ | BC_FILE_OPEN_READ;
|
||||
Blizzard::File::StreamRecord* stream;
|
||||
bool opened = Blizzard::File::Open(path, openflags, stream);
|
||||
size_t size;
|
||||
char* data;
|
||||
|
||||
if (opened) {
|
||||
size = static_cast<size_t>(Blizzard::File::GetFileInfo(stream)->size);
|
||||
|
||||
if (bytes) {
|
||||
*bytes = size;
|
||||
}
|
||||
|
||||
data = new char[size + extraBytes];
|
||||
|
||||
Blizzard::File::SetPos(stream, 0, BC_FILE_SEEK_START);
|
||||
Blizzard::File::Read(stream, data, size, nullptr);
|
||||
Blizzard::File::Close(stream);
|
||||
|
||||
if (extraBytes) {
|
||||
memset(data + size, 0, extraBytes);
|
||||
}
|
||||
|
||||
*buffer = data;
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
if (!buffer || !filename) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*buffer = nullptr;
|
||||
if (bytes) {
|
||||
*bytes = 0;
|
||||
}
|
||||
|
||||
SFile* file = nullptr;
|
||||
if (!SFile::OpenEx(nullptr, filename, 0, &file)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t high = 0;
|
||||
uint64_t size = SFile::GetFileSize(file, &high);
|
||||
size |= ((uint64_t) high << 32);
|
||||
|
||||
auto data = reinterpret_cast<char*>(SMemAlloc(size + extraBytes, __FILE__, __LINE__, 0));
|
||||
|
||||
if (!SFile::Read(file, data, size, nullptr, nullptr, nullptr)) {
|
||||
SMemFree(data, __FILE__, __LINE__, 0);
|
||||
SFile::Close(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (extraBytes) {
|
||||
memset(data + size, 0, extraBytes);
|
||||
}
|
||||
|
||||
if (bytes) {
|
||||
*bytes = size;
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
*buffer = data;
|
||||
}
|
||||
|
||||
SFile::Close(file);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t SFile::Open(const char* filename, SFile** file) {
|
||||
|
|
@ -72,38 +84,48 @@ int32_t SFile::Open(const char* filename, SFile** file) {
|
|||
|
||||
// TODO Proper implementation
|
||||
int32_t SFile::OpenEx(SArchive* archive, const char* filename, uint32_t flags, SFile** file) {
|
||||
auto pathLen = SStrLen(filename);
|
||||
char path[STORM_MAX_PATH];
|
||||
SStrCopy(path, filename, sizeof(path));
|
||||
|
||||
SFile* fileptr = new SFile;
|
||||
|
||||
fileptr->m_filename = strdup(filename);
|
||||
|
||||
uint32_t openflags = BC_FILE_OPEN_MUST_EXIST | BC_FILE_OPEN_SHARE_READ | BC_FILE_OPEN_READ;
|
||||
|
||||
Blizzard::File::StreamRecord* stream;
|
||||
auto opened = Blizzard::File::Open(fileptr->m_filename, openflags, stream);
|
||||
if (!opened) {
|
||||
*file = nullptr;
|
||||
if (!file || !filename) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto fileinfo = Blizzard::File::GetFileInfo(stream);
|
||||
char path[STORM_MAX_PATH];
|
||||
|
||||
fileptr->m_stream = stream;
|
||||
fileptr->m_size = fileinfo->size;
|
||||
// Overflow protection
|
||||
if (SStrLen(filename) + 1 > STORM_MAX_PATH) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*file = fileptr;
|
||||
SStrCopy(path, filename, STORM_MAX_PATH);
|
||||
OsFileToNativeSlashes(path);
|
||||
|
||||
HANDLE handle;
|
||||
if (!SFileOpenFileEx(nullptr, path, SFILE_OPEN_LOCAL_FILE, &handle)) {
|
||||
OsFileToBackSlashes(path);
|
||||
if (!SFileOpenFileEx(g_mpqHandle, path, SFILE_OPEN_FROM_MPQ, &handle)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
*file = new SFile;
|
||||
(*file)->m_handle = handle;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO Proper implementation
|
||||
int32_t SFile::Read(SFile* file, void* buffer, size_t bytestoread, size_t* bytesread, SOVERLAPPED* overlapped, TASYNCPARAMBLOCK* asyncparam) {
|
||||
Blizzard::File::Read(file->m_stream, buffer, bytestoread, bytesread);
|
||||
|
||||
return 1;
|
||||
DWORD read = 0;
|
||||
if (SFileReadFile(file->m_handle, buffer, static_cast<DWORD>(bytestoread), &read, nullptr)) {
|
||||
if (bytesread) {
|
||||
*bytesread = read;
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
if (bytesread) {
|
||||
*bytesread = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t SFile::Unload(void* ptr) {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
class SArchive;
|
||||
struct SOVERLAPPED;
|
||||
|
|
@ -20,7 +18,7 @@ class SFile {
|
|||
public:
|
||||
// Static functions
|
||||
static int32_t Close(SFile*);
|
||||
static size_t GetFileSize(SFile*, size_t*);
|
||||
static uint32_t GetFileSize(SFile*, uint32_t*);
|
||||
static int32_t IsStreamingMode(void);
|
||||
static int32_t Load(SArchive*, const char*, void**, size_t*, size_t, uint32_t, SOVERLAPPED*);
|
||||
static int32_t Open(const char*, SFile**);
|
||||
|
|
@ -33,9 +31,7 @@ class SFile {
|
|||
static int32_t GetDataPath(char* path, size_t capacity);
|
||||
|
||||
// Member variables
|
||||
const char* m_filename;
|
||||
Blizzard::File::StreamRecord* m_stream; // TODO Proper implementation
|
||||
uint64_t m_size; // TODO Proper implementation
|
||||
void* m_handle;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue