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

utility

Время, случайные числа, мышь, буфер обмена, проекция в экран. 15 канонических функций.

Функций15 (45 с алиасами)
Проверено вживую13 из 15 (GetFingerprint и TeleportToPlace частично)
Требуемый eventнет
Сайд-эффектыMoveMouse, SetClipboard, TeleportToPlace меняют глобальное состояние. LoadImage выделяет новый texture handle при каждом вызове.

Алиасы. Каждая функция на этой странице существует в трёх формах: utility.GetTickCount (канон), utility.getTickCount (camelCase), utility.get_tick_count (snake_case). Все три зовут одну и ту же C-функцию. См. Обзор / Конвенция именования.

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

ФункцияСигнатураЗаметкаСтатус
RandomInt(a: int, b: int) → intинклюзивный [a, b]проверено
RandomFloat(a: number, b: number) → numberинклюзивный [a, b]проверено
GetTickCount() → intмиллисекунды с запуска читапроверено
GetDeltaTime() → numberсекунды с прошлого кадрапроверено
GetSystemTime() → {year, month, day, hour, minute, second, weekday}локальное время, weekday 0=Вс..6=Сбпроверено
GetTimestamp() → intunix-секунды (UTC)проверено
GetFingerprint() → stringпусто в этом билдечастично
GetMousePos() → {[1] = x, [2] = y}одна array-table, не multi-returnпроверено
MoveMouse(dx: int, dy: int)относительный offset, НЕ pixel-perfect (Win-ускорение влияет)проверено
GetMenuState() → booltrue если меню чита открытопроверено
WorldToScreen(v3: Vector3) → screenX: number, screenY: number, onScreen: boolonScreen = проекция валидна, не boundsпроверено
GetClipboard() → stringUTF-8, пусто для не-текстапроверено
SetClipboard(s: string)перезаписывает системный буферпроверено
LoadImage(data: string) → numberPNG/JPG байты, новый texture id каждый вызовпроверено
TeleportToPlace(jobId: string)join Roblox-сервер по Job ID, сетевой сайд-эффектчастично

RandomInt

utility.RandomInt(a: int, b: int) → int

Возвращает случайное целое в инклюзивном диапазоне [a, b]. Передавай a <= b. Распределение равномерное.

Проверено вживую: RandomInt(1, 100) вернул 69, потом 38 на последовательных вызовах.

local roll = utility.RandomInt(1, 100)
print(roll)

RandomFloat

utility.RandomFloat(a: number, b: number) → number

Возвращает случайное число с плавающей точкой в диапазоне [a, b]. Передавай a <= b. Отрицательные диапазоны допустимы: RandomFloat(-1, 1) работает.

Проверено вживую: RandomFloat(0, 1) вернул 0.26634337488978, потом 0.48977073860767.

local jitter = utility.RandomFloat(-0.5, 0.5)

GetTickCount

utility.GetTickCount() → int

Счётчик тиков чита в миллисекундах. Монотонно возрастает.

Проверенное живое значение: 99868805 (около 27 часов с момента запуска чита).

Используй для троттлинга, кулдаунов, дельт между кадрами:

local last = 0
cheat.register("onUpdate", function()
local now = utility.GetTickCount()
if now - last < 500 then return end
last = now
print("срабатывает каждые 500 мс")
end)

GetDeltaTime

utility.GetDeltaTime() → number

Время в секундах с прошлого кадра.

Проверенное живое значение: 0.0045325998216867 (около 220 FPS).

cheat.register("onPaint", function()
local fps = 1 / math.max(utility.GetDeltaTime(), 0.0001)
draw.TextOutlined(string.format("FPS: %.0f", fps), 10, 10,
Color3.fromRGB(255, 255, 255), "Verdana")
end)

GetSystemTime

utility.GetSystemTime(){ year, month, day, hour, minute, second, weekday }

Локальное системное время как table. Все поля целочисленные.

weekday следует C-конвенции tm_wday: 0 = воскресенье, 1 = понедельник, ... 6 = суббота. Проверено вживую: 25 апреля 2026 была суббота, и вызов вернул weekday = 6.

Проверенный живой вывод:

{ year=2026, month=4, day=25, hour=18, minute=24, second=32, weekday=6 }
local t = utility.GetSystemTime()
local stamp = string.format("%04d-%02d-%02d %02d:%02d:%02d",
t.year, t.month, t.day, t.hour, t.minute, t.second)
print(stamp)

GetTimestamp

utility.GetTimestamp() → int

Unix-таймштамп в секундах с 1970-01-01 UTC.

