diff --git a/AutoMark/scripts/mods/AutoMark/mark/servo_skull_mark.lua b/AutoMark/scripts/mods/AutoMark/mark/servo_skull_mark.lua index b4516a6..5818e84 100644 --- a/AutoMark/scripts/mods/AutoMark/mark/servo_skull_mark.lua +++ b/AutoMark/scripts/mods/AutoMark/mark/servo_skull_mark.lua @@ -32,23 +32,49 @@ local CANCEL_INTERVAL = 0.5 -- set_tag() for off-LOS units is silently rejected because the game re-validates the tag -- through the target extension's forward-LOS _contextual_tag_template_name(); flag the single -- auto-hack target on its extension so the game's own validation accepts the order. -if not mod.omni_hack_spoof_hooked then - local spoof_class, spoof_class_name - for name, cls in pairs(CLASS) do - if type(cls) == "table" and rawget(cls, "_contextual_tag_template_name") ~= nil then - spoof_class, spoof_class_name = cls, name - break - end +-- the owning class is discovered lazily from a LIVE extension instance (the CLASS registry +-- scan at load time found nothing - extension classes aren't in it yet at that point). +local function ensure_automark_spoof_hook() + if mod.omni_hack_spoof_hooked then + return end - if spoof_class then - mod.omni_hack_spoof_hooked = true - mod.omni_hack_spoof_class = spoof_class_name - mod:hook(spoof_class, "_contextual_tag_template_name", function(previous_hook, self, player_unit, tag_name) + local smart_tag_system = context.smart_tag_system + local unit_extension_data = smart_tag_system and smart_tag_system._unit_extension_data + local _, any_ext = unit_extension_data and next(unit_extension_data) + if not any_ext then + return + end + local mt = getmetatable(any_ext) + local cls = mt + if cls and type(cls) == "table" and cls._contextual_tag_template_name == nil then + cls = rawget(cls, "__index") + end + if type(cls) == "table" and cls._contextual_tag_template_name ~= nil then + mod:hook(cls, "_contextual_tag_template_name", function(previous_hook, self, player_unit, tag_name) if tag_name == "companion_order" and self._automark_hack_order then return HACK_TAG_NAME end return previous_hook(self, player_unit, tag_name) end) + mod.omni_hack_spoof_hooked = true + mod.omni_hack_spoof_class = "lazy_class" + if mod_settings.debug_mode then + mod:diag("OMNI-HACK-DIAG spoof hook INSTALLED") + end + elseif mod_settings.debug_mode and not mod.omni_hack_spoof_fail_logged then + mod.omni_hack_spoof_fail_logged = true + local method_keys = {} + if type(cls) == "table" then + local seen = 0 + for k, v in pairs(cls) do + if type(k) == "string" and seen < 40 then + method_keys[#method_keys + 1] = k .. ":" .. type(v) + seen = seen + 1 + end + end + table.sort(method_keys) + end + mod:diag("OMNI-HACK-DIAG spoof HOOK FAILED mt=", tostring(mt), " cls=", tostring(cls), " instance_has_method=", tostring(any_ext._contextual_tag_template_name ~= nil), " cls_keys=", table.concat(method_keys, ",")) end end @@ -256,6 +282,7 @@ local function find_hackable_target_unit_omni() if not smart_tag_system or not player_unit then return end + ensure_automark_spoof_hook() local player_position = Unit_world_position(player_unit, 1) local selected_unit, selected_distance, selected_name, selected_extension