Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
bdab104
feat(targetbot): integrate HuntContext for enhanced targeting priorit…
mCodex Mar 10, 2026
b71bba3
fix(walking): reduce keyboard step threshold for improved responsiveness
mCodex Mar 10, 2026
f75b2c6
fix(pathfinding): enhance lookahead logic for goto action to improve …
mCodex Mar 10, 2026
517b9c7
feat(inspector): tabbed UI revamp + fix patterns always showing None
mCodex Mar 10, 2026
e04a01e
fix(cavebot): track lookahead target in regression detector to preven…
mCodex Mar 10, 2026
58795aa
feat(inspector): fix live tracking display + add Hunt Analyzer tabbed…
mCodex Mar 11, 2026
c7033aa
fix(cavebot): improve timeout and regression tolerance logic for navi…
mCodex Mar 11, 2026
3ca030a
fix(AttackBot, monster_inspector): add nil check for widget.id and fo…
mCodex Mar 11, 2026
02cfc44
fix(cavebot): reduce RECOVERY_IDLE_TIMEOUT from 5 min to 12s for quic…
mCodex Mar 11, 2026
8ad9d8c
fix(cavebot): enhance resetWaypointEngine to clear blacklists and pre…
mCodex Mar 11, 2026
9eb566c
fix(cavebot): enhance waypoint processing to skip blacklisted and flo…
mCodex Mar 11, 2026
27e7643
fix(monster_ai, monster_inspector, monster_patterns): enhance trackin…
mCodex Mar 11, 2026
1ad4b6b
fix(cavebot): improve handling of Z-level changes and waypoint proces…
mCodex Mar 11, 2026
d9d2c66
fix(monster_inspector): update formatting in live and patterns tab me…
mCodex Mar 11, 2026
d99a73b
fix(cavebot, waypoint_navigator): improve handling of floor changes a…
mCodex Mar 11, 2026
c33ab66
fix(cavebot): prevent oscillation near stairs by rejecting floor-chan…
mCodex Mar 11, 2026
72f15f3
fix(cavebot): enhance walking logic to prefer raw pathfinder directio…
mCodex Mar 11, 2026
d2cdf93
fix(cavebot): enhance lookahead logic to reject floor-change tiles an…
mCodex Mar 11, 2026
d00445d
refactor(AttackBot): improve UI structure and enhance control binding…
mCodex Mar 13, 2026
f5ed455
refactor(AttackBot, HealBot): streamline UI elements and enhance layo…
mCodex Mar 13, 2026
2928048
Enhance CaveBot navigation and combat mechanics
mCodex Mar 15, 2026
a1b116f
waypoint improvement
mCodex Mar 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions _Loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ loadCategory("tools_legacy", {
loadCategory("analytics", {
"analyzer",
"smart_hunt",
"hunt_context",
"spy_level",
"supplies",
"depositer_config",
Expand Down
305 changes: 266 additions & 39 deletions cavebot/actions.lua

Large diffs are not rendered by default.

294 changes: 235 additions & 59 deletions cavebot/cavebot.lua

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions cavebot/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ CaveBot.Config.setup = function()
add("walkDelay", "Walk delay", 10)
add("ignoreFields", "Ignore fields", true)
add("walkingDebug", "Walking debug", false) -- Disabled by default for performance
add("skipBlocked", "Skip blocked path", false)
add("mapClick", "Map click walking", true)
add("useDelay", "Delay after use", 400)
add("autoUseTools", "Auto use tools", true)
add("autoOpenDoors", "Auto open doors", true)
Expand Down
51 changes: 51 additions & 0 deletions cavebot/config_loader.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
-- config_loader.lua
-- Utilities to load and inspect cfg text using the v2 route pipeline.

CaveBot = CaveBot or {}

local ConfigLoader = {}

local WaypointSchema = CaveBot.WaypointSchema
local RouteCompiler = CaveBot.RouteCompiler
local RouteValidator = CaveBot.RouteValidator

local function trim(s)
if not s then return "" end
return (s:gsub("^%s+", ""):gsub("%s+$", ""))
end

function ConfigLoader.parseText(cfgText)
local nodes = {}
if type(cfgText) ~= "string" then
return nodes
end

local idx = 0
for line in cfgText:gmatch("[^\r\n]+") do
local raw = trim(line)
if raw ~= "" and not raw:match("^config:%s*") and not raw:match("^extensions:%s*") then
idx = idx + 1
local parsed = WaypointSchema and WaypointSchema.parseLine and WaypointSchema.parseLine(raw, idx) or nil
if parsed then
nodes[#nodes + 1] = parsed
end
end
end

return nodes
end

function ConfigLoader.loadFromText(cfgText)
local nodes = ConfigLoader.parseText(cfgText)
local route = RouteCompiler and RouteCompiler.compile and RouteCompiler.compile(nodes) or nil
local report = RouteValidator and RouteValidator.validate and RouteValidator.validate(route) or nil

return {
nodes = nodes,
route = route,
report = report,
}
end

CaveBot.ConfigLoader = ConfigLoader
return ConfigLoader
37 changes: 37 additions & 0 deletions cavebot/doors.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@ CaveBot.Extensions.OpenDoors = {}

local getClient = nExBot.Shared.getClient

local function chebyshev(a, b)
return math.max(math.abs(a.x - b.x), math.abs(a.y - b.y))
end

local function getDoorApproachPos(doorPos, playerPos)
local offsets = {
{x=0,y=-1},{x=1,y=0},{x=0,y=1},{x=-1,y=0},
{x=1,y=-1},{x=1,y=1},{x=-1,y=1},{x=-1,y=-1}
}
local best, bestDist = nil, math.huge
for i = 1, #offsets do
local p = {x = doorPos.x + offsets[i].x, y = doorPos.y + offsets[i].y, z = doorPos.z}
local d = chebyshev(playerPos, p)
if d < bestDist then
best = p
bestDist = d
end
end
return best
end

CaveBot.Extensions.OpenDoors.setup = function()
CaveBot.registerAction("OpenDoors", "#6be8e0", function(value, retries)
local pos = string.split(value, ",")
Expand All @@ -20,6 +41,22 @@ CaveBot.Extensions.OpenDoors.setup = function()
end

pos = {x=tonumber(pos[1]), y=tonumber(pos[2]), z=tonumber(pos[3])}
local playerPos = player:getPosition()
if not playerPos then return false end

if chebyshev(playerPos, pos) > 1 then
local maxDist = CaveBot.getMaxGotoDistance and CaveBot.getMaxGotoDistance() or 50
local approachPos = getDoorApproachPos(pos, playerPos)
local walkResult = CaveBot.walkTo(approachPos, maxDist, {
precision = 1,
allowFloorChange = false,
})
if walkResult then
CaveBot.delay(100)
return "retry"
end
return false
end

local Client = getClient()
local doorTile = (Client and Client.getTile) and Client.getTile(pos) or (g_map and g_map.getTile(pos))
Expand Down
76 changes: 76 additions & 0 deletions cavebot/loop_guard_v2.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
-- loop_guard_v2.lua
-- Ring-buffer waypoint-cycle detector.
-- Records each recovery-focus event and detects oscillation (A→B→A cycling).
-- Integrated into NavigationV2's recovery path to break infinite blacklist loops.

CaveBot = CaveBot or {}

local RING_SIZE = 8 -- slots in the circular buffer
local CYCLE_THRESHOLD = 3 -- same WP index seen >= this many times in window → cycling
local WINDOW_MS = 30000 -- 30-second detection window

local LoopGuard = {
_ring = {}, -- circular buffer: each slot = { idx=int, t=ms }
_head = 0, -- index of last-written slot (1-based, wraps mod RING_SIZE)
_size = 0, -- number of filled slots (up to RING_SIZE)
activations = 0, -- cumulative count of cycle-break escalations
lastActivation = 0, -- `now` timestamp of the last escalation
COOLDOWN = 5000, -- ms minimum between consecutive escalations
}

-- Record that NavigationV2 recovery just focused WP at `idx`.
function LoopGuard.recordFocus(idx)
if not idx then return end
LoopGuard._head = (LoopGuard._head % RING_SIZE) + 1
LoopGuard._ring[LoopGuard._head] = { idx = idx, t = now }
if LoopGuard._size < RING_SIZE then
LoopGuard._size = LoopGuard._size + 1
end
end

-- Count appearances of `idx` in the ring within the last WINDOW_MS.
local function countInWindow(idx)
local cutoff = now - WINDOW_MS
local n = 0
for i = 1, LoopGuard._size do
local slot = LoopGuard._ring[((LoopGuard._head - i) % RING_SIZE) + 1]
if slot and slot.t >= cutoff and slot.idx == idx then
n = n + 1
end
end
return n
end

-- Returns true if focusing `idx` again would indicate a repeating cycle.
function LoopGuard.isCycling(idx)
if not idx then return false end
return countInWindow(idx) >= CYCLE_THRESHOLD
end

-- Clear the ring buffer (call on config change or confirmed route advance).
function LoopGuard.reset()
LoopGuard._ring = {}
LoopGuard._head = 0
LoopGuard._size = 0
end

-- Record that a cycle was broken via blacklist escalation (for cooldown tracking).
function LoopGuard.markActivation()
LoopGuard.activations = LoopGuard.activations + 1
LoopGuard.lastActivation = now
end

-- True if still within cooldown period after the last escalation.
function LoopGuard.isCoolingDown()
return (now - LoopGuard.lastActivation) < LoopGuard.COOLDOWN
end

function LoopGuard.getMetrics()
return {
activations = LoopGuard.activations,
lastActivation = LoopGuard.lastActivation,
}
end

CaveBot.LoopGuard = LoopGuard
return LoopGuard
Loading