Проверенное живое значение: 1777159472 (апрель 2026).

local ts = utility.GetTimestamp()
file.append("events.log", ts .. " script_loaded\n")

GetFingerprint

utility.GetFingerprint() → string

Хеш аппаратного отпечатка. Задумывался как стабильный идентификатор машины для лицензий или per-machine конфигов.

Возвращает пустую строку в этом билде

Три последовательных вызова вернули "" (длина 0). Считай возврат потенциально пустым и имей fallback.

local fp = utility.GetFingerprint()
if fp == nil or fp == "" then
fp = "unknown-" .. tostring(utility.GetTimestamp())
end
print("HWID:", fp)

GetMousePos

utility.GetMousePos()table { [1] = x, [2] = y }

Текущая позиция мыши в пикселях экрана. Точка отсчёта - верхний левый угол, X растёт вправо, Y растёт вниз.

Возвращает одну array-table, а не multi-return

Функция возвращает одну table, ключи только целые 1 и 2. Доступ через mp[1] и mp[2]. Сокращений mp.X / mp.Y нет, и table не разворачивается в local x, y = ... (получишь table в x и nil в y).

Проверено вживую: вернула {[1]=862, [2]=679} когда курсор был в точке (862, 679).

cheat.register("onPaint", function()
local mp = utility.GetMousePos()
local x, y = mp[1], mp[2]
draw.Circle(x, y, 6, Color3.fromRGB(255, 255, 0), 1, 12, 1)
end)

MoveMouse

utility.MoveMouse(dx: int, dy: int)

Двигает мышь на относительное смещение (не абсолютные координаты экрана). Положительный dx вправо, положительный dy вниз (та же ось что у GetMousePos). Используется внутренне в логике silent-aim и triggerbot.

utility.MoveMouse(5, -3)
Аргумент это НЕ raw screen-пиксели

Проверено вживую: старт (972, 717), вызов MoveMouse(30, 0) сдвинул курсор в (1010, 717), то есть +38 px, не +30. MoveMouse(0, 25) дал +47 px по вертикали. Offset проходит через Windows pointer ballistics (mouse acceleration) - нелинейный множитель зависящий от скорости и текущей OS-чувствительности.

Последствия:

  • Наивный round-trip "двинули +N потом -N" не возвращает курсор в стартовую точку. Probe закончился drift'ом (-22, 0) после пары +30 / -30.
  • Для aimbot или smooth-aim нужно либо калибровать множитель на каждой машине, либо звать MoveMouse маленькими шажками (1-3 unit), где ballistic-кривая ближе к линейной.
  • Для тестов движения курсора сравнивай направление delta, а не магнитуду.
Сайд-эффект

Реально двигает системный курсор. Никогда не вызывай из onPaint. Используй onUpdate с rate-limit'ом через паттерн троттла из GetTickCount.


GetMenuState

utility.GetMenuState() → bool

Возвращает true если меню Serotonin сейчас открыто (виден курсор). Используй для подавления aim/movement когда юзер взаимодействует с читом.

Проверено вживую: вернула true когда меню было открыто.

cheat.register("onUpdate", function()
if utility.GetMenuState() then return end
end)

WorldToScreen

utility.WorldToScreen(v3: Vector3) → screenX, screenY, onScreen: bool

Проецирует world-space Vector3 в 2D-координаты экрана. Возвращает три значения: screenX, screenY, bool.

Проверено вживую с Vector3.new(0, 10, 0):

screenX  = 1201.9686279297
screenY = 410.52291870117
onScreen = true
select("#", utility.WorldToScreen(v3)) == 3

Валидация аргументов (проверено):

ВызовРезультат
WorldToScreen()"bad argument #1 to '?' (__vector3_meta expected, got no value)"
WorldToScreen(nil)"bad argument #1 to '?' (__vector3_meta expected, got nil)"
WorldToScreen({0,10,0})"bad argument #1 to '?' (__vector3_meta expected, got table)" (нужен Vector3 userdata, не plain table)
Что реально означает onScreen

onScreen равно true когда проекция математически валидна (точка перед камерой). Это не проверка "видно ли в окне", прогон с Vector3.new(-99999, 50, -99999) тоже вернул true. Для реальной проверки видимости дополнительно сверяй 0 <= screenX <= window_w и 0 <= screenY <= window_h через cheat.GetWindowSize().

cheat.register("onPaint", function()
local lp = entity.GetLocalPlayer()
if not lp then return end
local pos = lp:GetBonePosition("HumanoidRootPart")
if not pos then return end
local x, y, onScreen = utility.WorldToScreen(pos)
if onScreen then
draw.TextOutlined("Я", x, y, Color3.fromRGB(0, 255, 0), "Verdana")
end
end)

GetClipboard

utility.GetClipboard() → string

Текущий системный буфер обмена как UTF-8 строка. Пустая строка если буфер пуст или содержит не-текст (картинку, файл, бинарь). Лимита по длине не наблюдалось.

Проверено вживую: вернула 159-символьную строку с ранее скопированным Lua-сниппетом.

local text = utility.GetClipboard()
print("длина буфера:", #text)

SetClipboard

utility.SetClipboard(s: string)

Заменяет системный буфер обмена указанной строкой. Ничего не возвращает.

Проверено вживую полным round-trip: записал "serotonin-test-1777160880", немедленный GetClipboard() вернул ровно ту же строку, потом восстановление оригинального 232-символьного значения тоже сработало. Латентности больше одного кадра не потребовалось.

local lp = entity.GetLocalPlayer()
if lp then
utility.SetClipboard("UserId: " .. tostring(lp.UserId))
end
Сайд-эффект

Перезаписывает то что юзер скопировал. Чтобы вежливо, сохрани предыдущий буфер через GetClipboard и восстанови после.


LoadImage

utility.LoadImage(data: string) → number

Загружает raw байты изображения (PNG / JPG) и возвращает числовой texture id, пригодный для draw.Image. Используй с file.read для ассет-пайплайна.

Проверено вживую с PNG 21816 байт: первый вызов вернул id 1, второй вызов 2. Каждый вызов выделяет новый texture handle, функция не дедуплицирует. Грузи один раз на старте и переиспользуй id, не перегружай каждый кадр иначе утечка texture-памяти.

Битый ввод безопасно отвергается через pcall:

  • мусорная строка возвращает error "Failed to load texture from memory. HRESULT: 0x?"
  • не-string аргумент возвращает error "bad argument #1 to '?' (string expected)"
  • native-крашей не наблюдалось
local data = file.read("logo.png")
if data then
local tex = utility.LoadImage(data)
cheat.register("onPaint", function()
draw.Image(tex, 20, 20, 64, 64, Color3.new(1, 1, 1), 1)
end)
end

Файл лежит в C:\Serotonin\files\ (sandbox скрипта). Forward slashes в пути.

local data = file.read("logo.png")
if data then
local tex = utility.LoadImage(data)
cheat.register("onPaint", function()
draw.Image(tex, 20, 20, 64, 64, Color3.new(1, 1, 1), 1)
end)
end

Файл лежит в C:\Serotonin\files\ (sandbox скрипта). Forward slashes в пути.


TeleportToPlace

utility.TeleportToPlace(jobId: string)

Подключается к конкретному Roblox-серверу (game instance) по его Job ID, UUID идентификатору активного сервера в текущей игре. Это не "сменить игру", place остаётся прежним.

Реальная сигнатура восстановлена из runtime-error: вызов с nil, bool или table возвращает:

bad argument #1 to '?' (string Job ID expected)

Числа тоже принимаются (auto-coerce в string). Строковые аргументы не вызывают ошибку на месте, но если Job ID невалидный, чит всё равно может инициировать teleport-попытку которую Roblox client отвергнет, что выкинет тебя с текущего сервера.

Используй чтобы зайти к другу в его private-сервер или вернуться в тот же instance после disconnect:

local job_id = "сюда-настоящий-job-id"
utility.TeleportToPlace(job_id)

Job ID выглядит как df93c2e8-7c18-4f3a-9d1e-9b8a5b2f4e3c (стандартный UUID).

Сетевой сайд-эффект

Даже с невалидным Job ID чит может инициировать teleport-запрос который Roblox-сервер отвергнет на полпути. Это может крашнуть чит или кикнуть тебя с текущего сервера. Никогда не зови TeleportToPlace со случайными или угаданными строками, только с реальным Job ID который ты получил из game.GetService("Players").LocalPlayer или профиля друга.


Паттерны

Счётчик FPS

См. GetDeltaTime.

Throttled-действие (каждые N мс)

См. GetTickCount.

Сохранение состояния на машину

local fp = utility.GetFingerprint()
if fp == nil or fp == "" then fp = "anon" end
local path = "config_" .. string.sub(fp, 1, 8) .. ".json"
file.write(path, '{"theme":"dark"}')

Пропуск логики когда меню открыто

cheat.register("onUpdate", function()
if utility.GetMenuState() then return end
end)

Правильное чтение позиции мыши

local mp = utility.GetMousePos()
local mx, my = mp[1], mp[2]