Skip to content

Commit 7dbbdc4

Browse files
authored
fix potentially wrong texture loading order (#20)
* add gsl library to track memory allocations * rework creation to respect mod order slight slowdown but just to be safe * 1.6.1 * print info on timing * specify largeaddressaware (shouldn't matter since gw is linked with it, but can't hurt)
1 parent 9e593e8 commit 7dbbdc4

File tree

5 files changed

+64
-31
lines changed

5 files changed

+64
-31
lines changed

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ endif()
1717

1818
set(VERSION_MAJOR 1)
1919
set(VERSION_MINOR 6)
20-
set(VERSION_PATCH 0)
20+
set(VERSION_PATCH 1)
2121
set(VERSION_TWEAK 0)
2222

2323
set(VERSION_RC "${CMAKE_CURRENT_BINARY_DIR}/version.rc")
@@ -35,6 +35,7 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
3535
include(libzippp)
3636
include(minhook)
3737
include(dxtk)
38+
include(msgsl)
3839

3940
add_library(gMod SHARED)
4041

@@ -58,9 +59,11 @@ target_link_libraries(gMod PRIVATE
5859
psapi
5960
minhook
6061
directxtex
62+
Microsoft.GSL::GSL
6163
)
6264
target_link_options(gMod PRIVATE
6365
"$<$<CONFIG:DEBUG>:/NODEFAULTLIB:LIBCMT>"
66+
"/LARGEADDRESSAWARE"
6467
)
6568
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${SOURCES})
6669
target_sources(gMod PRIVATE ${SOURCES})

cmake/msgsl.cmake

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
cmake_minimum_required(VERSION 3.14)
2+
3+
include(FetchContent)
4+
5+
FetchContent_Declare(GSL
6+
GIT_REPOSITORY "https://github.com/microsoft/GSL"
7+
GIT_TAG "v4.0.0"
8+
GIT_SHALLOW ON
9+
)
10+
11+
FetchContent_MakeAvailable(GSL)

header/Defines.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,21 @@ inline void Message(const char* format, ...)
2626
#endif
2727
}
2828

29+
inline void Info(const char* format, ...)
30+
{
31+
#ifdef _DEBUG
32+
va_list args;
33+
va_start(args, format);
34+
vprintf(format, args);
35+
va_end(args);
36+
#endif
37+
}
38+
2939
inline void Warning(const char* format, ...)
3040
{
3141
#ifdef _DEBUG
42+
static HANDLE hConsole = GetStdHandle(STD_ERROR_HANDLE);
43+
[[maybe_unused]] static auto success = SetConsoleTextAttribute(hConsole, 6);
3244
va_list args;
3345
va_start(args, format);
3446
vfprintf(stderr, format, args);

header/Main.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "Utils.h"
1313

1414
#include <d3d9.h>
15+
#include <gsl/gsl>
1516

1617
#include "Defines.h"
1718
#include "Error.h"

modules/TextureClient.ixx

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ public:
2727
int MergeUpdate(); //called from uMod_IDirect3DDevice9::BeginScene()
2828
void Initialize();
2929

30-
// Add TextureFileStruct data, return size of data added. 0 on failure.
31-
unsigned long AddFile(TexEntry& entry, bool compress = false);
32-
3330
std::vector<uMod_IDirect3DTexture9*> OriginalTextures;
3431
// stores the pointer to the uMod_IDirect3DTexture9 objects created by the game
3532
std::vector<uMod_IDirect3DVolumeTexture9*> OriginalVolumeTextures;
@@ -53,9 +50,8 @@ private:
5350
int LockMutex();
5451
int UnlockMutex();
5552
HANDLE hMutex;
56-
std::mutex mutex;
5753

58-
std::unordered_map<HashType, TextureFileStruct*> modded_textures;
54+
std::unordered_map<HashType, gsl::owner<TextureFileStruct*>> modded_textures;
5955
// array which stores the file in memory and the hash of each texture to be modded
6056

6157
// called if a target texture is found
@@ -83,8 +79,8 @@ TextureClient::~TextureClient()
8379
if (hMutex != nullptr) {
8480
CloseHandle(hMutex);
8581
}
86-
for (const auto& it : modded_textures) {
87-
delete it.second;
82+
for (const auto texture_file_struct : modded_textures | std::views::values) {
83+
delete texture_file_struct;
8884
}
8985
modded_textures.clear();
9086
}
@@ -159,47 +155,44 @@ int TextureClient::UnlockMutex()
159155
return RETURN_OK;
160156
}
161157

