Add disabled GPS momentum penalty prototype

This commit is contained in:
2026-06-27 02:42:21 -05:00
parent 7ee09de73f
commit 12fb5d3b55
3 changed files with 279 additions and 9 deletions
+221
View File
@@ -103,6 +103,7 @@ constexpr bool kEnableGpsMultiplierHooks = false;
constexpr bool kEnableGpsAuxMultiplierHook = false;
constexpr bool kEnableGpsMultiplierSignatureTrace = false;
constexpr bool kEnableGpsNodeMultiplierInlinePatch = true;
constexpr bool kEnableGpsMomentumPenaltyInlinePatch = false;
constexpr bool kEnableGpsCostTablePatch = false;
constexpr bool kEnableGpsProviderClassPatch = false;
constexpr bool kEnableGpsProviderClassPatchTrace = false;
@@ -197,6 +198,9 @@ constexpr uintptr_t kGpsFilteredCostProviderVtableRva = 0x2AE60F8;
constexpr uintptr_t kGpsAuxMultiplierRva = 0x040BB00;
constexpr uintptr_t kGpsNodeMultiplierRva = 0x040BB40;
constexpr uintptr_t kGpsNodeMultiplierRoadTailRva = 0x040BB98;
constexpr uintptr_t kGpsRelaxUpdateRva = 0x040BA58;
constexpr uintptr_t kGpsExpandListARelaxPatchRva = 0x040B49A;
constexpr uintptr_t kGpsExpandListBRelaxPatchRva = 0x040B6C3;
constexpr uintptr_t kGpsCostMultiplierTableRva = 0x3154D28;
constexpr uint64_t kGpsResolveTraceWindowMs = 1200;
constexpr uint32_t kGpsResolveSelectedRetLogLimit = 24;
@@ -217,6 +221,9 @@ constexpr float kGpsSolverHighwayMultiplierDefault = 0.80f;
constexpr float kGpsSolverGpsOnlyMultiplier = 1.10f;
constexpr float kGpsSolverPavementMultiplier = 1.25f;
constexpr size_t kGpsNodeMultiplierRoadTailPatchSize = 14;
constexpr size_t kGpsMomentumRelaxPatchSize = 23;
constexpr size_t kGpsMomentumPenaltyCaveSize = 96;
constexpr float kGpsMomentumFixedEdgePenalty = 8.0f;
constexpr std::array<float, 8> kGpsSolverNonRoadMultipliers = {
10.0f, 6.0f, 2.0f, 0.0f, 4.0f, 2.5f, 1.5f, 0.0f,
};
@@ -245,6 +252,16 @@ constexpr std::array<GpsProviderClassOverride, 5> kGpsProviderClassOverrides = {
constexpr std::array<size_t, 6> kGpsProviderClassProbeIds = {1, 3, 4, 5, 14, 15};
struct GpsMomentumPenaltyPatchSite
{
const char* name;
uintptr_t targetRva;
std::array<uint8_t, kGpsMomentumRelaxPatchSize> original{};
void* cave = nullptr;
uint8_t* penaltyConstant = nullptr;
bool applied = false;
};
HMODULE gModule = nullptr;
std::mutex gLogMutex;
RED4ext::v1::PluginHandle gHandle = nullptr;
@@ -330,6 +347,10 @@ std::array<uint8_t, kGpsNodeMultiplierRoadTailPatchSize> gGpsNodeMultiplierRoadT
void* gGpsNodeMultiplierRoadTailCave = nullptr;
uint8_t* gGpsNodeMultiplierRoadTailHighwayConstant = nullptr;
bool gGpsNodeMultiplierRoadTailPatchApplied = false;
std::array<GpsMomentumPenaltyPatchSite, 2> gGpsMomentumPenaltyPatchSites = {{
{"expand-list-a", kGpsExpandListARelaxPatchRva},
{"expand-list-b", kGpsExpandListBRelaxPatchRva},
}};
std::mutex gGpsCostLogMutex;
std::mutex gGpsAsyncLogMutex;
std::mutex gGpsCostTablePatchMutex;
@@ -687,6 +708,43 @@ void LogGpsSolverHighwayMultiplier(std::string_view aPrefix, float aValue)
LogRed4ext(line.str());
}
void EmitAbsoluteRaxCall(uint8_t* aCave, size_t& aOffset, uintptr_t aTarget)
{
aCave[aOffset++] = 0x48; // mov rax, imm64
aCave[aOffset++] = 0xB8;
std::memcpy(aCave + aOffset, &aTarget, sizeof(aTarget));
aOffset += sizeof(aTarget);
aCave[aOffset++] = 0xFF; // call rax
aCave[aOffset++] = 0xD0;
}
void EmitAbsoluteRaxJump(uint8_t* aCave, size_t& aOffset, uintptr_t aTarget)
{
aCave[aOffset++] = 0x48; // mov rax, imm64
aCave[aOffset++] = 0xB8;
std::memcpy(aCave + aOffset, &aTarget, sizeof(aTarget));
aOffset += sizeof(aTarget);
aCave[aOffset++] = 0xFF; // jmp rax
aCave[aOffset++] = 0xE0;
}
void BuildAbsoluteJumpPatch(uint8_t* aPatch, size_t aPatchSize, uintptr_t aTarget)
{
size_t offset = 0;
aPatch[offset++] = 0xFF; // jmp qword ptr [rip+0]
aPatch[offset++] = 0x25;
aPatch[offset++] = 0x00;
aPatch[offset++] = 0x00;
aPatch[offset++] = 0x00;
aPatch[offset++] = 0x00;
std::memcpy(aPatch + offset, &aTarget, sizeof(aTarget));
offset += sizeof(aTarget);
while (offset < aPatchSize)
{
aPatch[offset++] = 0x90;
}
}
void MaybeReloadGpsSolverWeights(bool aForce = false)
{
if (!kEnableGpsNodeMultiplierInlinePatch)
@@ -761,6 +819,159 @@ void MaybeReloadGpsSolverWeights(bool aForce = false)
LogRed4ext(line.str());
}
void RemoveGpsMomentumPenaltyInlinePatch();
bool InstallGpsMomentumPenaltyPatchSite(GpsMomentumPenaltyPatchSite& aSite,
std::initializer_list<uint8_t> aAddCurrentCostInstruction)
{
if (aSite.applied)
{
return true;
}
auto* cave = static_cast<uint8_t*>(
VirtualAlloc(nullptr, kGpsMomentumPenaltyCaveSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE));
if (!cave)
{
std::ostringstream line;
line << "gps-momentum-penalty-inline-patch skipped site=" << aSite.name << " reason=alloc-failed";
LogRed4ext(line.str());
return false;
}
size_t offset = 0;
const auto emit = [&](std::initializer_list<uint8_t> aBytes) {
for (auto byte : aBytes)
{
cave[offset++] = byte;
}
};
// Replaces the final g/f assembly before 0x40ba58. The overwritten
// vanilla block differs only in which XMM register stores current.g.
emit(aAddCurrentCostInstruction);
const auto addPenaltyOffset = offset;
emit({0xF3, 0x0F, 0x58, 0x35, 0x00, 0x00, 0x00, 0x00}); // addss xmm6, [rip+disp32]
emit({0xF3, 0x0F, 0x58, 0xC6}); // addss xmm0, xmm6
emit({0x0F, 0x28, 0xDE}); // movaps xmm3, xmm6
emit({0xF3, 0x0F, 0x11, 0x44, 0x24, 0x20}); // movss [rsp+0x20], xmm0
EmitAbsoluteRaxCall(cave, offset, GetImageBase() + kGpsRelaxUpdateRva);
EmitAbsoluteRaxJump(cave, offset, GetImageBase() + aSite.targetRva + kGpsMomentumRelaxPatchSize);
while ((offset % alignof(float)) != 0)
{
cave[offset++] = 0x90;
}
const auto penaltyConstantOffset = offset;
WriteFloat(cave + offset, kGpsMomentumFixedEdgePenalty);
offset += sizeof(float);
const auto caveAddress = reinterpret_cast<uintptr_t>(cave);
WriteInt32(cave + addPenaltyOffset + 4,
static_cast<int32_t>((caveAddress + penaltyConstantOffset) - (caveAddress + addPenaltyOffset + 8)));
auto* target = reinterpret_cast<uint8_t*>(GetImageBase() + aSite.targetRva);
std::memcpy(aSite.original.data(), target, aSite.original.size());
std::array<uint8_t, kGpsMomentumRelaxPatchSize> patch{};
BuildAbsoluteJumpPatch(patch.data(), patch.size(), caveAddress);
DWORD oldProtect = 0;
if (!VirtualProtect(target, patch.size(), PAGE_EXECUTE_READWRITE, &oldProtect))
{
VirtualFree(cave, 0, MEM_RELEASE);
std::ostringstream line;
line << "gps-momentum-penalty-inline-patch skipped site=" << aSite.name << " reason=protect-failed";
LogRed4ext(line.str());
return false;
}
std::memcpy(target, patch.data(), patch.size());
FlushInstructionCache(GetCurrentProcess(), target, patch.size());
DWORD ignoredProtect = 0;
VirtualProtect(target, patch.size(), oldProtect, &ignoredProtect);
aSite.cave = cave;
aSite.penaltyConstant = cave + penaltyConstantOffset;
aSite.applied = true;
std::ostringstream line;
line << "gps-momentum-penalty-inline-patch applied site=" << aSite.name << " target_rva=0x" << std::hex
<< aSite.targetRva << " cave=" << static_cast<void*>(cave) << std::dec
<< " fixedEdgePenalty=" << kGpsMomentumFixedEdgePenalty;
LogRed4ext(line.str());
return true;
}
bool InstallGpsMomentumPenaltyInlinePatch()
{
if (!kEnableGpsMomentumPenaltyInlinePatch)
{
return true;
}
const bool firstOk =
InstallGpsMomentumPenaltyPatchSite(gGpsMomentumPenaltyPatchSites[0],
{0xF3, 0x41, 0x0F, 0x58, 0xF6}); // addss xmm6, xmm14
const bool secondOk =
InstallGpsMomentumPenaltyPatchSite(gGpsMomentumPenaltyPatchSites[1],
{0xF3, 0x41, 0x0F, 0x58, 0xF4}); // addss xmm6, xmm12
if (!firstOk || !secondOk)
{
RemoveGpsMomentumPenaltyInlinePatch();
return false;
}
return true;
}
void RemoveGpsMomentumPenaltyInlinePatch()
{
for (auto& site : gGpsMomentumPenaltyPatchSites)
{
if (!site.applied)
{
continue;
}
auto* target = reinterpret_cast<uint8_t*>(GetImageBase() + site.targetRva);
DWORD oldProtect = 0;
if (VirtualProtect(target, site.original.size(), PAGE_EXECUTE_READWRITE, &oldProtect))
{
std::memcpy(target, site.original.data(), site.original.size());
FlushInstructionCache(GetCurrentProcess(), target, site.original.size());
DWORD ignoredProtect = 0;
VirtualProtect(target, site.original.size(), oldProtect, &ignoredProtect);
std::ostringstream line;
line << "gps-momentum-penalty-inline-patch restored site=" << site.name;
LogRed4ext(line.str());
}
else
{
std::ostringstream line;
line << "gps-momentum-penalty-inline-patch restore-failed site=" << site.name
<< " reason=protect-failed";
LogRed4ext(line.str());
}
if (site.cave)
{
VirtualFree(site.cave, 0, MEM_RELEASE);
site.cave = nullptr;
}
site.penaltyConstant = nullptr;
site.applied = false;
}
}
bool InstallGpsNodeMultiplierInlinePatch()
{
if (!kEnableGpsNodeMultiplierInlinePatch || gGpsNodeMultiplierRoadTailPatchApplied)
@@ -5550,7 +5761,16 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
gGpsSolverHighwayMultiplier.load(std::memory_order_relaxed));
}
if (kEnableGpsMomentumPenaltyInlinePatch)
{
std::ostringstream line;
line << "momentum fixed-edge penalty active value=" << kGpsMomentumFixedEdgePenalty
<< " sites=ordinary-expansion";
LogRed4ext(line.str());
}
InstallGpsNodeMultiplierInlinePatch();
InstallGpsMomentumPenaltyInlinePatch();
if (kEnableGpsQueryLifecycleHooks)
{
@@ -5781,6 +6001,7 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
if (aReason == RED4ext::v1::EMainReason::Unload)
{
RemoveGpsNodeMultiplierInlinePatch();
RemoveGpsMomentumPenaltyInlinePatch();
if (kEnableGpsQueryLifecycleHooks)
{