- Fixed frequent crashes when using DX12, sometimes DX11 too.

- Fixed frequent crashing at game startup
- Fixed crashing when trying to use ".model" mods with the custom file loading system; PLEASE keep in mind that I haven't found a fix for this yet! Custom ".model" files will not get loaded by this mod's system
This commit is contained in:
EricPlayZ
2024-02-19 23:23:34 +02:00
parent d7774e56ec
commit 3239a9890f
5 changed files with 138 additions and 76 deletions

View File

@ -1,4 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommand>D:\Program Files (x86)\Steam\steamapps\common\Dying Light 2\ph\work\bin\x64\DyingLightGame_x64_rwdi.exe</LocalDebuggerCommand>
<LocalDebuggerWorkingDirectory>D:\Program Files (x86)\Steam\steamapps\common\Dying Light 2\ph\work\bin\x64</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommand>D:\Program Files (x86)\Steam\steamapps\common\Dying Light 2\ph\work\bin\x64\DyingLightGame_x64_rwdi.exe</LocalDebuggerCommand>
<LocalDebuggerWorkingDirectory>D:\Program Files (x86)\Steam\steamapps\common\Dying Light 2\ph\work\bin\x64</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

View File

@ -74,22 +74,32 @@ namespace impl {
init = true;
}
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
for (int retries = 0;; retries++) {
try {
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
Menu::FirstTimeRunning();
if (Menu::menuToggle.GetValue())
Menu::Render();
Menu::FirstTimeRunning();
if (Menu::menuToggle.GetValue())
Menu::Render();
ImGui::EndFrame();
ImGui::Render();
ImGui::EndFrame();
ImGui::Render();
if (d3d11RenderTargetView)
d3d11DeviceContext->OMSetRenderTargets(1, &d3d11RenderTargetView, nullptr);
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
if (d3d11RenderTargetView)
d3d11DeviceContext->OMSetRenderTargets(1, &d3d11RenderTargetView, nullptr);
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
return oPresent(pSwapChain, SyncInterval, Flags);
return oPresent(pSwapChain, SyncInterval, Flags);
} catch (const std::exception& e) {
spdlog::error("Exception thrown rendering ImGui in DX11: {}", e.what());
if (retries >= 6) {
spdlog::error("Retried rendering ImGui in DX11 6 times, game will exit now.");
IM_ASSERT(retries < 6 && "Retried rendering ImGui in DX11 6 times, game will exit now.");
}
}
}
}
HRESULT(__stdcall* oResizeBuffers)(IDXGISwapChain*, UINT, UINT, UINT, DXGI_FORMAT, UINT);

View File

@ -105,47 +105,59 @@ namespace impl {
init = true;
}
if (!frameContext[0].main_render_target_resource)
CreateRenderTarget(pSwapChain);
if (!d3d12CommandQueue || !frameContext[0].main_render_target_resource)
return;
for (int retries = 0;; retries++) {
try {
if (!frameContext[0].main_render_target_resource)
CreateRenderTarget(pSwapChain);
if (!d3d12CommandQueue || !frameContext[0].main_render_target_resource)
return;
ImGui_ImplDX12_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
ImGui_ImplDX12_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
Menu::FirstTimeRunning();
if (Menu::menuToggle.GetValue())
Menu::Render();
Menu::FirstTimeRunning();
if (Menu::menuToggle.GetValue())
Menu::Render();
ImGui::Render();
ImGui::Render();
UINT backBufferIdx = pSwapChain->GetCurrentBackBufferIndex();
ID3D12CommandAllocator* commandAllocator = frameContext[backBufferIdx].commandAllocator;
commandAllocator->Reset();
UINT backBufferIdx = pSwapChain->GetCurrentBackBufferIndex();
ID3D12CommandAllocator* commandAllocator = frameContext[backBufferIdx].commandAllocator;
commandAllocator->Reset();
D3D12_RESOURCE_BARRIER barrier{};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = frameContext[backBufferIdx].main_render_target_resource;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
d3d12CommandList->Reset(commandAllocator, NULL);
d3d12CommandList->ResourceBarrier(1, &barrier);
D3D12_RESOURCE_BARRIER barrier{};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = frameContext[backBufferIdx].main_render_target_resource;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
d3d12CommandList->Reset(commandAllocator, NULL);
d3d12CommandList->ResourceBarrier(1, &barrier);
d3d12CommandList->OMSetRenderTargets(1, &frameContext[backBufferIdx].main_render_target_descriptor, FALSE, NULL);
d3d12CommandList->SetDescriptorHeaps(1, &d3d12DescriptorHeapImGuiRender);
d3d12CommandList->OMSetRenderTargets(1, &frameContext[backBufferIdx].main_render_target_descriptor, FALSE, NULL);
d3d12CommandList->SetDescriptorHeaps(1, &d3d12DescriptorHeapImGuiRender);
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), d3d12CommandList);
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), d3d12CommandList);
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
d3d12CommandList->ResourceBarrier(1, &barrier);
d3d12CommandList->Close();
d3d12CommandList->ResourceBarrier(1, &barrier);
d3d12CommandList->Close();
d3d12CommandQueue->ExecuteCommandLists(1, reinterpret_cast<ID3D12CommandList* const*>(&d3d12CommandList));
d3d12CommandQueue->ExecuteCommandLists(1, reinterpret_cast<ID3D12CommandList* const*>(&d3d12CommandList));
break;
} catch (const std::exception& e) {
spdlog::error("Exception thrown rendering ImGui in DX12: {}", e.what());
if (retries >= 6) {
spdlog::error("Retried rendering ImGui in DX12 6 times, game will exit now.");
IM_ASSERT(retries < 6 && "Retried rendering ImGui in DX12 6 times, game will exit now.");
}
}
}
}
HRESULT(__stdcall* oPresent)(IDXGISwapChain3*, UINT, UINT);

