feat: overlay TARGETS table — per-candidate breed/distance/fate captured in find_auto_mark_target_unit (zero-cost unless debug_hud/debug_mode on): enumeration records unit->entry, omni_reject attributes first reject reason to current candidate, marked unit shows MARKED, winner shows PING; overlay renders nearest-10 by distance with pass name, green=PING/MARKED/ACCEPTED, gray=not_visible, rejects summary line dropped (redundant)

This commit is contained in:
2026-10-04 10:50:04 -04:00
parent fede4eb18f
commit ea76cb9067
2 changed files with 62 additions and 5 deletions
@@ -61,10 +61,15 @@ local AIM_CHECK_MAX_HITS = 64
local AIM_CHECK_MIN_RADIUS = 1 local AIM_CHECK_MIN_RADIUS = 1
local AIM_CHECK_RADIUS_PER_METER = 0.052 local AIM_CHECK_RADIUS_PER_METER = 0.052
local omni_rejects = nil local omni_rejects = nil
local omni_hud_units = nil
local omni_hud_cur = nil
local function omni_reject(reason) local function omni_reject(reason)
if omni_rejects then if omni_rejects then
omni_rejects[reason] = (omni_rejects[reason] or 0) + 1 omni_rejects[reason] = (omni_rejects[reason] or 0) + 1
end end
if omni_hud_cur and omni_hud_cur.res == "ok" then
omni_hud_cur.res = reason
end
end end
-- Params -- Params
@@ -592,6 +597,12 @@ function mod:find_auto_mark_target_unit(min_range, max_range, tag_name, tag_cont
end end
local ray_origin, forward, right, up = smart_targeting_extension:_targeting_parameters() local ray_origin, forward, right, up = smart_targeting_extension:_targeting_parameters()
local hits, num_hits, hits_are_units local hits, num_hits, hits_are_units
local hud_capture = mod_settings.debug_hud or mod_settings.debug_mode
omni_hud_units = nil
if hud_capture then
omni_hud_units = {}
mod.omni_candidates = nil
end
if omni_mark then if omni_mark then
-- enumerate smart-taggable units directly; physics sphere sweeps get swamped by world geometry actors -- enumerate smart-taggable units directly; physics sphere sweeps get swamped by world geometry actors
hits = {} hits = {}
@@ -602,9 +613,18 @@ function mod:find_auto_mark_target_unit(min_range, max_range, tag_name, tag_cont
for unit, smart_tag_extension in pairs(unit_extension_data) do for unit, smart_tag_extension in pairs(unit_extension_data) do
if HEALTH_ALIVE[unit] and smart_tag_extension._target_type == "breed" then if HEALTH_ALIVE[unit] and smart_tag_extension._target_type == "breed" then
local position = Unit_world_position(unit, 1) local position = Unit_world_position(unit, 1)
if Vector3_distance_squared(position, ray_origin) <= max_range_squared then local dist_squared = Vector3_distance_squared(position, ray_origin)
if dist_squared <= max_range_squared then
num_hits = num_hits + 1 num_hits = num_hits + 1
hits[num_hits] = { unit = unit, position = position } hits[num_hits] = { unit = unit, position = position }
if omni_hud_units then
local unit_data_extension = ScriptUnit_extension(unit, "unit_data_system")
local breed = unit_data_extension and unit_data_extension._breed
local entry = { unit = unit, b = breed and breed.name or "?", d = math.sqrt(dist_squared), res = "ok" }
omni_hud_units[unit] = entry
mod.omni_candidates = mod.omni_candidates or {}
mod.omni_candidates[#mod.omni_candidates + 1] = entry
end
end end
end end
end end
@@ -635,6 +655,10 @@ function mod:find_auto_mark_target_unit(min_range, max_range, tag_name, tag_cont
end end
if not hits or num_hits <= 0 then if not hits or num_hits <= 0 then
if hud_capture then
mod.omni_candidates = mod.omni_candidates or {}
mod.omni_candidates_pass = tag_name
end
return return
end end
@@ -706,8 +730,10 @@ function mod:find_auto_mark_target_unit(min_range, max_range, tag_name, tag_cont
end end
hit_unit = Actor_unit(hit_actor) hit_unit = Actor_unit(hit_actor)
end end
-- ignore player unit, already marked unit and dead unit omni_hud_cur = omni_hud_units and omni_hud_units[hit_unit]
if hit_unit == player_unit or hit_unit == marked_unit or canceled_units[hit_unit] or not HEALTH_ALIVE[hit_unit] then if omni_hud_cur and hit_unit == marked_unit then
omni_hud_cur.res = "MARKED"
elseif hit_unit == player_unit or hit_unit == marked_unit or canceled_units[hit_unit] or not HEALTH_ALIVE[hit_unit] then
omni_reject("skip_player_dead") omni_reject("skip_player_dead")
goto continue goto continue
end end
@@ -857,6 +883,15 @@ elseif tag_name == TAG_NAMES.SERVO_SKULL_TAG then
::continue:: ::continue::
end end
omni_hud_cur = nil
if omni_hud_units and best_unit then
local entry = omni_hud_units[best_unit]
if entry and entry.res == "ok" then
entry.res = "PING"
end
end
omni_hud_units = nil
if omni_rejects then if omni_rejects then
local parts = {} local parts = {}
for k, v in pairs(omni_rejects) do for k, v in pairs(omni_rejects) do
@@ -869,6 +904,7 @@ elseif tag_name == TAG_NAMES.SERVO_SKULL_TAG then
end end
mod.omni_last = { tag_name = tag_name, best = best_unit_breed_name, cands = num_hits } mod.omni_last = { tag_name = tag_name, best = best_unit_breed_name, cands = num_hits }
mod.omni_candidates_pass = tag_name
if best_unit ~= marked_unit then if best_unit ~= marked_unit then
return best_unit, best_unit_tag, best_unit_is_dormant_daemonhost return best_unit, best_unit_tag, best_unit_is_dormant_daemonhost
@@ -119,8 +119,25 @@ function mod:build_debug_hud_lines()
local last = mod.omni_last local last = mod.omni_last
if last then if last then
buf[#buf + 1] = string.format("PICK[%s] best=%s cands=%s", tostring(last.tag_name), tostring(last.best), tostring(last.cands)) buf[#buf + 1] = string.format("PICK[%s] best=%s cands=%s", tostring(last.tag_name), tostring(last.best), tostring(last.cands))
if mod.omni_last_rejects then end
buf[#buf + 1] = " rejects: " .. mod.omni_last_rejects
local cands = mod.omni_candidates
if cands then
local sorted = {}
for i = 1, #cands do
sorted[i] = cands[i]
end
table.sort(sorted, function(a, b)
return (a.d or math.huge) < (b.d or math.huge)
end)
local shown = math.min(10, #sorted)
buf[#buf + 1] = string.format("TARGETS[%s] %d (nearest %d)", tostring(mod.omni_candidates_pass), #sorted, shown)
if #sorted == 0 then
buf[#buf + 1] = " none in range"
end
for i = 1, shown do
local e = sorted[i]
buf[#buf + 1] = string.format(" %-24s %4dm %s", e.b, math.floor(e.d + 0.5), e.res == "ok" and "candidate" or e.res)
end end
end end
@@ -196,6 +213,10 @@ local function draw_inner(dt)
local col = Color(235, 235, 220, 150) local col = Color(235, 235, 220, 150)
if line:find("REJECTED") or line:find("OFF") or line:find("FAIL") then if line:find("REJECTED") or line:find("OFF") or line:find("FAIL") then
col = Color(235, 255, 110, 100) col = Color(235, 255, 110, 100)
elseif line:find("PING") or line:find("MARKED") or line:find("ACCEPTED") then
col = Color(235, 120, 255, 130)
elseif line:find("not_visible") then
col = Color(200, 150, 150, 160)
elseif i == 1 then elseif i == 1 then
col = Color(235, 140, 235, 255) col = Color(235, 140, 235, 255)
end end