refactor: debug overlay abandons the UIHud element pipeline entirely — draws direct to level_world screen gui (Gui.rect dark panel + Gui.slug_text lines) per FpsDoctor's proven pattern in the same mods dir: per-world gui handle validation, pcall+backoff, 5Hz rebuild, RESOLUTION_LOOKUP scaling; X/Y now anchor top-left; deletes hud_element_debug.lua + require-path/injection/recreate machinery; works hub/MeatGrinder/mission, applies live
This commit is contained in:
@@ -73,9 +73,9 @@ local localization = {
|
|||||||
["zh-tw"] = "除錯HUD面板",
|
["zh-tw"] = "除錯HUD面板",
|
||||||
},
|
},
|
||||||
debug_hud_tooltip = {
|
debug_hud_tooltip = {
|
||||||
en = "Shows a live text panel (left side of the screen) with current mark targets, cooldowns, skull/dog state and server accept results. Applied at the next mission start.",
|
en = "Shows a live overlay panel (dark box, top-left by default) with current mark targets, cooldowns, skull/dog state and server accept results. Applies immediately, works in hub, Meat Grinder and missions.",
|
||||||
["zh-cn"] = "在屏幕左侧显示实时文本面板:当前标记目标、冷却、骷髅/狗状态及服务器接受结果。下个任务开始时生效。",
|
["zh-cn"] = "显示实时悬浮面板(深色底,默认左上):当前标记目标、冷却、骷髅/狗状态及服务器接受结果。立即生效,大厅/训练场/任务均可用。",
|
||||||
["zh-tw"] = "在螢幕左側顯示即時文字面板:目前標記目標、冷卻、骷髏/狗狀態及伺服器接受結果。下個任務開始時生效。",
|
["zh-tw"] = "顯示即時浮動面板(深色底,預設左上):目前標記目標、冷卻、骷髏/狗狀態及伺服器接受結果。立即生效,大廳/訓練場/任務均可用。",
|
||||||
},
|
},
|
||||||
debug_hud_x = {
|
debug_hud_x = {
|
||||||
en = "Overlay X",
|
en = "Overlay X",
|
||||||
@@ -93,9 +93,9 @@ local localization = {
|
|||||||
["zh-tw"] = "距螢幕左緣的距離(UI像素),立即生效。",
|
["zh-tw"] = "距螢幕左緣的距離(UI像素),立即生效。",
|
||||||
},
|
},
|
||||||
debug_hud_y_tooltip = {
|
debug_hud_y_tooltip = {
|
||||||
en = "Vertical offset from screen middle (positive = down), in UI pixels. Applies immediately.",
|
en = "Distance from the top edge of the screen, in UI pixels. Applies immediately.",
|
||||||
["zh-cn"] = "相对屏幕垂直中线的偏移(正值向下),单位UI像素,立即生效。",
|
["zh-cn"] = "距屏幕顶部的距离(UI像素),立即生效。",
|
||||||
["zh-tw"] = "相對螢幕垂直中線的偏移(正值向下),單位UI像素,立即生效。",
|
["zh-tw"] = "距螢幕頂緣的距離(UI像素),立即生效。",
|
||||||
},
|
},
|
||||||
omni_mark = {
|
omni_mark = {
|
||||||
en = "360° Marking",
|
en = "360° Marking",
|
||||||
|
|||||||
@@ -1,104 +1,66 @@
|
|||||||
-- AutoMark debug HUD (mod side): injects the HUD element definition at mission
|
-- AutoMark debug HUD (mod side): a live status overlay drawn straight onto the
|
||||||
-- HUD creation and feeds it a rebuilt status line buffer at 5 Hz.
|
-- level world's screen gui (the pattern FpsDoctor uses in this very mods folder).
|
||||||
|
-- Deliberately avoids the UIHud element pipeline: direct Gui.rect + Gui.slug_text
|
||||||
|
-- with per-world gui handle validation, pcall-guarded with backoff on failure.
|
||||||
local mod = get_mod("AutoMark")
|
local mod = get_mod("AutoMark")
|
||||||
local mod_settings = mod.settings
|
local mod_settings = mod.settings
|
||||||
local TAG_NAMES = mod.TAG_NAMES
|
local TAG_NAMES = mod.TAG_NAMES
|
||||||
local Managers = Managers
|
local Managers = Managers
|
||||||
|
local World = World
|
||||||
|
local Gui = Gui
|
||||||
|
local Vector3 = Vector3
|
||||||
|
local Vector2 = Vector2
|
||||||
|
local Color = Color
|
||||||
|
local RESOLUTION_LOOKUP = RESOLUTION_LOOKUP
|
||||||
local ScriptUnit_extension = ScriptUnit.extension
|
local ScriptUnit_extension = ScriptUnit.extension
|
||||||
|
|
||||||
mod.debug_hud_last = {}
|
mod.debug_hud_last = {}
|
||||||
|
|
||||||
mod:diag("OMNI-HUD load: settings debug_hud=", tostring(mod_settings.debug_hud), " chat=", tostring(mod_settings.debug_chat), " debug=", tostring(mod_settings.debug_mode))
|
mod:diag("OMNI-HUD load: settings debug_hud=", tostring(mod_settings.debug_hud), " chat=", tostring(mod_settings.debug_chat), " debug=", tostring(mod_settings.debug_mode))
|
||||||
|
|
||||||
local ELEMENT_CLASS_NAME = "HudElementAutoMarkDebug"
|
local FONT_TYPE = "arial"
|
||||||
local ELEMENT_FILENAME = "AutoMark/scripts/mods/AutoMark/ui/hud_element_debug"
|
local REBUILD_INTERVAL = 0.2
|
||||||
|
local DRAW_FAIL_BACKOFF = 120
|
||||||
|
|
||||||
-- the game HUD requires element files through the game require system; without
|
local gui, gui_world, font_path
|
||||||
-- registering here, require(ELEMENT_FILENAME) from UIHud._add_element never finds
|
local fail_cooldown = 0
|
||||||
-- the mod file (DMF loads mod scripts through its own file loader, not package.path)
|
local rebuild_acc = REBUILD_INTERVAL
|
||||||
mod:add_require_path(ELEMENT_FILENAME)
|
local first_draw_logged = false
|
||||||
|
|
||||||
mod:hook("UIHud", "init",
|
local function level_world()
|
||||||
function(func, self, elements, visibility_groups, params)
|
local world_manager = Managers.world
|
||||||
if elements then
|
if world_manager and world_manager:has_world("level_world") then
|
||||||
if not mod.omni_hud_init_count then
|
return world_manager:world("level_world")
|
||||||
mod.omni_hud_init_count = 0
|
|
||||||
end
|
end
|
||||||
mod.omni_hud_init_count = mod.omni_hud_init_count + 1
|
return nil
|
||||||
mod:diag("OMNI-HUD init#", mod.omni_hud_init_count, "debug_hud=", tostring(mod_settings.debug_hud), " elements=", tostring(#elements))
|
end
|
||||||
local idx = nil
|
|
||||||
for i = 1, #elements do
|
|
||||||
if elements[i].class_name == ELEMENT_CLASS_NAME then
|
|
||||||
idx = i
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if mod_settings.debug_hud and not idx then
|
|
||||||
elements[#elements + 1] = {
|
|
||||||
class_name = ELEMENT_CLASS_NAME,
|
|
||||||
filename = ELEMENT_FILENAME,
|
|
||||||
use_hud_scale = true,
|
|
||||||
visibility_groups = { "alive", "dead" },
|
|
||||||
}
|
|
||||||
if not mod.debug_hud_inject_logged then
|
|
||||||
mod.debug_hud_inject_logged = true
|
|
||||||
mod:diag("OMNI-HUD inject: ADDED")
|
|
||||||
end
|
|
||||||
elseif not mod_settings.debug_hud and idx then
|
|
||||||
table.remove(elements, idx)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return func(self, elements, visibility_groups, params)
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- live toggling: UIHud init only runs on HUD creation, so when the setting flips we
|
local function ensure_gui()
|
||||||
-- rebuild the HUD on the spot (pattern borrowed from NumericUI's recreate_hud)
|
local world = level_world()
|
||||||
local recreate_timer = 0
|
if not world then
|
||||||
local last_debug_hud = nil
|
gui = nil
|
||||||
|
gui_world = nil
|
||||||
mod.update = function (dt)
|
font_path = nil
|
||||||
local want = mod_settings.debug_hud and true or false
|
return nil
|
||||||
if last_debug_hud == nil then
|
|
||||||
last_debug_hud = want
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
if gui and gui_world == world then
|
||||||
if want ~= last_debug_hud then
|
return gui
|
||||||
last_debug_hud = want
|
|
||||||
recreate_timer = 0.5
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
gui = World.create_screen_gui(world, "immediate")
|
||||||
|
gui_world = world
|
||||||
|
font_path = nil
|
||||||
|
return gui
|
||||||
|
end
|
||||||
|
|
||||||
if recreate_timer <= 0 then
|
local function ensure_font()
|
||||||
return
|
if font_path then
|
||||||
|
return font_path
|
||||||
end
|
end
|
||||||
|
local font_data = Managers.font and Managers.font:data_by_type(FONT_TYPE)
|
||||||
recreate_timer = recreate_timer - dt
|
if font_data then
|
||||||
if recreate_timer > 0 then
|
font_path = font_data.path
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local ok, err = pcall(function()
|
|
||||||
local ui_manager = Managers.ui
|
|
||||||
local hud = ui_manager and ui_manager._hud
|
|
||||||
if not hud or not hud._element_definitions or not hud._visibility_groups then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local player = Managers.player and Managers.player:local_player(1)
|
|
||||||
if not player then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local elements = hud._element_definitions
|
|
||||||
local visibility_groups = hud._visibility_groups
|
|
||||||
hud:destroy()
|
|
||||||
ui_manager:create_player_hud(player:peer_id(), player:local_player_id(), elements, visibility_groups)
|
|
||||||
mod:diag("OMNI-HUD: live recreate, debug_hud ->", tostring(want))
|
|
||||||
end)
|
|
||||||
if not ok then
|
|
||||||
mod:diag("OMNI-HUD: live recreate FAILED:", tostring(err))
|
|
||||||
end
|
end
|
||||||
|
return font_path
|
||||||
end
|
end
|
||||||
|
|
||||||
local function unit_breed_name(unit)
|
local function unit_breed_name(unit)
|
||||||
@@ -170,23 +132,108 @@ function mod:build_debug_hud_lines()
|
|||||||
return buf
|
return buf
|
||||||
end
|
end
|
||||||
|
|
||||||
local hud_build_timer = 0
|
local cached = { x = 0, top_y = 0, line_h = 0, font_px = 0, panel_w = 0, panel_h = 0, pad = 0 }
|
||||||
mod:hook_safe(CLASS.PlayerUnitSmartTargetingExtension, "fixed_update",
|
|
||||||
function(self, unit, dt, t, fixed_frame)
|
local function text_width(gui_handle, font, font_px, text)
|
||||||
if not mod_settings.debug_hud or not mod_settings.toggle_mod then
|
local ok, min, max = pcall(Gui.slug_text_extents, gui_handle, text, font, font_px)
|
||||||
return
|
if ok and min and max then
|
||||||
|
return max[1] - min[1]
|
||||||
end
|
end
|
||||||
if self._player.viewport_name ~= "player1" then
|
return #text * font_px * 0.55
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_inner(dt)
|
||||||
|
local gui_handle = ensure_gui()
|
||||||
|
if not gui_handle then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
hud_build_timer = hud_build_timer - dt
|
local font = ensure_font()
|
||||||
if hud_build_timer <= 0 then
|
if not font then
|
||||||
hud_build_timer = 0.2
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local buf = mod.debug_hud_last
|
||||||
|
local n = #buf
|
||||||
|
if n == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local r = RESOLUTION_LOOKUP
|
||||||
|
local scale = (r and r.scale) or 1.0
|
||||||
|
local sw = (r and r.width) or 1920
|
||||||
|
|
||||||
|
local font_px = math.max(8, math.floor(16 * scale + 0.5))
|
||||||
|
local line_h = math.floor(20 * scale + 0.5)
|
||||||
|
local pad = math.floor(6 * scale + 0.5)
|
||||||
|
|
||||||
|
local margin_x = math.floor((mod_settings.debug_hud_x or 25) * scale + 0.5)
|
||||||
|
local margin_y = math.floor((mod_settings.debug_hud_y or 24) * scale + 0.5)
|
||||||
|
|
||||||
|
local maxw = 0
|
||||||
|
for i = 1, n do
|
||||||
|
local w = text_width(gui_handle, font, font_px, buf[i])
|
||||||
|
if w > maxw then
|
||||||
|
maxw = w
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
cached.x = math.min(margin_x, math.max(0, sw - maxw - pad * 2 - 8))
|
||||||
|
cached.top_y = margin_y
|
||||||
|
cached.line_h = line_h
|
||||||
|
cached.font_px = font_px
|
||||||
|
cached.panel_w = maxw + pad * 2
|
||||||
|
cached.panel_h = n * line_h + pad * 2
|
||||||
|
cached.pad = pad
|
||||||
|
|
||||||
|
Gui.rect(gui_handle,
|
||||||
|
Vector3(cached.x - pad, cached.top_y - pad, 899),
|
||||||
|
Vector2(cached.panel_w, cached.panel_h),
|
||||||
|
Color(165, 10, 10, 10))
|
||||||
|
|
||||||
|
for i = 1, n do
|
||||||
|
local line = buf[i]
|
||||||
|
local col = Color(235, 235, 220, 150)
|
||||||
|
if line:find("REJECTED") or line:find("OFF") or line:find("FAIL") then
|
||||||
|
col = Color(235, 255, 110, 100)
|
||||||
|
elseif i == 1 then
|
||||||
|
col = Color(235, 140, 235, 255)
|
||||||
|
end
|
||||||
|
Gui.slug_text(gui_handle, line, font, font_px, Vector3(cached.x, cached.top_y + line_h * (i - 1), 900), nil, col)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not first_draw_logged then
|
||||||
|
first_draw_logged = true
|
||||||
|
mod:diag("OMNI-HUD first draw OK, lines=", n)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw(dt)
|
||||||
|
if fail_cooldown > 0 then
|
||||||
|
fail_cooldown = fail_cooldown - 1
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local ok, err = pcall(draw_inner, dt)
|
||||||
|
if not ok then
|
||||||
|
gui, gui_world, font_path = nil, nil, nil
|
||||||
|
fail_cooldown = DRAW_FAIL_BACKOFF
|
||||||
|
mod:diag("OMNI-HUD draw failed, backing off:", tostring(err))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mod.update = function (dt)
|
||||||
|
if not mod_settings.debug_hud or not mod_settings.toggle_mod then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
rebuild_acc = rebuild_acc + dt
|
||||||
|
if rebuild_acc >= REBUILD_INTERVAL then
|
||||||
|
rebuild_acc = 0
|
||||||
local ok, err = pcall(mod.build_debug_hud_lines, mod)
|
local ok, err = pcall(mod.build_debug_hud_lines, mod)
|
||||||
if not ok and mod_settings.debug_mode and not mod.debug_hud_err_logged then
|
if not ok then
|
||||||
mod.debug_hud_err_logged = true
|
|
||||||
mod:diag("OMNI-HUD builder error:", tostring(err))
|
mod:diag("OMNI-HUD builder error:", tostring(err))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
|
||||||
|
draw(dt)
|
||||||
|
end
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
-- AutoMark debug HUD element: plain-text live status panel (fork feature).
|
|
||||||
-- Instantiated by the game HUD pipeline (UIHud._add_element requires this file
|
|
||||||
-- by definition.filename). Content is produced by AutoMark mod side
|
|
||||||
-- (ui/debug_hud.lua -> mod.debug_hud_last) so this file stays dumb.
|
|
||||||
local UIWorkspaceSettings = require("scripts/settings/ui/ui_workspace_settings")
|
|
||||||
local UIWidget = require("scripts/managers/ui/ui_widget")
|
|
||||||
|
|
||||||
require("scripts/foundation/utilities/color")
|
|
||||||
|
|
||||||
local mod = get_mod("AutoMark")
|
|
||||||
|
|
||||||
local HudElementAutoMarkDebug = class("HudElementAutoMarkDebug", "HudElementBase")
|
|
||||||
|
|
||||||
local panel_size = { 860, 800 }
|
|
||||||
|
|
||||||
local scenegraph_definition = {
|
|
||||||
screen = UIWorkspaceSettings.screen,
|
|
||||||
panel = {
|
|
||||||
horizontal_alignment = "left",
|
|
||||||
parent = "screen",
|
|
||||||
vertical_alignment = "middle",
|
|
||||||
size = panel_size,
|
|
||||||
position = {
|
|
||||||
25,
|
|
||||||
0,
|
|
||||||
10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
local widget_definitions = {
|
|
||||||
automark_debug = UIWidget.create_definition({
|
|
||||||
{
|
|
||||||
pass_type = "text",
|
|
||||||
style_id = "debug_text",
|
|
||||||
value_id = "debug_text",
|
|
||||||
style = {
|
|
||||||
drop_shadow = true,
|
|
||||||
font_size = 19,
|
|
||||||
font_type = "proxima_nova_bold",
|
|
||||||
horizontal_alignment = "left",
|
|
||||||
vertical_alignment = "top",
|
|
||||||
text_horizontal_alignment = "left",
|
|
||||||
text_vertical_alignment = "top",
|
|
||||||
line_spacing = 1.2,
|
|
||||||
size = panel_size,
|
|
||||||
offset = {
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
},
|
|
||||||
text_color = Color.terminal_text_header(255, true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, "panel"),
|
|
||||||
}
|
|
||||||
|
|
||||||
HudElementAutoMarkDebug.init = function (self, parent, draw_layer, start_scale)
|
|
||||||
HudElementAutoMarkDebug.super.init(self, parent, draw_layer, start_scale, {
|
|
||||||
scenegraph_definition = scenegraph_definition,
|
|
||||||
widget_definitions = widget_definitions,
|
|
||||||
})
|
|
||||||
self._rebuild_time = 0
|
|
||||||
self._last_text = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
HudElementAutoMarkDebug.update = function (self, dt, t, ui_renderer, render_settings, input_service)
|
|
||||||
HudElementAutoMarkDebug.super.update(self, dt, t, ui_renderer, render_settings, input_service)
|
|
||||||
|
|
||||||
self._rebuild_time = self._rebuild_time - dt
|
|
||||||
if self._rebuild_time > 0 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
self._rebuild_time = 0.2
|
|
||||||
|
|
||||||
local panel = self._ui_scenegraph and self._ui_scenegraph.panel
|
|
||||||
if panel and panel.local_position then
|
|
||||||
local lp = panel.local_position
|
|
||||||
local x = mod.settings.debug_hud_x or 25
|
|
||||||
local y = mod.settings.debug_hud_y or 0
|
|
||||||
if lp[1] ~= x or lp[2] ~= y then
|
|
||||||
lp[1] = x
|
|
||||||
lp[2] = y
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local buf = mod.debug_hud_last
|
|
||||||
local text = table.concat(buf, "\n")
|
|
||||||
|
|
||||||
if text ~= self._last_text then
|
|
||||||
self._last_text = text
|
|
||||||
local widget = self._widgets_by_name.automark_debug
|
|
||||||
if widget then
|
|
||||||
widget.content.debug_text = text
|
|
||||||
widget.dirty = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return HudElementAutoMarkDebug
|
|
||||||
Reference in New Issue
Block a user