Античит для синглплеера

Добавлен , опубликован
Способ реализации:
Lua
Версия Warcraft:
Простая и лёгкая система, позволяющая поймать за руку игрока, использующего оригинальные чит-коды в одиночной игре. И также просто и легко обнаруживается в коде карты.

Принцип работы

Для работы системы используются три триггера. Первые два отслеживают события TEXT_CHANGED и ENTER для фрейма типа Edit Box, третий триггер — вспомогательный, он нужен для перерегистрации событий фрейма для основных триггеров при загрузке сохраненной игры (иначе фрейм ивенты будут потеряны). Весь текст, введённый игроком, сравнивается с содержимым таблицы чит-кодов, и найденное совпадение расценивается как ввод чит-кода.

Установка

  1. Переключить карту в режим Lua, если ещё не.
  2. Вставить код в карту.
  3. Вызвать метод AntiCheat:init(debugMode). Аргумент debugMode используется для включения/отключения дебаг сообщений (true/false).

Настройка и управление

  1. Реакция на ввод чита вынесена в функцию AntiCheat:punish(cheat), и может быть изменена по желанию пользователя. Функция принимает строку с обнаруженным чит-кодом.
  2. Список отслеживаемых чит-кодов хранится в таблице AnitCheat.list, и может быть измененён при необходимости.
  3. Функция AntiCheat:setEnable(true/false) позвоялет включать/отключать детект во время игры при необходимости.
  4. Удалить все триггеры системы в рантайме можно вызовом AntiCheat:destroy()

Код

Раскрыть
--[[
    AntiCheat — Simple cheat code detection for single-player Warcraft 3 maps.

    Last tested patch: Reforged 2.0.3

    How it works:
    — Listens for player input in the Edit Box UI frame.
    — Compares input against a table of known cheat codes.
    — If a match is found, triggers a punishment (by default: player defeat).

    Configuration:
    — Customize the AntiCheat:_punish(cheat) function for your own cheat code responses.
    — Edit AntiCheat.list to add or remove cheat codes.

    Control:
    — Initialize with AntiCheat:init(debugMode). Set debugMode to true or false.
    — Disable or re-enable the system with AntiCheat:setEnable(false/true).
    — Remove the system with AntiCheat:destroy().

    Important note:
    UI frame events must not be initialized too early, as the game UI may not be available yet.
    This system uses a short delay and checks for null frames to minimize the risk,
    but always ensure you are not calling AntiCheat:init() before the game UI is fully loaded.

    Naming convention:
    Functions prefixed with an underscore (`_`) are internal. Do not call these directly.
--]]

AntiCheat = {}
AntiCheat.debug = true

function AntiCheat:_punish(cheat)
    self:_displayMessage(cheat) -- Debug

    -- You can add any reaction to entering a cheat code to this function
    -- In this example, the player gets defeat

    CustomDefeatBJ(GetLocalPlayer(), "Good luck next time!")
end

AntiCheat.list = { -- Table of known cheat codes in Warcraft 3
    "allyourbasearebelongtous", -- Instantly win the current mission
    "daylightsavings", -- Switches from day to night, halts or restarts the flow of the day/night cycle
    "greedisgood", -- Instantly obtain set number of lumber and gold
    "iocanepowder", -- Enables fast acting death/decay of bodies
    "iseedeadpeople", -- Full map is revealed, fog of war disabled
    "itvexesme", -- Disables victory conditions
    "keysersoze", -- Instantly obtain set number of gold
    "leafittome", -- Instantly obtain set number of lumber
    "lightsout", -- Sets time of day to evening
    "motherland", -- Selects a mission number for the chosen race to warp to
    "pointbreak", -- Disables food limit for creating new units
    "riseandshine", -- Sets time of day to morning
    "sharpandshiny", -- Instantly grants all upgrades
    "somebodysetupthebomb", -- Instantly lose the current mission
    "strengthandhonor", -- Disables game over screen after losing objectives in campaign mode
    "synergy", -- Unlocks the full tech tree
    "tenthleveltaurenchieftan", -- Plays a special music track "Power of the Horde"
    "thedudeabides", -- Enables faster spell cooldown times
    "thereisnospoon", -- All units gain infinite mana
    "warpten", -- Enables faster building times
    "whoisjohngalt", -- Enables faster research time for upgrades
    "whosyourdaddy", -- All units and buildings gain full invulnerability, units will be able to 1-hit kill any opponent or enemy structure (does not effect friendly fire)
    -- Source: https://www.ign.com/wikis/warcraft-3/PC_Cheats_and_Secrets_-_List_of_Warcraft_3_Cheat_Codes
}

