diff --git a/src/Poe2Trade.Navigation/MinimapCapture.cs b/src/Poe2Trade.Navigation/MinimapCapture.cs
index 97ec652..1ac80d6 100644
--- a/src/Poe2Trade.Navigation/MinimapCapture.cs
+++ b/src/Poe2Trade.Navigation/MinimapCapture.cs
@@ -38,8 +38,13 @@ public class MinimapCapture : IFrameConsumer, IDisposable
if (detected != _detectedMode)
{
var oldMode = _detectedMode;
+ var oldRegion = _detectedMode == MinimapMode.Overlay ? _config.OverlayRegion : _config.CornerRegion;
_detectedMode = detected;
- Log.Information("MODE SWITCH: {Old} → {New}", oldMode, _detectedMode);
+ 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);
}
@@ -56,7 +61,7 @@ public class MinimapCapture : IFrameConsumer, IDisposable
var frame = ProcessBgr(bgr);
if (frame == null) return;
- Log.Debug("Process: mode={Mode} cropSize={W}x{H} classifiedSize={CW}x{CH} wallSize={WW}x{WH}",
+ Log.Information("Process: mode={Mode} cropSize={W}x{H} classifiedSize={CW}x{CH} wallSize={WW}x{WH}",
_detectedMode, bgr.Width, bgr.Height,
frame.ClassifiedMat.Width, frame.ClassifiedMat.Height,
frame.WallMask.Width, frame.WallMask.Height);
diff --git a/src/Poe2Trade.Navigation/WorldMap.cs b/src/Poe2Trade.Navigation/WorldMap.cs
index 7d9018f..3e5c4a8 100644
--- a/src/Poe2Trade.Navigation/WorldMap.cs
+++ b/src/Poe2Trade.Navigation/WorldMap.cs
@@ -85,8 +85,8 @@ public class WorldMap : IDisposable
StitchWithConfidence(classifiedMat, _position, boosted: true, mode: mode);
if (_consecutiveMatchFails >= 30)
{
- Log.Information("Re-bootstrap: stitching at current position after {Fails} match failures ({Ms:F1}ms)",
- _consecutiveMatchFails, sw.Elapsed.TotalMilliseconds);
+ Log.Information("Re-bootstrap: mode={Mode} pos=({X:F1},{Y:F1}) frameSize={FS} walls={W} stitch={Ms:F1}ms",
+ mode, _position.X, _position.Y, classifiedMat.Width, wallCountAfter, sw.Elapsed.TotalMilliseconds);
_consecutiveMatchFails = 0;
}
else
@@ -114,13 +114,16 @@ public class WorldMap : IDisposable
_consecutiveMatchFails = 0;
LastMatchSucceeded = true;
+ var prevPos = _position;
_position = matched;
var stitchStart = sw.Elapsed.TotalMilliseconds;
StitchWithConfidence(classifiedMat, _position, boosted: false, mode: mode);
var stitchMs = sw.Elapsed.TotalMilliseconds - stitchStart;
- Log.Information("MatchAndStitch: dedup={Dedup:F1}ms match={Match:F1}ms stitch={Stitch:F1}ms total={Total:F1}ms",
- dedupMs, matchMs, stitchMs, sw.Elapsed.TotalMilliseconds);
+ var posDx = _position.X - prevPos.X;
+ var posDy = _position.Y - prevPos.Y;
+ Log.Information("MatchAndStitch: mode={Mode} pos=({X:F1},{Y:F1}) moved=({Dx:F1},{Dy:F1}) dedup={Dedup:F1}ms match={Match:F1}ms stitch={Stitch:F1}ms total={Total:F1}ms",
+ mode, _position.X, _position.Y, posDx, posDy, dedupMs, matchMs, stitchMs, sw.Elapsed.TotalMilliseconds);
return _position;
}
@@ -525,19 +528,53 @@ public class WorldMap : IDisposable
}
///
- /// Mode switch: clear frame dedup cache (frame sizes differ between modes)
- /// but keep template matching active — no blind bootstrap needed since scales match.
+ /// Mode switch: halve confidence around current position so old mode's weak walls
+ /// decay quickly while strong walls provide matching reference for the new mode.
+ /// No re-bootstrap stitch — let the first match find the correct position.
///
public void Rebootstrap()
{
Log.Information("Rebootstrap: frameCount={N} pos=({X:F1},{Y:F1}) matchFails={Fails} prevWallMask={Size}",
_frameCount, _position.X, _position.Y, _consecutiveMatchFails,
_prevWallMask != null ? $"{_prevWallMask.Width}x{_prevWallMask.Height}" : "null");
+
+ // Halve confidence around current position — weak walls get demoted,
+ // strong walls survive to help the new mode's first match find position
+ var halfClear = 250; // slightly larger than largest frame half (200)
+ var cx = (int)Math.Round(_position.X);
+ var cy = (int)Math.Round(_position.Y);
+ var x0 = Math.Max(0, cx - halfClear);
+ var y0 = Math.Max(0, cy - halfClear);
+ var w = Math.Min(_config.CanvasSize, cx + halfClear) - x0;
+ var h = Math.Min(_config.CanvasSize, cy + halfClear) - y0;
+ if (w > 0 && h > 0)
+ {
+ var rect = new Rect(x0, y0, w, h);
+ var confThreshold = (short)_config.ConfidenceThreshold;
+
+ using var confRoi = new Mat(_confidence, rect);
+ using var canvasRoi = new Mat(_canvas, rect);
+
+ var demoted = 0;
+ for (var row = 0; row < h; row++)
+ for (var col = 0; col < w; col++)
+ {
+ var conf = confRoi.At(row, col);
+ if (conf <= 0) continue;
+ conf = (short)(conf / 2);
+ confRoi.Set(row, col, conf);
+ if (conf < confThreshold && canvasRoi.At(row, col) == (byte)MapCell.Wall)
+ {
+ canvasRoi.Set(row, col, (byte)MapCell.Explored);
+ demoted++;
+ }
+ }
+ Log.Information("Rebootstrap: halved confidence in {W}x{H} area, demoted {Demoted} weak walls", w, h, demoted);
+ }
+
_prevWallMask?.Dispose();
_prevWallMask = null;
- // Force one re-bootstrap stitch so the new mode seeds walls on the canvas.
- // This triggers needsBootstrap=true (>= 30), skips dedup, stitches boosted.
- _consecutiveMatchFails = 30;
+ // Don't force re-bootstrap — let the match find the correct position first
}
public void Dispose()