feat(scanner): complete localized artifact quality checkpoint
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
namespace GenshinAssistant.InputHelper;
|
||||
|
||||
internal enum NativeScannerInputGuardOutcome
|
||||
{
|
||||
Ready,
|
||||
Stopped,
|
||||
Blocked,
|
||||
}
|
||||
|
||||
internal readonly record struct NativeScannerInputGuardDecision(
|
||||
NativeScannerInputGuardOutcome Outcome,
|
||||
string Message)
|
||||
{
|
||||
public bool CanContinue => Outcome == NativeScannerInputGuardOutcome.Ready;
|
||||
|
||||
public static NativeScannerInputGuardDecision Ready()
|
||||
=> new(NativeScannerInputGuardOutcome.Ready, "");
|
||||
|
||||
public static NativeScannerInputGuardDecision Blocked(string message)
|
||||
=> new(NativeScannerInputGuardOutcome.Blocked, message);
|
||||
}
|
||||
|
||||
internal static class NativeScannerInputSafetyPolicy
|
||||
{
|
||||
// The live inventory capacity is 2,400 Artifacts. A full visible page
|
||||
// contains 32 safe targets and the live-calibrated page transition uses 39
|
||||
// wheel events. 3,200 upward events therefore cover the complete inventory
|
||||
// with a deterministic safety margin while remaining explicitly bounded.
|
||||
internal const int MaximumArtifactInventoryCapacity = 2400;
|
||||
internal const int VisibleArtifactTargetsPerPage = 32;
|
||||
internal const int PageScrollWheelEvents = 39;
|
||||
internal const int InventoryTopResetWheelEvents = 3200;
|
||||
internal const int InventoryTopResetStabilizationMs = 300;
|
||||
internal const int PageScrollStabilizationMs = 120;
|
||||
internal const int WheelPacingBatchEvents = PageScrollWheelEvents;
|
||||
internal const int WheelPacingDelayMs = 1;
|
||||
|
||||
internal static bool ShouldPauseAfterWheelEvent(int completedEventCount)
|
||||
=> completedEventCount > 0 && completedEventCount % WheelPacingBatchEvents == 0;
|
||||
|
||||
internal static NativeScannerInputGuardDecision Evaluate(
|
||||
bool stopRequested,
|
||||
bool escapePressed,
|
||||
bool enterPressed,
|
||||
bool f9Pressed,
|
||||
long expectedGenshinHwnd,
|
||||
long foregroundHwnd,
|
||||
string foregroundProcess,
|
||||
string action)
|
||||
{
|
||||
if (stopRequested)
|
||||
{
|
||||
return new NativeScannerInputGuardDecision(
|
||||
NativeScannerInputGuardOutcome.Stopped,
|
||||
$"stop requested before {action}");
|
||||
}
|
||||
if (escapePressed)
|
||||
{
|
||||
return new NativeScannerInputGuardDecision(
|
||||
NativeScannerInputGuardOutcome.Stopped,
|
||||
$"ESC held - native scan stopped before {action}");
|
||||
}
|
||||
if (enterPressed)
|
||||
{
|
||||
return new NativeScannerInputGuardDecision(
|
||||
NativeScannerInputGuardOutcome.Stopped,
|
||||
$"Enter held - native scan stopped before {action}");
|
||||
}
|
||||
if (f9Pressed)
|
||||
{
|
||||
return new NativeScannerInputGuardDecision(
|
||||
NativeScannerInputGuardOutcome.Stopped,
|
||||
$"F9 held - native scan stopped before {action}");
|
||||
}
|
||||
|
||||
if (expectedGenshinHwnd == 0)
|
||||
{
|
||||
return NativeScannerInputGuardDecision.Blocked(
|
||||
$"Genshin target window is unavailable before {action}; native scan stopped without refocusing.");
|
||||
}
|
||||
if (foregroundHwnd != expectedGenshinHwnd)
|
||||
{
|
||||
var actual = string.IsNullOrWhiteSpace(foregroundProcess) ? "unknown" : foregroundProcess;
|
||||
return NativeScannerInputGuardDecision.Blocked(
|
||||
$"Genshin lost foreground before {action}; native scan stopped without refocusing (foreground: {actual}).");
|
||||
}
|
||||
|
||||
return NativeScannerInputGuardDecision.Ready();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user