81 lines
3.6 KiB
CMake
81 lines
3.6 KiB
CMake
# Patch applied to CommonLibSSE-NG via FetchContent PATCH_COMMAND.
|
|
#
|
|
# Skyrim AE 1.7.99 inserts two event sink bases into RE::SkyrimVM at 0x180 and
|
|
# 0x188, so every member from 0x180 onwards moves up by 0x10. CommonLibSSE-NG
|
|
# 6.5.0 modelled most of that shift (handlePolicy, the runtime data blocks and
|
|
# the tail block all get version aware accessors), but it left the pointer block
|
|
# that starts at "impl" declared at its pre-1.7.99 offsets.
|
|
#
|
|
# "impl" holds the BSScript::IVirtualMachine the whole Papyrus layer runs on:
|
|
#
|
|
# RE::BSScript::Internal::VirtualMachine::GetSingleton()
|
|
# -> SkyrimVM::GetSingleton()->impl.get()
|
|
#
|
|
# On 1.7.99 that reads offset 0x200, which now lands inside the preceding
|
|
# BSTEventSource, so the singleton is null or garbage. The visible effects are
|
|
# "Failed to get vm type id for class <n>!" for every object typed Papyrus
|
|
# parameter (RE::BSScript::GetRawTypeFromVMType null checks the pointer) and a
|
|
# crash in any caller that does not (Papyrus argument marshalling in
|
|
# PackUnpack.cpp, and this plugin's own script checks).
|
|
#
|
|
# The patch adds a version aware GetImpl() and routes the two in tree consumers
|
|
# through it. It deliberately leaves the member declarations alone, so every
|
|
# layout static_assert still holds.
|
|
#
|
|
# Verification: 61 call sites in SkyrimSE.exe 1.6.1170 read the field at
|
|
# [SkyrimVM + 0x200], and the matching 61 sites in 1.7.99 read [SkyrimVM + 0x210].
|
|
#
|
|
# Remove this file, its two PATCH_COMMAND entries and this note once upstream
|
|
# fixes the offset. The script is idempotent, and it fails the configure step if
|
|
# any of the three anchors is missing, so a bump that changes or fixes this code
|
|
# is reported instead of silently producing an unpatched build.
|
|
|
|
set(_clib_header "include/RE/S/SkyrimVM.h")
|
|
set(_clib_vm "src/RE/V/VirtualMachine.cpp")
|
|
set(_clib_skvm "src/RE/S/SkyrimVM.cpp")
|
|
|
|
set(_clib_marker "GetImpl")
|
|
|
|
set(_clib_accessor
|
|
" // AE 1.7.99 shifts every member from 0x180 onwards by +0x10, and impl is
|
|
// declared at its pre-1.7.99 offset. Read it through here, never directly.
|
|
[[nodiscard]] inline BSTSmartPointer<BSScript::IVirtualMachine>& GetImpl() noexcept
|
|
{
|
|
// Only AE reaches 1.7.99, so the version test alone selects the runtime.
|
|
return REL::RelocateMemberIfNewer<BSTSmartPointer<BSScript::IVirtualMachine>>(
|
|
SKSE::RUNTIME_SSE_1_7_99, this, 0x200, 0x210);
|
|
}
|
|
|
|
[[nodiscard]] inline const BSTSmartPointer<BSScript::IVirtualMachine>& GetImpl() const noexcept
|
|
{
|
|
return const_cast<SkyrimVM*>(this)->GetImpl();
|
|
}
|
|
|
|
static SkyrimVM* GetSingleton();")
|
|
|
|
function(_clib_patch_file path from to)
|
|
if(NOT EXISTS "${path}")
|
|
message(FATAL_ERROR "CommonLibSSE patch: ${path} is missing.")
|
|
endif()
|
|
file(READ "${path}" _content)
|
|
string(FIND "${_content}" "${_clib_marker}" _found)
|
|
if(_found GREATER_EQUAL 0)
|
|
return() # already patched
|
|
endif()
|
|
string(FIND "${_content}" "${from}" _anchor)
|
|
if(_anchor LESS 0)
|
|
message(FATAL_ERROR
|
|
"CommonLibSSE patch: anchor not found in ${path}.\n"
|
|
"Check whether upstream fixed SkyrimVM::impl for AE 1.7.99. If it did, "
|
|
"delete cmake/patch_commonlibsse.cmake and its PATCH_COMMAND entries.")
|
|
endif()
|
|
string(REPLACE "${from}" "${to}" _content "${_content}")
|
|
file(WRITE "${path}" "${_content}")
|
|
endfunction()
|
|
|
|
_clib_patch_file("${_clib_header}" " static SkyrimVM* GetSingleton();" "${_clib_accessor}")
|
|
_clib_patch_file("${_clib_vm}" "vm->impl.get()" "vm->GetImpl().get()")
|
|
_clib_patch_file("${_clib_skvm}" "impl.get()->SendEvent" "GetImpl().get()->SendEvent")
|
|
|
|
message(STATUS "Patched CommonLibSSE-NG SkyrimVM::impl for AE 1.7.99.")
|