Add live GPS momentum weights

This commit is contained in:
2026-06-27 03:22:39 -05:00
parent d288b9fa6b
commit 186fc303e5
9 changed files with 224 additions and 8 deletions
+138 -8
View File
@@ -224,7 +224,8 @@ 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 float kGpsMomentumFixedEdgePenaltyDefault = 8.0f;
constexpr float kGpsMomentumFixedEdgePenaltyMax = 1000.0f;
constexpr std::array<float, 8> kGpsSolverNonRoadMultipliers = {
10.0f, 6.0f, 2.0f, 0.0f, 4.0f, 2.5f, 1.5f, 0.0f,
};
@@ -236,6 +237,7 @@ constexpr float kGpsSpatialPavementMultiplier = 1.35f;
constexpr float kGpsSpatialUnknownMultiplier = 1.05f;
constexpr uint64_t kGpsSolverWeightsReloadIntervalMs = 500;
constexpr uint64_t kGpsSpatialWeightsReloadIntervalMs = 500;
constexpr uint64_t kGpsMomentumWeightsReloadIntervalMs = 500;
struct GpsProviderClassOverride
{
@@ -601,13 +603,18 @@ std::array<std::atomic<float>, 5> gGpsSpatialMultipliers = {
kGpsSpatialUnknownMultiplier,
};
std::atomic<float> gGpsSolverHighwayMultiplier{kGpsSolverHighwayMultiplierDefault};
std::atomic<float> gGpsMomentumFixedEdgePenalty{kGpsMomentumFixedEdgePenaltyDefault};
std::mutex gGpsSpatialWeightsMutex;
std::mutex gGpsMomentumWeightsMutex;
std::atomic<uint64_t> gGpsSolverWeightsNextReloadCheckMs = 0;
std::atomic<uint64_t> gGpsSpatialWeightsNextReloadCheckMs = 0;
std::atomic<uint64_t> gGpsMomentumWeightsNextReloadCheckMs = 0;
std::filesystem::file_time_type gGpsSolverWeightsLastWriteTime{};
std::filesystem::file_time_type gGpsSpatialWeightsLastWriteTime{};
std::filesystem::file_time_type gGpsMomentumWeightsLastWriteTime{};
bool gGpsSolverWeightsFileKnown = false;
bool gGpsSpatialWeightsFileKnown = false;
bool gGpsMomentumWeightsFileKnown = false;
uintptr_t GetImageBase();
@@ -638,6 +645,11 @@ std::filesystem::path GetSolverWeightsPath()
return GetPluginDirectory() / L"solver_weights.bin";
}
std::filesystem::path GetMomentumWeightsPath()
{
return GetPluginDirectory() / L"momentum_weights.bin";
}
uint64_t GetElapsedMs()
{
if (!gLogStartTick || !gLogFrequency)
@@ -715,6 +727,34 @@ void LogGpsSolverHighwayMultiplier(std::string_view aPrefix, float aValue)
LogRed4ext(line.str());
}
bool IsUsableMomentumPenalty(float aValue)
{
return std::isfinite(aValue) && aValue >= 0.0f && aValue <= kGpsMomentumFixedEdgePenaltyMax;
}
void StoreGpsMomentumFixedEdgePenalty(float aValue)
{
gGpsMomentumFixedEdgePenalty.store(aValue, std::memory_order_relaxed);
for (auto& site : gGpsMomentumPenaltyPatchSites)
{
if (!site.penaltyConstant)
{
continue;
}
WriteFloat(site.penaltyConstant, aValue);
FlushInstructionCache(GetCurrentProcess(), site.penaltyConstant, sizeof(aValue));
}
}
void LogGpsMomentumFixedEdgePenalty(std::string_view aPrefix, float aValue)
{
std::ostringstream line;
line << aPrefix << " fixedEdgePenalty=" << aValue;
LogRed4ext(line.str());
}
void EmitAbsoluteRaxCall(uint8_t* aCave, size_t& aOffset, uintptr_t aTarget)
{
aCave[aOffset++] = 0x48; // mov rax, imm64
@@ -838,6 +878,82 @@ void MaybeReloadGpsSolverWeights(bool aForce = false)
LogRed4ext(line.str());
}
void MaybeReloadGpsMomentumWeights(bool aForce = false)
{
if (!kEnableGpsMomentumPenaltyInlinePatch)
{
return;
}
const auto nowMs = GetElapsedMs();
if (!aForce && nowMs < gGpsMomentumWeightsNextReloadCheckMs.load(std::memory_order_relaxed))
{
return;
}
std::lock_guard lock(gGpsMomentumWeightsMutex);
if (!aForce && nowMs < gGpsMomentumWeightsNextReloadCheckMs.load(std::memory_order_relaxed))
{
return;
}
gGpsMomentumWeightsNextReloadCheckMs.store(nowMs + kGpsMomentumWeightsReloadIntervalMs,
std::memory_order_relaxed);
const auto path = GetMomentumWeightsPath();
std::error_code error;
const auto writeTime = std::filesystem::last_write_time(path, error);
if (error)
{
if (aForce || gGpsMomentumWeightsFileKnown)
{
gGpsMomentumWeightsFileKnown = false;
std::ostringstream line;
line << "momentum weights file unavailable path=" << path.string()
<< " using fixedEdgePenalty=" << gGpsMomentumFixedEdgePenalty.load(std::memory_order_relaxed);
LogRed4ext(line.str());
}
return;
}
if (!aForce && gGpsMomentumWeightsFileKnown && writeTime == gGpsMomentumWeightsLastWriteTime)
{
return;
}
float fixedEdgePenalty = 0.0f;
std::ifstream input(path, std::ios::binary);
input.read(reinterpret_cast<char*>(&fixedEdgePenalty), static_cast<std::streamsize>(sizeof(fixedEdgePenalty)));
if (input.gcount() != static_cast<std::streamsize>(sizeof(fixedEdgePenalty)))
{
std::ostringstream line;
line << "momentum weights reload skipped path=" << path.string() << " bytes=" << input.gcount()
<< " expected=" << sizeof(fixedEdgePenalty);
LogRed4ext(line.str());
gGpsMomentumWeightsFileKnown = true;
gGpsMomentumWeightsLastWriteTime = writeTime;
return;
}
if (!IsUsableMomentumPenalty(fixedEdgePenalty))
{
std::ostringstream line;
line << "momentum weights reload skipped path=" << path.string()
<< " invalidFixedEdgePenalty=" << fixedEdgePenalty;
LogRed4ext(line.str());
gGpsMomentumWeightsFileKnown = true;
gGpsMomentumWeightsLastWriteTime = writeTime;
return;
}
StoreGpsMomentumFixedEdgePenalty(fixedEdgePenalty);
gGpsMomentumWeightsFileKnown = true;
gGpsMomentumWeightsLastWriteTime = writeTime;
std::ostringstream line;
line << "momentum weights reloaded path=" << path.string() << " fixedEdgePenalty=" << fixedEdgePenalty;
LogRed4ext(line.str());
}
void RemoveGpsMomentumPenaltyInlinePatch();
bool InstallGpsMomentumPenaltyPatchSite(GpsMomentumPenaltyPatchSite& aSite,
@@ -889,7 +1005,7 @@ bool InstallGpsMomentumPenaltyPatchSite(GpsMomentumPenaltyPatchSite& aSite,
}
const auto penaltyConstantOffset = offset;
WriteFloat(cave + offset, kGpsMomentumFixedEdgePenalty);
WriteFloat(cave + offset, gGpsMomentumFixedEdgePenalty.load(std::memory_order_relaxed));
offset += sizeof(float);
const auto caveAddress = reinterpret_cast<uintptr_t>(cave);
@@ -925,7 +1041,7 @@ bool InstallGpsMomentumPenaltyPatchSite(GpsMomentumPenaltyPatchSite& aSite,
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;
<< " fixedEdgePenalty=" << gGpsMomentumFixedEdgePenalty.load(std::memory_order_relaxed);
LogRed4ext(line.str());
return true;
}
@@ -2604,6 +2720,14 @@ void AppendGpsResultObjectLightCounts(std::ostringstream& aLine, const char* aPr
aLine << " " << aPrefix << "_pointCount=" << pointCount;
}
bool TryReadGpsResultRouteCount(void* aResultObject, uint32_t& aRouteCount)
{
aRouteCount = 0;
return aResultObject &&
TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aResultObject) + 0x34),
aRouteCount);
}
void AppendGpsResultElementArraySummary(std::ostringstream& aLine, const char* aPrefix, void* aResultObject)
{
uint32_t capacity = 0;
@@ -4555,7 +4679,9 @@ bool DetourGpsQueryResultFetch(void* aManager, uint32_t aQueryId, void* aOutPath
(!isTracked && callCount < kMaxUntrackedSamples && aQueryId < 2))
: (result && isMapRouteQuery);
if (result && isMapRouteQuery)
uint32_t gpsResultRouteCount = 0;
const auto hasGpsResultRouteCount = TryReadGpsResultRouteCount(aOutPath, gpsResultRouteCount);
if (result && isMapRouteQuery && hasGpsResultRouteCount && gpsResultRouteCount > 0)
{
TrackedGpsQuery summaryQuery{};
uint64_t callsA = 0;
@@ -4566,14 +4692,15 @@ bool DetourGpsQueryResultFetch(void* aManager, uint32_t aQueryId, void* aOutPath
globalCallsB))
{
const auto totalCalls = callsA + callsB;
const auto fixedPenalty = kGpsMomentumFixedEdgePenalty;
const auto fixedPenalty = gGpsMomentumFixedEdgePenalty.load(std::memory_order_relaxed);
std::ostringstream line;
line << "gps-momentum-summary queryId=" << aQueryId << " resultFetchCall=" << perQueryCall;
AppendTrackedGpsQuery(line, summaryQuery);
line << " callsA=" << callsA << " callsB=" << callsB << " callsTotal=" << totalCalls
<< " fixedPenalty=" << fixedPenalty
<< " penaltyTotal=" << static_cast<double>(totalCalls) * static_cast<double>(fixedPenalty)
<< " globalCallsA=" << globalCallsA << " globalCallsB=" << globalCallsB;
<< " globalCallsA=" << globalCallsA << " globalCallsB=" << globalCallsB
<< " gpsResultRouteCount=" << gpsResultRouteCount;
AppendGpsResultObjectLightCounts(line, "gpsResult", aOutPath);
LogRed4ext(line.str());
}
@@ -5787,6 +5914,7 @@ bool OnRunningUpdate(void* aApp)
}
MaybeReloadGpsSolverWeights();
MaybeReloadGpsMomentumWeights();
return false;
}
@@ -5869,9 +5997,11 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
if (kEnableGpsMomentumPenaltyInlinePatch)
{
std::ostringstream line;
line << "momentum fixed-edge penalty active value=" << kGpsMomentumFixedEdgePenalty
<< " sites=ordinary-expansion";
line << "momentum weights path=" << GetMomentumWeightsPath().string();
LogRed4ext(line.str());
MaybeReloadGpsMomentumWeights(true);
LogGpsMomentumFixedEdgePenalty("momentum fixed-edge penalty active",
gGpsMomentumFixedEdgePenalty.load(std::memory_order_relaxed));
}
InstallGpsNodeMultiplierInlinePatch();