-- Debug Messages
AntiCheat.messages = {
    success = "|c0000FF80Anti-Cheat system is enabled.|r",
    cancel = "|c00EDED12Not a single-player mode. Initialization of the Anti-Cheat system was canceled.|r",
    error = "|c00FF0000Error when trying to access Edit Box.\r\nThe Anti-Cheat system was not enabled.|r",
    detect = "|c00FF0000\"CHEATCODE\" cheat code detected.|r",
    disabled = "|c00EDED12Anti-Cheat system was disabled.|r",
    destroyed = "|c00EDED12Anti-Cheat system was removed from game.|r"
}

-- “Impossible” index for nil-frame comparison
-- (do not use this index for real frames or change it if you need)
AntiCheat.nullFrameIndex = 93242

AntiCheat.states = {}

---@param debugMode boolean output debug messages
function AntiCheat:init(debugMode)
    self.debug = debugMode

    if not ReloadGameCachesFromDisk() then
        self:_displayMessage("cancel")
        return
    end

    local saveLoadedTrigger, textChangedTrigger, textEnteredTrigger = CreateTrigger(), CreateTrigger(), CreateTrigger()
    local states, cheats = self.states, self.list

    TriggerRegisterGameEvent(saveLoadedTrigger, EVENT_GAME_LOADED)
    TriggerAddCondition(saveLoadedTrigger, Condition(function() self:_setBoxEvents() end))

    TriggerAddCondition(textChangedTrigger, Condition(function()
        states[2] = states[1]
        states[1] = BlzGetTriggerFrameText()
    end))

    TriggerAddCondition(textEnteredTrigger, Condition(function()
        local enteredText = states[2]:lower()

        for i = 1, #cheats do
            if enteredText:find(cheats[i]) then
                self:_punish(cheats[i])
                break
            end
        end
    end))

    self.triggers = {textChangedTrigger, textEnteredTrigger, saveLoadedTrigger}
    self:_setBoxEvents()
end

function AntiCheat:_setBoxEvents()
    -- Event registration has been moved to a separate function,
    -- since when loading a saved game it will need to be done again.

    local t = CreateTimer()
    -- Accessing to the frame while the map is initializing can result in a fatal error, so delay is needed

    TimerStart(t, .1, false, function()
        local eBox = self:_getEditBox()

        if eBox then
            BlzTriggerRegisterFrameEvent(self.triggers[1], eBox, FRAMEEVENT_EDITBOX_TEXT_CHANGED)
            BlzTriggerRegisterFrameEvent(self.triggers[2], eBox, FRAMEEVENT_EDITBOX_ENTER)
            self:_displayMessage("success")
        else
            self:_displayMessage("error")
            self:destroy()
        end

        DestroyTimer(t)
    end)
end

function AntiCheat:_getEditBox()
    -- Includes frame access check
    local index = self.nullFrameIndex

    local nullFrame = BlzGetOriginFrame(ConvertOriginFrameType(index), 0)
    local gameUI = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
    if gameUI == nullFrame then return nil end

    nullFrame = BlzFrameGetChild(gameUI, index)
    local msgFrame = BlzFrameGetChild(gameUI, 11)
    if msgFrame == nullFrame then return nil end

    local editBox = BlzFrameGetChild(msgFrame, 1)
    if editBox == nullFrame then return nil end

    return editBox
end

