mirror of
https://github.com/EricPlayZ/EGameTools.git
synced 2025-07-18 17:37:53 +08:00
- 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:
@ -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>
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user