Updated CommonLibSSE, added GOG VRAM Leak Fix by DwemerEngineer

This commit is contained in:
Eddoursul 2026-01-19 04:42:24 +01:00
parent 3fe7fb62ac
commit 7692789c38
9 changed files with 82 additions and 23 deletions

View File

@ -11,6 +11,11 @@ Beware, spoilers ahead!
- Removed the Blueprint keyword from the Dreamflower Elixir Recipe to avoid sorting it into the blueprint storage (reported by Fubz). - Removed the Blueprint keyword from the Dreamflower Elixir Recipe to avoid sorting it into the blueprint storage (reported by Fubz).
- Fixed an exploit allowing to collect more gold from containers (reported by LevinLozenges). - Fixed an exploit allowing to collect more gold from containers (reported by LevinLozenges).
Engine patches:
- Automatically detects and warns about form type collisions when using Skyrim mods.
- `Enderal - Forgotten Stories.esm` is always force-loaded.
- Included GOG Memory (VRAM) Leak Fix by DwemerEngineer.
Lirk: Lirk:
- Fixed several issues with weapon impact sounds. - Fixed several issues with weapon impact sounds.
- Fixed normals in agnodwall.nif. - Fixed normals in agnodwall.nif.

View File

@ -8,3 +8,4 @@ ForceBorderless = true
AttachLightHitEffectCrashFix = true AttachLightHitEffectCrashFix = true
AutoScaleHeroMenu = true AutoScaleHeroMenu = true
WarnFormTypeCollisions = true WarnFormTypeCollisions = true
GogVramLeakFix = true

View File

@ -80,7 +80,7 @@ add_library("Microsoft::DirectXTK" ALIAS "DirectXTK")
# simpleini # simpleini
FetchContent_Declare( FetchContent_Declare(
simpleini simpleini
URL "https://github.com/brofield/simpleini/archive/refs/tags/v4.22.tar.gz" URL "https://github.com/brofield/simpleini/archive/refs/tags/v4.25.tar.gz"
DOWNLOAD_EXTRACT_TIMESTAMP 1 DOWNLOAD_EXTRACT_TIMESTAMP 1
) )
FetchContent_MakeAvailable(simpleini) FetchContent_MakeAvailable(simpleini)
@ -89,7 +89,7 @@ INCLUDE_DIRECTORIES(${simpleini_SOURCE_DIR})
# rapidcsv # rapidcsv
FetchContent_Declare( FetchContent_Declare(
rapidcsv rapidcsv
URL "https://github.com/d99kris/rapidcsv/archive/refs/tags/v8.87.tar.gz" URL "https://github.com/d99kris/rapidcsv/archive/refs/tags/v8.90.tar.gz"
DOWNLOAD_EXTRACT_TIMESTAMP 1 DOWNLOAD_EXTRACT_TIMESTAMP 1
OVERRIDE_FIND_PACKAGE OVERRIDE_FIND_PACKAGE
) )
@ -97,11 +97,11 @@ FetchContent_MakeAvailable(rapidcsv)
set(RAPIDCSV_INCLUDE_DIRS ${rapidcsv_SOURCE_DIR}/src) set(RAPIDCSV_INCLUDE_DIRS ${rapidcsv_SOURCE_DIR}/src)
# spdlog # spdlog
set(SPDLOG_INSTALL ON CACHE INTERNAL "Install SPDLOG for CommonLibSSE") set(SPDLOG_INSTALL ON CACHE BOOL " " FORCE)
set(SPDLOG_USE_STD_FORMAT ON CACHE INTERNAL "Use std::format in SPDLOG, not fmt") set(SPDLOG_USE_STD_FORMAT ON CACHE BOOL " " FORCE)
FetchContent_Declare( FetchContent_Declare(
spdlog spdlog
URL "https://github.com/gabime/spdlog/archive/refs/tags/v1.15.3.tar.gz" URL "https://github.com/gabime/spdlog/archive/refs/tags/v1.17.0.tar.gz"
DOWNLOAD_EXTRACT_TIMESTAMP 1 DOWNLOAD_EXTRACT_TIMESTAMP 1
OVERRIDE_FIND_PACKAGE OVERRIDE_FIND_PACKAGE
) )
@ -110,7 +110,7 @@ FetchContent_MakeAvailable(spdlog)
# xbyak # xbyak
FetchContent_Declare( FetchContent_Declare(
xbyak xbyak
URL "https://github.com/herumi/xbyak/archive/v7.28.tar.gz" URL "https://github.com/herumi/xbyak/archive/v7.30.tar.gz"
DOWNLOAD_EXTRACT_TIMESTAMP 1 DOWNLOAD_EXTRACT_TIMESTAMP 1
) )
FetchContent_MakeAvailable(xbyak) FetchContent_MakeAvailable(xbyak)
@ -121,11 +121,11 @@ set(ENABLE_SKYRIM_SE ON CACHE BOOL " " FORCE)
set(ENABLE_SKYRIM_AE ON CACHE BOOL " " FORCE) set(ENABLE_SKYRIM_AE ON CACHE BOOL " " FORCE)
set(ENABLE_SKYRIM_VR ON CACHE BOOL " " FORCE) set(ENABLE_SKYRIM_VR ON CACHE BOOL " " FORCE)
set(BUILD_TESTS OFF CACHE BOOL " " FORCE) set(BUILD_TESTS OFF CACHE BOOL " " FORCE)
message(STATUS "Fetching CommonLibSSE-NG (5e5417e3585c9434295e919bdda27737244e9c5a)...") message(STATUS "Fetching CommonLibSSE-NG...")
FetchContent_Declare( FetchContent_Declare(
CommonLibSSE CommonLibSSE
GIT_REPOSITORY https://github.com/eddoursul/CommonLibVR.git GIT_REPOSITORY https://github.com/alandtse/CommonLibVR
GIT_TAG 5e5417e3585c9434295e919bdda27737244e9c5a GIT_TAG aacbd76c01bff9381e253ffdfcb4f9d5f263f1df
) )
FetchContent_MakeAvailable(CommonLibSSE) FetchContent_MakeAvailable(CommonLibSSE)

