Перейти к основному содержимому

cheat

Три core-хелпера от Serotonin runtime: регистрация event'ов (Register), запрос window size (GetWindowSize), runtime-исполнение кода (LoadString). 3 канонических функции.

Функций3 (8 с алиасами)
Проверено вживую2 из 3 (Register и GetWindowSize)
Требуемый eventнет
Сайд-эффектыRegister добавляет персистентный per-event callback который нельзя unregister на время жизни скрипта. LoadString исполнял бы код если бы работал.

Алиасы. Register имеет две формы (cheat.Register / cheat.register). GetWindowSize и LoadString имеют по три формы (PascalCase / camelCase / snake_case). См. Обзор / Конвенция именования.

Алиасы это разные function objects. Проверено: cheat.Register == cheat.register возвращает false, хотя они вызывают одну underlying C-функцию и ведут себя идентично. Не полагайся на == для идентификации конкретной API-функции, сравнивай по имени.

Краткий справочник​

ФункцияСигнатураЗаметкаСтатус
Register(event: string, callback: function)регистрирует callback для именованного event'а. Без валидации event-имени, см. нижепроверено
GetWindowSize() → width, height (multi-return)размер окна Roblox в пикселяхпроверено
LoadString(name: string, code: string)runtime-исполнение кода. Сломан в билде version-390ba09e7e944154частично

Register​

cheat.Register(event: string, callback: function)

Регистрирует callback для именованного event'а. Callback вызывается каждый раз когда чит диспатчит этот event.

Известные диспатчируемые event'ы​

Имя event'аКогда срабатывает
onUpdatelogic tick (~5 мс)
onSlowUpdatebackground tick (~1 с)
onPaintper-frame, обязательный контекст для всех draw.*
shutdownпри выгрузке скрипта
newPlaceпри teleport'е игрока в новое место

Важно: НЕТ валидации event-имени​

Проверено: cheat.Register молча принимает любую строку (или число) в первом аргументе, включая:

  • Garbage-имена вроде "totally_invalid_event_xyz_999" → ok = true, без ошибки
  • Пустую строку "" → ok = true
  • Wrong-case версии known events: "OnUpdate", "ONUPDATE", "on_update" → все ok = true
  • Число: Register(123, function() end) → ok = true

Эти вызовы регистрируют callback во внутреннюю таблицу, но callback никогда не сработает потому что никто не диспатчит это event-имя. 5 имён в таблице выше case-sensitive и единственные которые чит реально диспатчит.

Валидация аргументов​

ВызовРезультат
Register()"bad argument #1 to '?' (string expected, got no value)"
Register("onUpdate")"bad argument #2 to '?' (function expected, got no value)"
Register("onUpdate", nil)"bad argument #2 to '?' (function expected, got nil)"
Register("onUpdate", "str")"bad argument #2 to '?' (function expected, got string)"
Register(nil, fn)"bad argument #1 to '?' (string expected, got nil)"
Register(123, fn)принят молча (числовые event-имена допустимы но не диспатчатся)

Нельзя unregister​

Нет Unregister API. После вызова cheat.Register callback живёт всё время жизни скрипта. Перезапуск скрипта (без рестарта Roblox) накапливает новые callbacks поверх старых. Защищайся от двойной регистрации в development:

if not _ALREADY_LOADED then
_ALREADY_LOADED = true
cheat.Register("onPaint", function()

end)
end

Примеры​

cheat.Register("onUpdate", function()
local lp = entity.GetLocalPlayer()
if not lp then return end

end)

cheat.Register("onPaint", function()
draw.Text("hello", 10, 10, Color3.fromRGB(255, 255, 255), 14, 1)
end)

cheat.Register("shutdown", function()
print("script unloading, cleaning up...")
end)

GetWindowSize​

cheat.GetWindowSize() → width: number, height: number

Возвращает пиксельные размеры окна Roblox как два return value (multi-return), не packed table.

Проверено вживую: cheat.GetWindowSize() вернул (2048, 1208) на 2K-дисплее в windowed mode. select("#", cheat.GetWindowSize()) вернул 2.

local w, h = cheat.GetWindowSize()
draw.Text(string.format("%dx%d", w, h), w - 80, 4, Color3.fromRGB(200, 200, 200), 12, 1)

Можно также упаковать в таблицу если нужно:

local size = { cheat.GetWindowSize() }

Сравни с draw.GetScreenSize (когда будет задокументирован), это то же значение но вызывается внутри drawing-контекста.