162-
unsigned long TextureClient::AddFile(TexEntry& entry, const bool compress)
158+
gsl::owner<TextureFileStruct*> AddFile(TexEntry& entry, const bool compress, const std::filesystem::path& dll_path)
163159
{
164-
if (modded_textures.contains(entry.crc_hash)) {
165-
return 0;
166-
}
167-
auto texture_file_struct = new TextureFileStruct();
160+
const auto texture_file_struct = new TextureFileStruct();
168161
texture_file_struct->crc_hash = entry.crc_hash;
169-
should_update = true;
170162
const auto dds_blob = TextureFunction::ConvertToCompressedDDS(entry, compress, dll_path);
171163
texture_file_struct->data.assign(static_cast<BYTE*>(dds_blob.GetBufferPointer()), static_cast<BYTE*>(dds_blob.GetBufferPointer()) + dds_blob.GetBufferSize());
172-
std::lock_guard lock(mutex);
173-
modded_textures.emplace(entry.crc_hash, texture_file_struct);
174-
return texture_file_struct->data.size();
164+
return texture_file_struct;
175165
}
176166

177-
unsigned ProcessModfile(TextureClient& client, const std::string& modfile, const bool compress)
167+
std::vector<gsl::owner<TextureFileStruct*>> ProcessModfile(const std::string& modfile, const std::filesystem::path& dll_path, const bool compress)
178168
{
179169
const auto hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
180-
if (FAILED(hr)) return 0;
170+
if (FAILED(hr)) return {};
181171
Message("Initialize: loading file %s... ", modfile.c_str());
182172
auto file_loader = ModfileLoader(modfile);
183173
auto entries = file_loader.GetContents();
184174
if (entries.empty()) {
185175
Message("No entries found.\n");
186-
return 0;
176+
return {};
187177
}
188178
Message("%zu textures... ", entries.size());
189-
unsigned long file_bytes_loaded = 0;
179+
std::vector<gsl::owner<TextureFileStruct*>> texture_file_structs;
180+
texture_file_structs.reserve(entries.size());
181+
unsigned file_bytes_loaded = 0;
190182
for (auto& tpf_entry : entries) {
191-
file_bytes_loaded += client.AddFile(tpf_entry, compress);
183+
const auto tex_file_struct = AddFile(tpf_entry, compress, dll_path);
184+
texture_file_structs.push_back(tex_file_struct);
185+
file_bytes_loaded += texture_file_structs.back()->data.size();
192186
}
193187
entries.clear();
194188
Message("%d bytes loaded.\n", file_bytes_loaded);
195189
CoUninitialize();
196-
return file_bytes_loaded;
190+
return texture_file_structs;
197191
}
198192

199193
void TextureClient::LoadModsFromFile(const char* source)
200194
{
201195
static std::vector<std::string> loaded_modfiles{};
202-
static unsigned long loaded_size = 0;
203196
Message("Initialize: searching in %s\n", source);
204197

205198
std::ifstream file(source);
@@ -226,20 +219,32 @@ void TextureClient::LoadModsFromFile(const char* source)
226219
files_size += std::filesystem::file_size(modfile);
227220
}
228221
}
229-
std::vector<std::future<unsigned>> futures;
222+
std::vector<std::future<std::vector<gsl::owner<TextureFileStruct*>>>> futures;
230223
for (const auto modfile : modfiles) {
231-
futures.emplace_back(std::async(std::launch::async, ProcessModfile, std::ref(*this), modfile, files_size > 400'000'000));
224+
futures.emplace_back(std::async(std::launch::async, ProcessModfile, modfile, dll_path, files_size > 400'000'000));
232225
}
233-
// Join all threads
226+
auto loaded_size = 0u;
234227
for (auto& future : futures) {
235-
loaded_size += future.get();
228+
const auto texture_file_structs = future.get();
229+
for (const auto texture_file_struct : texture_file_structs) {
230+
if (!texture_file_struct->crc_hash) continue;
231+
if (!modded_textures.contains(texture_file_struct->crc_hash)) {
232+
modded_textures.emplace(texture_file_struct->crc_hash, texture_file_struct);
233+
loaded_size += texture_file_struct->data.size();
234+
}
235+
else {
236+
delete texture_file_struct;
237+
}
238+
}
239+
should_update = true;
236240
}
237241
Message("Finished loading mods from %s: Loaded %u bytes (%u mb)", source, loaded_size, loaded_size / 1024 / 1024);
238242
}
239243

240244
void TextureClient::Initialize()
241245
{
242-
Message("Initialize: begin\n");
246+
const auto t1 = std::chrono::high_resolution_clock::now();
247+
Info("Initialize: begin\n");
243248
Message("Initialize: searching for modlist.txt\n");
244249
char gwpath[MAX_PATH]{};
245250
GetModuleFileName(GetModuleHandle(nullptr), gwpath, MAX_PATH); //ask for name and path of this executable
@@ -254,8 +259,9 @@ void TextureClient::Initialize()
254259
LoadModsFromFile(modlist.string().c_str());
255260
}
256261
}
257-
258-
Message("Initialize: end\n");
262+
const auto t2 = std::chrono::high_resolution_clock::now();
263+
const auto ms = duration_cast<std::chrono::milliseconds>(t2 - t1);
264+
Info("Initialize: end, took %d ms\n", ms);
259265
}
260266

261267
int TextureClient::AddTexture(uModTexturePtr auto pTexture)

0 commit comments

Comments
 (0)