function AntiCheat:_displayMessage(mType)
    if not self.debug then return end

    if self.messages[mType] then
        print(self.messages[mType])
        return
    end

    for _, v in ipairs(self.list) do
        if v == mType then
            local message = self.messages.detect:gsub("CHEATCODE", mType)
            print(message)
            return
        end
    end
end

---@param enable boolean
function AntiCheat:setEnable(enable)
    local triggers = self.triggers
    if not triggers then return end

    if enable then
        EnableTrigger(triggers[2])
        self:_displayMessage("success")
        return
    end

    DisableTrigger(triggers[2])
    self:_displayMessage("disabled")
end

function AntiCheat:destroy()
    local triggers = self.triggers

    if triggers then
        for _, v in ipairs(triggers) do
            DisableTrigger(v)
            DestroyTrigger(v)
        end
    end

    self.triggers = nil
    self:_displayMessage("destroyed")
end

Ссылки и кредиты

`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
23
Можно тупой вопрос - а для чего его использовать? Если ютуберов мошенников ловить - так они могут из своих видео вырезать все детекты читов, под любым удобным предлогом. Если обычный синглплеер - так там игрок один играет, никому не вредит в катке. А какие ещё ситуации могут быть, чтоб требовалась античит система в сингле? В мультиплеер понятно, но там и читы не работают
12
EugeAl, к примеру другу челленж в варкрафте устроить, и что-бы он не читерил (когда ты отвернулся) вставить эту систему
38
EugeAl, просто отключить стандартные средства читов в игре. Просто потому что они не требуются по задумке. В своей кампании я так делал, но по косвенным признакам, а не по чату.
Ты же отбираешь у юнитов стандартные абилки, убираешь ратушу в кастомках, почему не убрать читы?
23
ScorpioT1000, так ведь тут не отключение читов, а их отслеживание. Отключить читы из игры по умолчанию нельзя, разве что костыль написать на джассе, что если игрок вводит например warpten, то тут же с помощью нативки Cheat ввести чит повторно и снять эффект, аналогично с whosyourdaddy итд, или ещё как нибудь наказывать игрока.
27
ScorpioT1000, я, например, в своей карте детектил урон и если он был овердохера (при хузедадди урон выше в тысячу рвз), то заканчивал принудительно прохождение☺
38
Lord_Teo, там достаточно чтобы в скрытом месте дамми постоянно дамажил другой дамми и сверялся урон. С видимостью подобное
27
EugeAl, просто фича такая, можно добавить для разнообразия
там достаточно чтобы в скрытом месте дамми постоянно дамажил другой дамми и сверялся урон
Легендарные системы детекта на даммиках с жаром преисподней
7
Звучит странно, но интересно стало:
Используя подобную махинацию можно при этом ещё соединить триггер с убийством игрока молнией за применение команды чит-кода?)
Например: записал whosyourdaddy - смэрть от молнии.
СмЭЭЭрть(с акцентом деда)
27
Vozmezdie, игрока убивать нельзя, это уголовно наказуемо.
7
Makeba, Я говорю в синглплеерном режиме...Если так не получится, тогда ладно...
38
Makeba, убить персонажа сегодня недостаточно, нужно поджечь пк игрока и устроить задымление дома?)
27
Vozmezdie, это шутка на тему, что лучше убивать таки юнита, чем игрока.
Да всё что угодно можно, почему нельзя, для этой цели наработка и создана.
7
Makeba, Я это и имел ввиду! XD
Хотелось создавать себе подобную кампанию в рпг-жанра как с Рексаром или с Сибирем РПГ(то есть Нортренд), где введение подобной команды сработает триггер где убивает ГГ и провалится миссия)
38
Vozmezdie, посмотри jc она открыта и там есть детект читов
7
ScorpioT1000, Она открыта с триггерами? 0_0
Просматривая подобные скриншоты, это пригодится другому челу...Который занимается машинимами...
Этот комментарий удален
27
Вышла новая версия!
Прокрутить к ресурсу
По рекомендациям хайва добавлена проверка на сингл-плеер режим и добавлено описание в шапку кода
35
Я в своей карте убрал античит (Когдато был он). И сам добавил кучу читов)
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.