-- Anti-cheat bypass: stops PAYDAY 2 from flagging the local player as a
-- "cheater" (the red CHEATER tag broadcast to other peers) by neutering the
-- verification functions the game uses to detect modified outfits/skills/bags.
--
-- Translated from parker-stephens/pirate-perfection (disable_anticheat.lua),
-- adapted to BLT's CloneClass / .orig restore pattern so it can be toggled.
--
-- NOTE: This only affects YOUR client telling the truth about itself. It is the
-- same approach used by every "non-modded lobby" / "disable anticheat" mod.

HT.AntiCheat = {}

HT.AntiCheat.enabled = false

-- Each entry: { class = <global class>, methods = { name = override_fn } }.
-- override_fn receives (self, ...) like a normal method. We store originals on
-- <class>.orig via CloneClass so we can restore on toggle-off.
local function buildOverrides()
    local TRUE = function() return true end
    local NOOP = function() end

    return {
        {
            class = "PlayerManager",
            methods = {
                verify_carry     = TRUE, -- can block the host from spawning bags
                verify_equipment = TRUE,
                verify_grenade   = TRUE,
            },
        },
        {
            class = "NetworkPeer",
            methods = {
                -- The single chokepoint for ALL cheater flagging: sets _cheater,
                -- broadcasts the "X cheated by..." system message, shows the red
                -- tag and can auto-kick. No-op = you are never flagged no matter
                -- which verify path (too many bags/assets/outfit) triggers.
                mark_cheater           = NOOP,
                begin_ticket_session   = TRUE,
                on_verify_ticket       = NOOP,
                end_ticket_session     = NOOP,
                change_ticket_callback = NOOP,
                verify_job             = NOOP,
                verify_character       = NOOP,
                verify_bag             = TRUE,
                -- Deploying more of a deployable than tweak_data.equipments.max_amount
                -- allows (which is exactly what Unlimited Equipment does) fails this
                -- check and self-marks you a cheater on your own machine. TRUE = never.
                verify_deployable      = TRUE,
                verify_grenade         = TRUE,
                verify_outfit          = NOOP,
                _verify_outfit_data    = NOOP,
                _verify_cheated_outfit = NOOP,
                _verify_content        = TRUE,
                tradable_verify_outfit = NOOP,
                on_verify_tradable_outfit = NOOP,
            },
        },
        {
            class = "NetworkMember",
            methods = { place_bag = TRUE },
        },
        {
            class = "GrenadeBase",
            methods = { check_time_cheat = TRUE },
        },
        {
            class = "ProjectileBase",
            methods = { check_time_cheat = TRUE },
        },
        -- Stop the game throwing away "illegal" loaded skill/infamy data, which
        -- is what makes silently-applied perks stick without being reverted.
        {
            class = "InfamyManager",
            methods = { _verify_loaded_data = NOOP },
        },
    }
end

function HT.AntiCheat:apply(value)
    for _, group in ipairs(buildOverrides()) do
        local cls = _G[group.class]
        if cls then
            pcall(function()
                _G.CloneClass(cls)
                for name, fn in pairs(group.methods) do
                    if value then
                        cls[name] = fn
                    elseif cls.orig and cls.orig[name] ~= nil then
                        cls[name] = cls.orig[name]
                    end
                end
            end)
        end
    end
end

function HT.AntiCheat:setEnabled(value, --[[optional]]showAlert)
    HT.AntiCheat.enabled = value
    HT:setSetting("enable_disable_anti_cheat", value)
    HT:updateJsonValue("configuration", "ut_item_configuration_toggle_disable_anti_cheat", value)

    HT.AntiCheat:apply(value)

    if showAlert == false then
        return
    end
    if value then
        HT:addAlert("Anti-cheat bypass enabled (cheater tag off)", HT.colors.success, false)
    else
        HT:addAlert("Anti-cheat bypass disabled", HT.colors.warning, false)
    end
end

-- Re-apply on load if the user left it enabled (safe to keep on permanently).
function HT.AntiCheat:restore()
    if HT:getSetting("enable_disable_anti_cheat") then
        HT.AntiCheat:apply(true)
        HT.AntiCheat.enabled = true
    end
end