BIN
source/Enderal DLL/LICENSE (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -15,6 +15,7 @@
#include "Patches/AttachLightHitEffectCrash.h" #include "Patches/AttachLightHitEffectCrash.h"
#include "Patches/PluginsTxtPatch.h" #include "Patches/PluginsTxtPatch.h"
#include "Patches/FormTypeCollisionDetector.h" #include "Patches/FormTypeCollisionDetector.h"
#include "Patches/GogVramLeakFix.h"
using namespace SKSE; using namespace SKSE;
@ -28,7 +29,8 @@ static std::map<std::string, bool> g_settings{
{ "VideoInterruptPatch", true }, { "VideoInterruptPatch", true },
{ "ForceBorderless", true }, { "ForceBorderless", true },
{ "AttachLightHitEffectCrashFix", true }, { "AttachLightHitEffectCrashFix", true },
{ "AutoScaleHeroMenu", true } { "AutoScaleHeroMenu", true },
{ "GogVramLeakFix", true }
}; };
namespace { namespace {
@ -69,6 +71,11 @@ namespace {
if (message->type == MessagingInterface::kPostLoad) { if (message->type == MessagingInterface::kPostLoad) {
if (!REL::Module::IsVR()) { if (!REL::Module::IsVR()) {
if (g_settings.at("GogVramLeakFix") && REL::Module::get().version() == REL::Version(1, 6, 1179, 0) && !GetLoadInterface()->GetPluginInfo("GOG-Leak-Fix")) {
logger::info("Installing GOG VRAM leak fix...");
GogVramLeakFix::Install();
}
if (g_settings.at("AttachLightHitEffectCrashFix")) { if (g_settings.at("AttachLightHitEffectCrashFix")) {
logger::info("Installing light attach crash fix..."); logger::info("Installing light attach crash fix...");
AttachLightHitEffectCrash::Install(); AttachLightHitEffectCrash::Install();
@ -188,12 +195,15 @@ SKSEPluginLoad(const LoadInterface* skse) {
auto* plugin = PluginDeclaration::GetSingleton(); auto* plugin = PluginDeclaration::GetSingleton();
auto version = plugin->GetVersion(); auto version = plugin->GetVersion();
logger::info("{} {} ({}) is loading...", plugin->GetName(), version, SemVerToInt({ version.major(), version.minor(), version.patch(), version.build() })); auto versionStr = version.build() > 0
? std::format("{}.{}.{}.{}", version.major(), version.minor(), version.patch(), version.build())
: std::format("{}.{}.{}", version.major(), version.minor(), version.patch());
logger::info("{} {} ({}) is loading...", plugin->GetName(), versionStr, SemVerToInt(version.major(), version.minor(), version.patch(), version.build()));
Init(skse); Init(skse, false);
InitializeMessaging(); InitializeMessaging();
if (g_settings.at("WarnFormTypeCollisions")) { if (g_settings.at("WarnFormTypeCollisions") && !!REL::Module::IsVR()) {
FormTypeCollisionDetector::Install(); FormTypeCollisionDetector::Install();
} }

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#define SPDLOG_COMPILED_LIB
#include <RE/Skyrim.h> #include <RE/Skyrim.h>
#include <SKSE/SKSE.h> #include <SKSE/SKSE.h>
#include <REL/Relocation.h> #include <REL/Relocation.h>
@ -28,4 +30,11 @@ namespace SKSE::stl
{ {
asm_replace(a_from, a_size, reinterpret_cast<std::uintptr_t>(T::func)); asm_replace(a_from, a_size, reinterpret_cast<std::uintptr_t>(T::func));
} }
template <class T, std::size_t N = 5>
void write_thunk_jump(std::uintptr_t a_src)
{
auto& trampoline = SKSE::GetTrampoline();
T::func = trampoline.write_branch<N>(a_src, T::thunk);
}
} }

View File

@ -59,7 +59,7 @@ namespace Papyrus::PapyrusFunctions
{ {
const auto pluginVersion = SKSE::PluginDeclaration::GetSingleton()->GetVersion(); const auto pluginVersion = SKSE::PluginDeclaration::GetSingleton()->GetVersion();
return SemVerToInt({ pluginVersion.major(), pluginVersion.minor(), pluginVersion.patch(), pluginVersion.build() }); return SemVerToInt(pluginVersion.major(), pluginVersion.minor(), pluginVersion.patch(), pluginVersion.build());
} }
inline RE::TESObjectREFR* GetCurrentContainer(RE::StaticFunctionTag*) inline RE::TESObjectREFR* GetCurrentContainer(RE::StaticFunctionTag*)

View File

@ -0,0 +1,36 @@
#pragma once
// Fix GOG VRAM leak by properly releasing Direct3D texture resources
// Based on https://github.com/SaneEngineer/GOG-Leak-Fix
namespace GogVramLeakFix
{
struct ReplaceRelease
{
static void thunk(RE::BSGraphics::Renderer* a_renderer, RE::BSGraphics::Texture* a_texture)
{
if (_InterlockedExchangeAdd(&a_texture->unk20, 0xFFFFFFFF) == 1) {
if (a_texture->resourceView) {
a_texture->resourceView->Release();
}
if (a_texture->texture) {
a_texture->texture->Release();
}
if (a_texture->unk08) {
reinterpret_cast<ID3D11UnorderedAccessView*>(a_texture->unk08)->Release();
}
REL::Relocation<void(void*, int)> NiMemFree{ REL::RelocationID(102158, 109588) };
NiMemFree(a_texture, 0x28);
}
}
static inline REL::Relocation<decltype(thunk)> func;
};
void Install()
{
SKSE::AllocTrampoline(14);
SKSE::stl::write_thunk_jump<ReplaceRelease>(REL::RelocationID(75527, 77322).address());
logger::info("Initialized GOG VRAM Leak Fix");
}
}

View File

@ -23,14 +23,9 @@ inline uint8_t NewGameCount(bool increment = false)
return g_NewGameStarted; return g_NewGameStarted;
} }
inline std::uint32_t SemVerToInt(std::vector<int> numbers) inline std::uint32_t SemVerToInt(std::uint16_t major, std::uint16_t minor, std::uint16_t patch, std::uint16_t build)
{ {
if (numbers.size() < 4) { return (static_cast<std::uint32_t>(major) << 24) | (static_cast<std::uint32_t>(minor) << 16) | (static_cast<std::uint32_t>(patch) << 8) | static_cast<std::uint32_t>(build);
logger::error("Invalid SemVerToInt argument");
return 0;
}
return (numbers[0] << 24) | (numbers[1] << 16) | (numbers[2] << 8) | numbers[3];
} }
inline void CheckIncompatibleMods() inline void CheckIncompatibleMods()
@ -311,10 +306,10 @@ inline RE::BSFixedString GetPlayerHash()
{ {
char buf[] = "DEADBEEF"; char buf[] = "DEADBEEF";
auto saveData = RE::BSWin32SaveDataSystemUtility::GetSingleton(); auto saveData = RE::BSWin32SaveDataSystemUtility::GetSingleton();
if (saveData->profileHash == static_cast<std::uint32_t>(-1)) { if (saveData->currentCharacterID == static_cast<std::uint32_t>(-1)) {
std::snprintf(buf, sizeof(buf), "%08o", 0); std::snprintf(buf, sizeof(buf), "%08o", 0);
} else { } else {
std::snprintf(buf, sizeof(buf), "%08X", saveData->profileHash); std::snprintf(buf, sizeof(buf), "%08X", saveData->currentCharacterID);
} }
return buf; return buf;
} }