LoadString​

cheat.LoadString(scriptContent: string, scriptName: string)
Всё ещё сломан в билде version-390ba09e7e944154

Перепроверено вживую через API-verifier: cheat.LoadString("return 1+2", "verify_chunk") поднимает "C++ exception" - ту же uncatchable native-ошибку из ранних аудитов. Patch-нота "Improved exception safety in decompiler" в этом билде не сделала LoadString рабочим; каждый 2-аргументный вызов который мы пробовали (валидный Lua source, syntax errors, runtime errors, raw bytecode, пустые строки) поднимает "C++ exception", и pcall его не ловит надёжно - функция никогда не исполняет chunk.

Считай cheat.LoadString нерабочим в текущем билде. Используй стандартный Lua loadstring / load.

Сигнатура (из IntelliSense, подтверждена через pcall):

  • Аргумент 1: scriptContent - Lua source или LuaJIT bytecode (обязательный)
  • Аргумент 2: scriptName - имя chunk'а для error-сообщений (обязательный)
  • Return: должен был бы быть загруженный chunk; в текущем билде вызов поднимает "C++ exception" до возврата
Используй стандартный Lua loadstring для типичного запуска удалённых скриптов

Для классического паттерна "скачать скрипт по HTTP и выполнить" правильный инструмент - стандартный Lua-5.1 loadstring (доступен в sandbox'енном LuaJIT Serotonin'а). Он компилирует исходник в callable chunk, который ты вызываешь сам:

http.Get(
"https://example.com/payload.lua",
{},
function(response)
local chunk, err = loadstring(response)
if chunk then chunk() end
end
)

loadstring возвращает function | nil, errorMessage, позволяет проверить chunk перед запуском и поддерживает compile-time syntax errors. cheat.LoadString это отдельный Serotonin-helper, чьи side-effects в текущем билде это не load-and-return; для типичных задач сначала бери loadstring.

Проверенная валидация аргументов (эти ошибки случаются ДО C++ exception)​

ВызовРезультат
LoadString()"bad argument #1 to '?' (string expected, got no value)"
LoadString("x = 1")"bad argument #2 to '?' (string expected, got no value)"
LoadString(nil, "x = 1")"bad argument #1 to '?' (string expected, got nil)"
LoadString("n", nil)"bad argument #2 to '?' (string expected, got nil)"
LoadString("n", 123)"C++ exception" (числовой code доходит до loader'а)

Проверенные failure modes (все 2-arg, любой код который мы пробовали)​

ВызовРезультат
LoadString("a", "x = 1")"C++ exception"
LoadString("a", "return 42")"C++ exception" (lone return claim из ранних доков)
LoadString("a", "this is = not.lua")"C++ exception" (syntax error)
LoadString("a", "error('boom')")"C++ exception" (runtime error)
LoadString("a", "file.write('m','EXEC')")"C++ exception", файл не изменился

Если нужно динамическое исполнение кода, используй стандартный Lua loadstring/load (всё ещё в sandbox) и вызывай его явно:

local fn, err = loadstring("return 1 + 2")
if fn then print(fn()) else print("compile failed:", err) end

Этот паттерн надёжно работает в sandbox в отличие от cheat.LoadString.


Паттерны​

Идемпотентная загрузка скрипта​

if not _MTC_BOOTED then
_MTC_BOOTED = true
cheat.Register("onUpdate", function() ... end)
cheat.Register("onPaint", function() ... end)
end

Window-aware HUD-якорь​

cheat.Register("onPaint", function()
local w, h = cheat.GetWindowSize()

local bx, by = w - 240, h - 80
draw.RectFilled(bx, by, 230, 70, Color3.new(0.1, 0.1, 0.12), 4, 0.85)
draw.Text("MTC v0.1", bx + 8, by + 8, Color3.new(1, 1, 1), 14, 1)
end)

Cleanup при unload​

cheat.Register("shutdown", function()

file.write("session.log", string.format("ended at %d\n", utility.GetTickCount()))
end)

Сравнение event-таймингов​

local update_count, paint_count = 0, 0
cheat.Register("onUpdate", function() update_count = update_count + 1 end)
cheat.Register("onPaint", function() paint_count = paint_count + 1 end)
cheat.Register("onSlowUpdate", function()
print(string.format("update=%d/s paint=%d/s", update_count, paint_count))
update_count, paint_count = 0, 0
end)