diff --git a/AutoMark/scripts/mods/AutoMark/mark/servo_skull_mark.lua b/AutoMark/scripts/mods/AutoMark/mark/servo_skull_mark.lua index 9bc8d42..dc8111a 100644 --- a/AutoMark/scripts/mods/AutoMark/mark/servo_skull_mark.lua +++ b/AutoMark/scripts/mods/AutoMark/mark/servo_skull_mark.lua @@ -28,65 +28,61 @@ local Vector3_distance = Vector3.distance local HACK_TAG_NAME = "hacking_over_here_companion" local CANCEL_INTERVAL = 0.5 --- set_tag() for off-LOS units is silently rejected: as HOST, SmartTagSystem:set_tag() runs --- _tagger_is_looking_at_target() (dot-0.75 aim cone + LOS sweep, from the game source) and --- returns before creating the tag. Since we hold the full source of the accept-branch --- (_generate_tag_id -> _create_tag_locally -> group limit check -> rpc to clients), the hook --- below reproduces it verbatim, minus the look check, for our flagged auto-hack targets only. +-- set_tag() for off-LOS targets is silently rejected: as HOST, SmartTagSystem:set_tag() runs +-- _tagger_is_looking_at_target() (dot-0.75 aim cone + LOS sweep, from game source) and returns +-- before creating the tag. Probes proved class-table hooks (CLASS registry, metatable, +-- metatable.__index) never land on this instance's call path — so we rawset an instance-level +-- shadow that beats every lookup chain. It replicates set_tag's host accept-branch +-- (_generate_tag_id -> _create_tag_locally -> group limit -> rpc to clients) minus the gate. local function ensure_automark_tag_hook() - if mod.omni_hack_tag_hooked then - return - end local smart_tag_system = context.smart_tag_system - if not smart_tag_system then + if not smart_tag_system or mod.omni_hack_patched_sys == smart_tag_system then return end - local cls = getmetatable(smart_tag_system) - if type(cls) == "table" and rawget(cls, "set_tag") == nil then - cls = rawget(cls, "__index") or cls + local orig_set_tag = smart_tag_system.set_tag + if type(orig_set_tag) ~= "function" then + return end - if type(cls) == "table" and cls.set_tag ~= nil then - mod:hook(cls, "set_tag", function(previous_hook, self, template_name, tagger_unit, target_unit, target_location) - mod.omni_hack_hook_count = (mod.omni_hack_hook_count or 0) + 1 - if template_name == HACK_TAG_NAME and mod_settings.debug_mode and not mod.omni_hack_hook_fired then - mod.omni_hack_hook_fired = true - local ext = target_unit and self._unit_extension_data[target_unit] - mod:diag("OMNI-HACK-DIAG hook FIRE is_server=", tostring(self._is_server), " flagged=", tostring(ext and ext._automark_hack_order), " has_ext=", tostring(ext ~= nil), " target=", tostring(target_unit), " loc=", tostring(target_location)) - end - if template_name == HACK_TAG_NAME and target_unit and self._is_server then - local target_extension = self._unit_extension_data[target_unit] - if target_extension and target_extension._automark_hack_order then - local ok, err = pcall(function() - local tag_id = self:_generate_tag_id() - local tag = self:_create_tag_locally(tag_id, template_name, tagger_unit, target_unit, target_location) - self:_server_check_tag_group_limit(tagger_unit, tag:group()) - local template_name_id = NetworkLookup.smart_tag_templates[template_name] - local tagger_game_object_id = Managers.state.unit_spawner:game_object_id(tagger_unit) - local target_game_object_id = Managers.state.unit_spawner:game_object_id(target_unit) - Managers.state.game_session:send_rpc_clients("rpc_set_smart_tag", tag_id, template_name_id, tagger_game_object_id, target_game_object_id, nil, target_location) - end) - if ok then - return - end - if mod_settings.debug_mode and not mod.omni_hack_taghook_err_logged then - mod.omni_hack_taghook_err_logged = true - mod:diag("OMNI-HACK-DIAG tag-branch replication FAILED:", tostring(err)) - end + local patched = {} + patched.set_tag = function(self, template_name, tagger_unit, target_unit, target_location) + if self ~= smart_tag_system then + return orig_set_tag(self, template_name, tagger_unit, target_unit, target_location) + end + mod.omni_hack_hook_count = (mod.omni_hack_hook_count or 0) + 1 + if template_name == HACK_TAG_NAME and target_unit and self._is_server and not patched.in_branch then + local target_extension = self._unit_extension_data[target_unit] + if target_extension and target_extension._automark_hack_order then + if mod_settings.debug_mode and not mod.omni_hack_hook_fired then + mod.omni_hack_hook_fired = true + mod:diag("OMNI-HACK-DIAG hook FIRE is_server=", tostring(self._is_server)) + end + patched.in_branch = true + local ok, err = pcall(function() + local tag_id = self:_generate_tag_id() + local tag = self:_create_tag_locally(tag_id, template_name, tagger_unit, target_unit, target_location) + self:_server_check_tag_group_limit(tagger_unit, tag:group()) + local template_name_id = NetworkLookup.smart_tag_templates[template_name] + local tagger_game_object_id = Managers.state.unit_spawner:game_object_id(tagger_unit) + local target_game_object_id = Managers.state.unit_spawner:game_object_id(target_unit) + Managers.state.game_session:send_rpc_clients("rpc_set_smart_tag", tag_id, template_name_id, tagger_game_object_id, target_game_object_id, nil, target_location) + end) + patched.in_branch = nil + if ok then + return + end + if mod_settings.debug_mode and not mod.omni_hack_taghook_err_logged then + mod.omni_hack_taghook_err_logged = true + mod:diag("OMNI-HACK-DIAG tag-branch replication FAILED:", tostring(err)) end end - return previous_hook(self, template_name, tagger_unit, target_unit, target_location) - end) - mod.omni_hack_tag_hooked = true - mod.omni_hack_hooked_ptr = tostring(cls.set_tag) - pcall(function() - cls.set_tag.omni_hook_marker = true - end) - if mod_settings.debug_mode then - mod:diag("OMNI-HACK-DIAG set_tag hook INSTALLED cls_ptr=", tostring(cls.set_tag), " sys_ptr=", tostring(smart_tag_system.set_tag), " same_sys_obj=", tostring(smart_tag_system == context.smart_tag_system)) end - elseif mod_settings.debug_mode and not mod.omni_hack_taghook_fail_logged then - mod.omni_hack_taghook_fail_logged = true - mod:diag("OMNI-HACK-DIAG set_tag hook FAILED to locate class, mt=", tostring(cls)) + return orig_set_tag(self, template_name, tagger_unit, target_unit, target_location) + end + rawset(smart_tag_system, "set_tag", patched.set_tag) + patched.set_tag.omni_hook_marker = true + mod.omni_hack_patched_sys = smart_tag_system + if mod_settings.debug_mode then + mod:diag("OMNI-HACK-DIAG set_tag instance-shadow INSTALLED marker=", tostring(rawget(smart_tag_system, "set_tag") == patched.set_tag)) end end @@ -367,7 +363,7 @@ function mod:auto_hack(dt, t, fixed_frame) if hack_check.ttl <= 0 then if mod_settings.debug_mode then local smart_tag_system = context.smart_tag_system - mod:diag(string.format("OMNI-HACK-DIAG tagcheck %s alive=%s tag_applied=%s skull_hacking=%s hooked=%s hookcalls=%s", tostring(hack_check.n), tostring(HEALTH_ALIVE[hack_check.unit] == true), tostring(smart_tag_system and smart_tag_system:unit_tag(hack_check.unit) ~= nil), tostring(mod:is_servo_skull_hacking()), tostring(mod.omni_hack_tag_hooked), tostring(mod.omni_hack_hook_count))) + mod:diag(string.format("OMNI-HACK-DIAG tagcheck %s alive=%s tag_applied=%s skull_hacking=%s hooked=%s hookcalls=%s", tostring(hack_check.n), tostring(HEALTH_ALIVE[hack_check.unit] == true), tostring(smart_tag_system and smart_tag_system:unit_tag(hack_check.unit) ~= nil), tostring(mod:is_servo_skull_hacking()), tostring(mod.omni_hack_patched_sys ~= nil), tostring(mod.omni_hack_hook_count))) end hack_check = nil end