View File

@ -67,31 +67,48 @@ namespace Core {
}
static void CreateSymlinkForLoadingFiles() {
std::filesystem::create_directories("EGameTools\\UserModFiles");
try {
const char* userModFilesPath = "..\\..\\..\\source\\data\\EGameTools\\UserModFiles";
const char* EGameToolsPath = "..\\..\\..\\source\\data\\EGameTools";
if (!std::filesystem::exists(userModFilesPath))
std::filesystem::create_directories(userModFilesPath);
for (const auto& entry : std::filesystem::directory_iterator("..\\..\\data")) {
if (entry.path().filename().string() == "EGameTools" && is_symlink(entry.symlink_status())) {
if (std::filesystem::equivalent("..\\..\\data\\EGameTools", "EGameTools"))
return;
std::filesystem::remove(entry.path());
for (const auto& entry : std::filesystem::directory_iterator(".")) {
if (entry.path().filename().string() == "EGameTools") {
if (is_symlink(entry.symlink_status()) && std::filesystem::equivalent("EGameTools", EGameToolsPath))
return;
std::filesystem::remove(entry.path());
}
}
spdlog::warn("Creating folder shortcut \"EGameTools\" for \"Dying Light 2\\ph\\source\\data\\EGameTools\" folder");
std::filesystem::create_directory_symlink(EGameToolsPath, Utils::Files::GetCurrentProcDirectory() + "\\EGameTools");
spdlog::info("Game shortcut created");
} catch (const std::exception& e) {
spdlog::error("Exception thrown while trying to create folder shortcut: {}", e.what());
spdlog::warn("This error should NOT affect any features of my mod. The shortcut is only a way for the user to easily access the folder \"Dying Light 2\\ph\\source\\data\\EGameTools\".");
}
spdlog::warn("Creating game shortcut for \"EGameTools\"");
std::filesystem::create_directory_symlink(Utils::Files::GetCurrentProcDirectory() + "\\EGameTools", "..\\..\\data\\EGameTools");
spdlog::info("Game shortcut created");
}
static void InitLogger() {
constexpr size_t maxSize = static_cast<size_t>(1048576) * 100;
constexpr size_t maxFiles = 10;
static std::vector<spdlog::sink_ptr> sinks{};
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>("EGameTools\\log.txt", maxSize, maxFiles, true));
sinks.push_back(std::make_shared<spdlog::sinks::wincolor_stdout_sink_mt>());
std::shared_ptr<spdlog::logger> combined_logger = std::make_shared<spdlog::logger>("EGameTools", std::begin(sinks), std::end(sinks));
combined_logger->flush_on(spdlog::level::trace);
try {
static std::vector<spdlog::sink_ptr> sinks{};
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>("..\\..\\..\\source\\data\\EGameTools\\log.txt", maxSize, maxFiles, true));
sinks.push_back(std::make_shared<spdlog::sinks::wincolor_stdout_sink_mt>());
std::shared_ptr<spdlog::logger> combined_logger = std::make_shared<spdlog::logger>("EGameTools", std::begin(sinks), std::end(sinks));
combined_logger->flush_on(spdlog::level::trace);
spdlog::set_default_logger(combined_logger);
spdlog::set_default_logger(combined_logger);
} catch (const std::exception& e) {
UNREFERENCED_PARAMETER(e);
std::cout << "Failed creating spdlog instance! Please contact mod author, this is not supposed to happen!" << std::endl;
std::cout << "Game will exit in 30 seconds. Close this window once you've read the text." << std::endl;
Sleep(30000);
exit(0);
}
}
void OnPostUpdate() {

View File

@ -67,21 +67,18 @@ namespace Engine {
#pragma endregion
#pragma region fs::open
static LPVOID GetFsOpen() {
return Utils::Memory::GetProcAddr("filesystem_x64_rwdi.dll", "?open@fs@@YAPEAUSFsFile@@V?$string_const@D@ttl@@W4TYPE@EFSMode@@W45FFSOpenFlags@@@Z");
}
static DWORD64 detourFsOpen(DWORD64 file, DWORD a2, DWORD a3);
static Utils::Hook::MHook<LPVOID, DWORD64(*)(DWORD64, DWORD, DWORD)> FsOpenHook{ "fs::open", &GetFsOpen, &detourFsOpen };
static std::vector<std::string> cachedUserModDirs{};
static Utils::Time::Timer timeSinceCache{ 0 };
static void CacheUserModDirs() {
spdlog::warn("Recaching user mod directories");
if (!cachedUserModDirs.empty())
cachedUserModDirs.clear();
cachedUserModDirs.push_back("EGameTools\\UserModFiles");
for (const auto& entry : std::filesystem::recursive_directory_iterator("EGameTools\\UserModFiles")) {
const char* userModFilesPath = "..\\..\\..\\source\\data\\EGameTools\\UserModFiles";
cachedUserModDirs.push_back(userModFilesPath);
for (const auto& entry : std::filesystem::recursive_directory_iterator(userModFilesPath)) {
const std::filesystem::path pathToDir = entry.path();
if (!std::filesystem::is_directory(pathToDir))
continue;
@ -90,13 +87,18 @@ namespace Engine {
}
}
static Utils::Time::Timer timeSinceCache{ 0 };
static LPVOID GetFsOpen() {
return Utils::Memory::GetProcAddr("filesystem_x64_rwdi.dll", "?open@fs@@YAPEAUSFsFile@@V?$string_const@D@ttl@@W4TYPE@EFSMode@@W45FFSOpenFlags@@@Z");
}
static DWORD64 detourFsOpen(DWORD64 file, DWORD a2, DWORD a3);
static Utils::Hook::MHook<LPVOID, DWORD64(*)(DWORD64, DWORD, DWORD)> FsOpenHook{ "fs::open", &GetFsOpen, &detourFsOpen };
static DWORD64 detourFsOpen(DWORD64 file, DWORD a2, DWORD a3) {
const DWORD64 firstByte = (file >> 56) & 0xFF; // get first byte of addr
const char* filePath = reinterpret_cast<const char*>(file & 0x1FFFFFFFFFFFFFFF); // remove first byte of addr in case it exists
const std::string fileName = std::filesystem::path(filePath).filename().string();
if (fileName.empty())
if (fileName.empty() || fileName.contains("EGameTools") || fileName.ends_with(".model"))
return FsOpenHook.pOriginal(file, a2, a3);
if (timeSinceCache.DidTimePass()) {
@ -104,15 +106,27 @@ namespace Engine {
timeSinceCache = Utils::Time::Timer(5000);
}
for (const auto& entry : cachedUserModDirs) {
const std::string finalPath = entry + "\\" + fileName;
if (!std::filesystem::exists(finalPath))
continue;
std::string finalPath{};
const char* filePath2 = finalPath.c_str();
spdlog::warn("Loading user mod file \"{}\"", filePath2);
try {
for (const auto& entry : cachedUserModDirs) {
finalPath = entry + "\\" + fileName;
if (!std::filesystem::exists(finalPath))
continue;
return FsOpenHook.pOriginal(firstByte != 0x0 ? (reinterpret_cast<DWORD64>(filePath2) | (firstByte << 56)) : reinterpret_cast<DWORD64>(filePath2), a2, a3); // restores first byte of addr if first byte was not 0
const std::string finalPath2 = std::filesystem::absolute(finalPath).string();
const char* filePath2 = finalPath2.c_str();
spdlog::warn("Loading user mod file \"{}\"", finalPath.c_str());
const DWORD64 finalAddr = firstByte != 0x0 ? (reinterpret_cast<DWORD64>(filePath2) | (firstByte << 56)) : reinterpret_cast<DWORD64>(filePath2); // restores first byte of addr if first byte was not 0
const DWORD64 result = FsOpenHook.pOriginal(finalAddr, a2, a3);
if (!result)
spdlog::error("fs::open returned 0! Something went wrong with loading user mod file \"{}\"!", finalPath.c_str());
return result;
}
} catch (const std::exception& e) {
spdlog::error("Exception thrown while loading user mod file \"{}\": {}", finalPath.c_str(), e.what());
}
return FsOpenHook.pOriginal(file, a2, a3);
}