Update for Skyrim 1.7.99 (CommonLibSSE-NG 6.6.3) - #4
Open
rrasto wants to merge 1 commit into
Open
Conversation
Precision does not load on Skyrim 1.7.99. This makes it build and run there while remaining correct on 1.6.x and 1.5.97. Most of the diff comes from building against a current CommonLibSSE-NG rather than from the game update itself: - build: C++23 and no /await, which is what CommonLibSSE-NG 6.x needs; four dependencies added to vcpkg.json, all of them declared by that library - eleven duplicate Havok class declarations removed from Havok.h after checking member by member that the layouts CommonLibSSE-NG now ships are identical - renamed and reshaped APIs: EnumSet flags, CFilter, BSGeometry runtime data, ahkpWorld::userData, NiCloningProcess::scale, REX::W32, PluginVersionData - LOADED_REF_DATA has no named member at 0x58 any more, so the same pointer is read by offset, verified against v3.7.0 that the byte layout is unchanged One genuine runtime fix: Actor::IsDead() returns true for living essential and protected NPCs on 1.7.99, measured over 29 actors, which stopped Precision from tracking almost everyone. ActorState::GetLifeState() is used instead. This looks like a CommonLibSSE-NG issue and should be reverted if it is fixed upstream. Two hook offsets moved within their functions in 1.7.99 and are now selected at runtime, so one binary stays correct on every supported runtime. No behaviour was changed on purpose. Where the original code looked wrong but worked, it was left alone, with a comment recording why. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I have also written to you on Nexus, in case GitHub notifications do not reach you. That message
asks whether you would be willing to let me publish this as an unofficial update if you no longer
have time for the mod.
Precision does not load on Skyrim 1.7.99. This updates it to build and run there, while remaining
correct on 1.6.x and 1.5.97. Tested in game on 1.7.99.
The bulk of the diff is not really about 1.7.99. Building against a current CommonLibSSE-NG accounts
for most of it, and only one change is a genuine runtime fix.
Build
cxx_std_20tocxx_std_23, required by CommonLibSSE-NG 6.x./awaitfrom the MSVC options. It is the pre-C++20 experimental coroutine switch, and withit MSVC's
<coroutine>disables itself (STL4039) and provides onlystd::experimental::coroutine_handle, so CommonLibSSE-NG 6.x does not compile. C++23 hascoroutines without any flag.
#include <coroutine>at the top ofPCH.h. CommonLibSSE-NG 6.x uses coroutines inIVirtualMachine, and relies on its own precompiled header having pulled the header in; thisproject has its own PCH.
directxmath,directxtk,nlohmann-jsonandtoml11tovcpkg.json. These are not newrequirements of Precision; they are CommonLibSSE-NG 6.6.3's own declared dependencies, and the
library is consumed here through
add_subdirectory.Duplicate Havok declarations removed
src/Havok/Havok.hdeclared eleven Havok types that CommonLibSSE-NG has since added, which nowcollide. I compared all eleven member by member before deleting any of them, and the byte layouts
are identical in every case, so the removal is safe.
hkpConvexVerticesShape::BuildConfigis the one exception: CommonLibSSE-NG defines the class but notthat nested struct, so it stays here as
hkpConvexVerticesShapeBuildConfigforthkpConvexVerticesShape_ctor.CommonLibSSE-NG API changes
hkContactPointMaterial::flagsREX::EnumSet, so|=becomes.set()and&becomes.any()collisionFilterInfoRE::CFilterrather than a rawuint32_t;GetCollisionFilterInfotakesCFilter&BSGeometry::properties[States::kEffect]GetGeometryRuntimeData().shaderPropertyahkpWorld::unk430userDataNiCloningProcess::unk68scaleSKSE::WinAPIREX::W32PluginVersionDataUsesAddressLibrary(true)toUsesAddressLibrary(),HasNoStructUse(true)toUsesNoStructs()RE::Offset::BSSoundHandle::SetPositionRE::Offsetnamespace is gone in 6.x; its only call site was already commented out, so the relocation was removedLOADED_REF_DATAneeds a word of its own. CommonLibSSE-NG now covers0x30to0x68with thehandleListarena, so the field the old headers calledunk58has no name any more. I verifiedagainst CommonLibSSE-NG v3.7.0, where that range was six raw
uint64values withdata3Dat0x68,that the byte layout is unchanged, and read the same pointer by offset with a comment saying so.
The one real fix:
Actor::IsDead()on 1.7.99CanAddToWorldpassed for every actor, yet almost none were tracked. The gate wasbIsActorDead.Actor::IsDead()is a virtual call at a fixed index, and on 1.7.99 it returnstruefor livingNPCs. Measured over 29 actors in Whiterun:
IsDead()GetLifeState()truekAlivefalsekAlivetruekDeadThe two it got right were a cow and a guard; every actor it got wrong is essential or protected,
including the player. That points at the
a_notEssentialparameter rather than a shifted vtable, anda shifted vtable is independently unlikely since other mods hook
Actorvirtuals at higher indiceson 1.7.99 without trouble.
ActorState::GetLifeState()reads a bitfield member with no vtable involved, sobIsActorDeadnowderives from that. This looks like a CommonLibSSE-NG issue rather than a Precision one, and I
intend to report it upstream; if it is fixed there, this change can be reverted.
Two hook offsets recomputed for 1.7.99
_TESObjectCELL_PlaceParticleEffectand_CdPointCollectorCastsit at offsets inside their parentfunctions, and 1.7.99 moved both. The functions were not changed; the executable was rebuilt and the
compiler laid the same code out differently.
hook4 + 0xB39becomes+0xB49hook3 + 0x294becomes+0x2ACThey are selected at runtime by
AEOffsetSince1799()inPCH.h, in the spirit ofREL::RelocateMemberIfNewer, so one binary stays correct on 1.6.x and 1.7.99 alike.On how they were found, since this is the part of the diff that deserves the most scepticism: both
were recovered from the executables by two independent methods, one resolving the call target through
the Address Library and one matching a byte fingerprint with the
rel32operand wildcarded. Thetooling was validated by reproducing 32 of the 33 offsets already in this file on 1.6.1170 before it
was pointed at 1.7.99. They are also consistent with in game behaviour, since hits register once
rather than twice and impact effects appear in the right place, but that is corroboration and not
proof.
Deliberately not changed
ContactPointCallbackopens with what looks like a precedence slip:!binds tighter than&, so the second term is(!flags) & kIsNew, and withkIsNew == 1that issimply "no flags set" rather than the apparently intended
!(flags & kIsNew). I wrote the intendedversion, and it silently broke weapon versus wall recoil by dropping continuing contacts. It is
preserved exactly as it was, with a comment recording why.
Licensing
One consequence worth flagging, because it is easy to miss and it is not caused by this pull request.
The README pins CommonLibSSE-NG v3.4.0, which was MIT. The 6.x series is GPL-3.0-or-later, with
two additional permissions in
EXCEPTIONS.md. Neither applies here: the Modding Exception coverslinking against Skyrim itself and explicitly requires that all other code used in conjunction with the
library obey the GPL, and the second covers combining with other modding libraries under incompatible
licences.
In practice:
relicensing and I have not touched
LICENSE.available. That applies to any release built from this branch, by either of us.
There is no way around it while supporting 1.7.99: the game changed the Address Library format, and
every CommonLibSSE-NG version that can read the new format is GPL licensed.
Testing
Built and played on Skyrim 1.7.99 with SKSE 2.3.0. Verified in game: skeleton colliders on all living
actors within the active distance, attack collisions and hit detection, weapon versus wall recoil, hit
material resolution, and the recoil material list loading from
Precision.esp.Not tested on 1.6.x or 1.5.97, on VR, or in first person.