minimap quickness
This commit is contained in:
parent
d80e723b94
commit
3087f9146e
3 changed files with 65 additions and 26 deletions
BIN
assets/toc_finish.png
Normal file
BIN
assets/toc_finish.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 995 B |
|
|
@ -13,6 +13,8 @@ public class MinimapCapture : IFrameConsumer, IDisposable
|
|||
private readonly IScreenCapture _backend; // kept for debug capture paths
|
||||
private int _modeCheckCounter = 9; // trigger mode detection on first frame
|
||||
private MinimapMode _detectedMode = MinimapMode.Overlay;
|
||||
private int _pendingModeCount; // consecutive detections of a different mode
|
||||
private MinimapMode _pendingMode;
|
||||
private MinimapFrame? _lastFrame;
|
||||
|
||||
public MinimapMode DetectedMode => _detectedMode;
|
||||
|
|
@ -31,23 +33,48 @@ public class MinimapCapture : IFrameConsumer, IDisposable
|
|||
/// </summary>
|
||||
public void Process(ScreenFrame screen)
|
||||
{
|
||||
// Auto-detect minimap mode every 10th frame via single pixel probe
|
||||
// Auto-detect minimap mode by checking orange player dot at both positions.
|
||||
// null = not in gameplay (loading/menu) → skip frame entirely.
|
||||
// Require 3 consecutive detections of a new mode to avoid transient flips.
|
||||
if (++_modeCheckCounter >= 10)
|
||||
{
|
||||
_modeCheckCounter = 0;
|
||||
var detected = DetectMinimapMode(screen);
|
||||
if (detected == null)
|
||||
{
|
||||
_pendingModeCount = 0;
|
||||
_lastFrame = null;
|
||||
return; // not in gameplay — skip frame
|
||||
}
|
||||
|
||||
if (detected != _detectedMode)
|
||||
{
|
||||
var oldMode = _detectedMode;
|
||||
var oldRegion = _detectedMode == MinimapMode.Overlay ? _config.OverlayRegion : _config.CornerRegion;
|
||||
_detectedMode = detected;
|
||||
var newRegion = _detectedMode == MinimapMode.Overlay ? _config.OverlayRegion : _config.CornerRegion;
|
||||
Log.Information("MODE SWITCH: {Old} → {New} | oldRegion=({OX},{OY},{OW}x{OH}) newRegion=({NX},{NY},{NW}x{NH})",
|
||||
oldMode, _detectedMode,
|
||||
oldRegion.X, oldRegion.Y, oldRegion.Width, oldRegion.Height,
|
||||
newRegion.X, newRegion.Y, newRegion.Width, newRegion.Height);
|
||||
ResetAdaptation();
|
||||
ModeChanged?.Invoke(_detectedMode);
|
||||
if (detected == _pendingMode)
|
||||
_pendingModeCount++;
|
||||
else
|
||||
{
|
||||
_pendingMode = detected.Value;
|
||||
_pendingModeCount = 1;
|
||||
}
|
||||
|
||||
if (_pendingModeCount >= 3)
|
||||
{
|
||||
var oldMode = _detectedMode;
|
||||
var oldRegion = _detectedMode == MinimapMode.Overlay ? _config.OverlayRegion : _config.CornerRegion;
|
||||
_detectedMode = detected.Value;
|
||||
var newRegion = _detectedMode == MinimapMode.Overlay ? _config.OverlayRegion : _config.CornerRegion;
|
||||
Log.Information("MODE SWITCH: {Old} → {New} | oldRegion=({OX},{OY},{OW}x{OH}) newRegion=({NX},{NY},{NW}x{NH})",
|
||||
oldMode, _detectedMode,
|
||||
oldRegion.X, oldRegion.Y, oldRegion.Width, oldRegion.Height,
|
||||
newRegion.X, newRegion.Y, newRegion.Width, newRegion.Height);
|
||||
ResetAdaptation();
|
||||
_pendingModeCount = 0;
|
||||
ModeChanged?.Invoke(_detectedMode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_pendingModeCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,19 +164,24 @@ public class MinimapCapture : IFrameConsumer, IDisposable
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detect minimap mode by sampling pixels at the corner minimap center.
|
||||
/// If the pixel is close to #DE581B (orange player dot), corner minimap is active.
|
||||
/// Detect minimap mode by sampling the orange player dot (#DE581B) at both
|
||||
/// the overlay center and corner center. Returns null if neither is found
|
||||
/// (loading screen, menu, map transition).
|
||||
/// </summary>
|
||||
private MinimapMode DetectMinimapMode(ScreenFrame screen)
|
||||
private MinimapMode? DetectMinimapMode(ScreenFrame screen)
|
||||
{
|
||||
var cx = _config.CornerCenterX;
|
||||
var cy = _config.CornerCenterY;
|
||||
if (IsOrangeDot(screen, _config.OverlayCenterX, _config.OverlayCenterY))
|
||||
return MinimapMode.Overlay;
|
||||
if (IsOrangeDot(screen, _config.CornerCenterX, _config.CornerCenterY))
|
||||
return MinimapMode.Corner;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Bounds check
|
||||
private static bool IsOrangeDot(ScreenFrame screen, int cx, int cy)
|
||||
{
|
||||
if (cx < 2 || cy < 2 || cx + 2 >= screen.Width || cy + 2 >= screen.Height)
|
||||
return _detectedMode;
|
||||
return false;
|
||||
|
||||
// Average a 5x5 patch worth of pixels
|
||||
double bSum = 0, gSum = 0, rSum = 0;
|
||||
var count = 0;
|
||||
for (var dy = -2; dy <= 2; dy++)
|
||||
|
|
@ -162,16 +194,13 @@ public class MinimapCapture : IFrameConsumer, IDisposable
|
|||
count++;
|
||||
}
|
||||
|
||||
var b = bSum / count;
|
||||
var g = gSum / count;
|
||||
var r = rSum / count;
|
||||
var g = gSum / count;
|
||||
var b = bSum / count;
|
||||
|
||||
// #DE581B → R=222, G=88, B=27
|
||||
const int tol = 60;
|
||||
if (Math.Abs(r - 222) < tol && Math.Abs(g - 88) < tol && Math.Abs(b - 27) < tol)
|
||||
return MinimapMode.Corner;
|
||||
|
||||
return MinimapMode.Overlay;
|
||||
return Math.Abs(r - 222) < tol && Math.Abs(g - 88) < tol && Math.Abs(b - 27) < tol;
|
||||
}
|
||||
|
||||
private Mat BuildWallMask(Mat hsv, Mat playerMask, bool sample = false)
|
||||
|
|
|
|||
|
|
@ -93,8 +93,17 @@ public class WorldMap : IDisposable
|
|||
// Warmup / re-bootstrap: stitch at current position to seed the canvas
|
||||
if (needsBootstrap)
|
||||
{
|
||||
// Don't consume warmup slots on empty frames (game still loading minimap)
|
||||
if (wallCountAfter < 50)
|
||||
{
|
||||
_frameCount--;
|
||||
Log.Information("Warmup waiting for minimap ({Ms:F1}ms)", sw.Elapsed.TotalMilliseconds);
|
||||
return _position;
|
||||
}
|
||||
|
||||
StitchWithConfidence(classifiedMat, _position, boosted: true, mode: mode);
|
||||
PaintExploredCircle(_position);
|
||||
LastMatchSucceeded = true; // signal caller to update viewport
|
||||
if (_consecutiveMatchFails >= 30)
|
||||
{
|
||||
Log.Information("Re-bootstrap: mode={Mode} pos=({X:F1},{Y:F1}) frameSize={FS} walls={W} stitch={Ms:F1}ms",
|
||||
|
|
@ -471,6 +480,7 @@ public class WorldMap : IDisposable
|
|||
_position = new MapPosition(_canvasSize / 2.0, _canvasSize / 2.0);
|
||||
_frameCount = 0;
|
||||
_consecutiveMatchFails = 0;
|
||||
LastMatchSucceeded = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -520,7 +530,7 @@ public class WorldMap : IDisposable
|
|||
|
||||
_prevWallMask?.Dispose();
|
||||
_prevWallMask = null;
|
||||
// Don't force re-bootstrap — let the match find the correct position first
|
||||
_frameCount = 0; // force re-warmup with new mode's data
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue