rUNC Executor Test

rUNC — это комплексный, открытый набор тестов для глубокой проверки функциональности среды исполнения Luau. Он оценивает корректность реализации десятков функций, выявляя потенциальные проблемы, уязвимости и несоответствия стандарту.

Запуск теста

Чтобы запустить тест, выполните следующую команду в вашей среде исполнения:

Luau
loadstring(game:HttpGet("https://raw.githubusercontent.com/TesterTD/rUNC/main/rUNC.lua"))()

FAQ

Что такое rUNC?

rUNC — инструмент для комплексного тестирования окружения, который проверяет наличие и корректную работу десятков ключевых функций: от базовых (например, newcclosure) до продвинутых, связанных с отладкой, метатаблицами и взаимодействием с движком Roblox.

В отличие от оригинального UNC, созданного как единый стандарт именования и API, rUNC имитирует реальные сценарии использования функций, чтобы убедиться, что они действительно работают так, как должны, а не просто существуют для прохождения базовых проверок.

Что означает "Skid Rate"?

Это условный показатель, который отражает процент неудачных тестов для критически важных или базовых функций. Высокий Skid Rate может указывать на низкое качество, эмуляцию или неполную реализацию среды исполнения.

В чем цель этого проекта?

Тест был создан, чтобы доказать, что надежная проверка среды исполнения может и должна быть с открытым исходным кодом. Он служит альтернативой закрытым системам, которые анализируют среду анонимно, не позволяя пользователям изучить сам механизм проверки.

Почему нет тестов для WebSocket?

Тесты для WebSocket намеренно исключены, так как его реализация часто приводит к нестабильной работе или вылетам в различных средах исполнения. Вместо этого предоставляется общая документация по его API.

Где большинство примеров?

Остаточные примеры можно посмотреть в самом открытом коде для проверки функций. Я не вижу смысла оставлять их везде, к тому же на разных инжекторах они реагируют по‑разному, хоть и проходят тест они одинаково хорошо или плохо.

newcclosure

Создает "C-замыкание" из функции Luau. Это позволяет маскировать Luau-функции под встроенные C-функции, что изменяет их поведение при обработке ошибок и для таких проверок, как iscclosure.

Синтаксис

function newcclosure(func: function): function

Примеры

1. Простое оборачивание
local my_func = function() return "Hello from Luau!" end
local c_func = newcclosure(my_func)

print(iscclosure(my_func)) --> false
print(iscclosure(c_func)) --> true
print(c_func()) --> Hello from Luau!
2. Маскировка ошибок
local error_func = newcclosure(function()
    error("This is a custom error")
end)

-- pcall вернет ошибку без информации о скрипте и строке, как будто она из C-кода
local success, message = pcall(error_func)
print(success, message) --> false, This is a custom error

Как проверяется в rUNC

Тест проверяет несколько ключевых аспектов:

  • Создание и тип: Убеждается, что newcclosure успешно создает функцию и что iscclosure правильно идентифицирует её как C-замыкание.
  • Сохранение семантики: Проверяет, что обернутая функция возвращает те же значения (включая множественные возвраты), что и оригинал.
  • Обработка yield: Тестирует, может ли newcclosure оборачивать "yielding" функции (например, с task.wait) и корректно возобновлять их выполнение.
  • Маскировка ошибок: Удостоверяется, что ошибки, возникающие внутри C-замыкания, выглядят как ошибки из C-кода (без stack trace).
  • Вложенность: Проверяет возможность создавать newcclosure из функции, которая уже является C-замыканием.

hookfunction

Позволяет перехватить вызовы одной функции и заменить их другой. Возвращает оригинальную функцию, чтобы её можно было вызвать внутри перехватчика для сохранения исходной логики. Это мощный инструмент для логирования, модификации поведения или блокировки функций.

Синтаксис

function hookfunction(target: function, hook: function): function -- Возвращает оригинал

Примеры

1. Логирование вызовов `warn`
local original_warn
original_warn = hookfunction(warn, function(...)
    print("[WARN CALLED]:", ...)
    return original_warn(...)
end)

warn("Test message")
2. Модификация аргументов `print`
local old_print
old_print = hookfunction(print, function(...)
    local args = {...}
    table.insert(args, 1, "[HOOKED]")
    return old_print(table.unpack(args))
end)

print("Hello", "world") -- Выведет: [HOOKED] Hello world

Как проверяется в rUNC

Тест проводит комплексную проверку:

  • Базовый перехват: Удостоверяется, что вызов оригинальной функции теперь выполняет код хука.
  • Возврат оригинала: Проверяет, что hookfunction возвращает рабочую копию оригинальной функции.
  • Обработка ошибок: Тестирует, что ошибки в оригинальной функции могут быть перехвачены и обработаны внутри хука.
  • Работа с C-функциями: Убеждается, что можно перехватывать глобальные C-функции, такие как warn.
  • Восстановление: Проверяет, что хук можно снять, вызвав hookfunction повторно с оригинальной функцией.
  • Совместимость с `newcclosure`: Тест запускается дважды: с обычной Luau-функцией и с C-замыканием в качестве хука.

restorefunction

Полностью восстанавливает оригинальное состояние функции, которая была ранее изменена с помощью hookfunction. Удаляет все установленные хуки, включая вложенные, возвращая функцию к её первоначальному состоянию.

Синтаксис

function restorefunction(target: function)

Примеры

1. Восстановление `print` после хука
hookfunction(print, function(...) end) -- Блокируем print
print("This will not appear")

restorefunction(print)
print("This will appear now") --> This will appear now
2. Снятие нескольких хуков
local function my_func() return "original" end

local old1 = hookfunction(my_func, function() return "hooked 1" end)
local old2 = hookfunction(my_func, function() return "hooked 2" end)

print(my_func()) --> "hooked 2"

restorefunction(my_func)
print(my_func()) --> "original"

Как проверяется в rUNC

  • Ошибка на не-хукнутой функции: Убеждается, что вызов restorefunction на обычной функции вызывает ошибку.
  • Полное восстановление: После установки нескольких хуков на одну функцию, проверяет, что restorefunction возвращает её к самому первому, оригинальному состоянию.
  • Изоляция: Проверяет, что восстановление одной функции не затрагивает хуки, установленные на другие функции.
  • Повторное восстановление: Убеждается, что повторный вызов restorefunction на уже восстановленной функции вызывает ошибку.

cloneref

Создает "легкую" копию (ссылку) на Instance. Клон и оригинал указывают на один и тот же объект в памяти. Это означает, что изменение свойства у клона изменит его и у оригинала. Уничтожение оригинала делает клон невалидным. Защищает от __mode атак, то есть детекты с помощью weak tables.

Синтаксис

function cloneref(target: Instance): Instance

Примеры

1. Демонстрация работы ссылок
local part_original = Instance.new("Part", workspace)
local part_clone = cloneref(part_original)

print(part_original == part_clone) --> false (ссылки разные)

part_clone.Name = "NewName"
print(part_original.Name) --> "NewName" (объект один)
2. Валидность после Destroy
local part_original = Instance.new("Part", workspace)
local part_clone = cloneref(part_original)

part_original:Destroy()
task.wait(0.1)

local success, result = pcall(function()
    return part_clone.Parent
end)
print(success, result) --> true nil

Как проверяется в rUNC

  • Создание и неравенство: Убеждается, что клон успешно создается, но при этом original ~= clone возвращает true.
  • Общие сигналы: Проверяет, что подключение к сигналу на клоне влияет на оригинал.
  • Совместное уничтожение: После вызова :Destroy() на оригинале, тест проверяет, что и оригинал, и клон удалены из игрового дерева.
  • Невалидность: Убеждается, что после уничтожения оригинала, доступ к свойствам или методам клона вызывает ошибку или возвращает `nil`.

compareinstances

Сравнивает два `Instance`, чтобы определить, указывают ли они на один и тот же базовый объект. Это особенно полезно при работе с `cloneref`, так как обычное сравнение `==` вернет `false` для оригинала и его клона.

Синтаксис

function compareinstances(a: Instance, b: Instance): boolean

Примеры

1. Сравнение оригинала и клона
local original = Instance.new("Part")
local ref = cloneref(original)

print(original == ref) --> false
print(compareinstances(original, ref)) --> true
2. Сравнение разных объектов
local part1 = Instance.new("Part")
local part2 = Instance.new("Part")

print(compareinstances(part1, part2)) --> false
print(compareinstances(part1, part1)) --> true

Как проверяется в rUNC

  • Идентичность: Проверяет, что compareinstances(inst, inst) возвращает `true`.
  • Сравнение с клоном: Убеждается, что compareinstances(inst, cloneref(inst)) возвращает `true`.
  • Различие: Проверяет, что compareinstances(inst1, inst2) для разных объектов возвращает `false`.

loadstring

Компилирует строку кода Luau в функцию без её немедленного выполнения. Если в коде есть синтаксическая ошибка, возвращает `nil` и сообщение об ошибке.

Синтаксис

function loadstring(code: string, chunkName: string?): (function?, string?)

Примеры

1. Динамическое выполнение кода
local code = "getgenv().a = 10; return a + 5"
local func, err = loadstring(code)

if func then
    print("Result:", func()) --> Result: 15
    print("Global var:", getgenv().a) --> Global var: 10
else
    warn("Failed to compile code:", err)
end
2. Обработка ошибок компиляции
local invalid_code = "local a =="
local func, err = loadstring(invalid_code, "MyChunk")

if not func then
    print("Error:", err) --> Error: [MyChunk]:1: Expected identifier...
end

Как проверяется в rUNC

  • Компиляция и исполнение: Проверяет, что `loadstring` для корректного кода возвращает функцию, которая выполняется и возвращает правильное значение.
  • Доступ к окружению: Убеждается, что код может изменять глобальное окружение (getgenv).
  • Обработка невалидного кода: Проверяет, что для кода с ошибкой `loadstring` возвращает `nil` и строку с сообщением об ошибке.
  • Имя чанка: Удостоверяется, что имя чанка (`chunkName`) появляется в сообщении об ошибке.

firesignal

Вызывает сигнал (`RBXScriptSignal`) с указанными аргументами. По сути, это способ программно имитировать срабатывание сигнала.

Синтаксис

function firesignal(signal: RBXScriptSignal, ...: any)

Примеры

1. Имитация клика по кнопке
local button = Instance.new("TextButton")
button.MouseButton1Click:Connect(function()
    print("Button was clicked programmatically!")
end)

firesignal(button.MouseButton1Click)
2. Вызов BindableEvent с аргументами
local bindable = Instance.new("BindableEvent")
bindable.Event:Connect(function(player, score)
    print(player.Name .. " scored " .. score)
end)

local player = game:GetService("Players").LocalPlayer
firesignal(bindable.Event, player, 100)

Как проверяется в rUNC

  • Вызов с аргументами и без: Проверяет, что вызовы `firesignal` корректно активируют подключенную функцию и передают ей аргументы (или `nil`).
  • Отключенные соединения: Проверяет, что `firesignal` не вызывает соединения, которые были отключены через `:Disconnect()`.

identifyexecutor

Возвращает имя и версию текущей среды исполнения (эксплойта).

Синтаксис

function identifyexecutor(): (string --[[name]], string --[[version]])

Примеры

1. Вывод информации в консоль
local name, version = identifyexecutor()
print(`Executor: {name} v{version}`)

Как проверяется в rUNC

  • Успешное выполнение: Проверяет, что функция выполняется без ошибок.
  • Тип и содержимое: Убеждается, что оба возвращаемых значения — это непустые строки, соответствующие имени и версии.

isrbxactive

Проверяет, активно ли окно Roblox. Возвращает `true`, если окно находится в фокусе, и `false` в противном случае. Полезно для скриптов, которые должны приостанавливать свою работу, когда игрок сворачивает игру.

Синтаксис

function isrbxactive(): boolean

Примеры

1. Пауза цикла, когда игра неактивна
task.spawn(function()
    while true do
        if isrbxactive() then
            -- Выполняем действия, только если игра в фокусе
            print("Окно удерживается")
        end
        task.wait(1)
    end
end)

Как проверяется в rUNC

  • Возвращаемое значение: Тест просто вызывает функцию и проверяет, что она выполняется без ошибок и возвращает `true`, так как во время выполнения теста окно по определению активно.

gethui

Возвращает скрытый контейнер интерфейса (`Instance`), предназначенный для безопасного размещения UI-элементов. Объекты в `gethui` Если так подумать, это CoreGui parent на максималках, cloneref с CoreGui будет в разы лучше.

Синтаксис

function gethui(): Instance

Примеры

1. Создание постоянного GUI
local permanentGui = Instance.new("ScreenGui")
permanentGui.ResetOnSpawn = false
permanentGui.Parent = gethui()

Как проверяется в rUNC

  • Тип объекта: Проверяет, что `gethui` возвращает объект типа `Instance`.
  • Функциональность родителя: Убеждается, что в возвращенный объект можно помещать другие `Instance` (например, `ScreenGui`).

islclosure / iscclosure / isexecutorclosure

Эти функции проверяют тип замыкания (closure). Они используются для определения, является ли функция обычной Luau-функцией, C-функцией или специфичной для эксплойта.

  • islclosure(func): Возвращает `true`, если `func` — это стандартная функция, написанная на Luau.
  • iscclosure(func): Возвращает `true`, если `func` — это C-функция, включая newcclosure.
  • isexecutorclosure(func): Возвращает `true`, если функция принадлежит среде исполнения.

Примеры

1. Проверка разных типов функций
local lua_func = function() end
local c_func_wrapped = newcclosure(lua_func)
local c_func_native = print
local exploit_func = getgenv

print("lua_func is lclosure:", islclosure(lua_func))             --> true
print("c_func_native is cclosure:", iscclosure(c_func_native)) --> true
print("exploit_func is executorclosure:", isexecutorclosure(exploit_func)) --> true

Как проверяется в rUNC

Тест проверяет все три функции на разных типах целей: Luau-функция, стандартная C-функция (`print`), обернутая C-функция (`newcclosure`) и функция среды исполнения (`getgenv`).

isnewcclosure

Определяет, была ли C-функция создана с помощью newcclosure. Это позволяет отличить "настоящие" встроенные C-функции от Luau-функций, замаскированных под C.

Синтаксис

function isnewcclosure(func: function): boolean

Примеры

1. Отличие обертки от нативной функции
local wrapped = newcclosure(function() end)

print("For wrapped function:", isnewcclosure(wrapped)) --> true
print("For native 'print':", isnewcclosure(print))   --> false

Как проверяется в rUNC

Тест проверяет, что функция возвращает true для результата newcclosure и false для обычной Luau-функции.

isfunctionhooked

Проверяет, была ли функция перехвачена (захукана) с помощью hookfunction.

Синтаксис

function isfunctionhooked(func: function): boolean

Примеры

1. Проверка состояния хука
local function my_func() end
print("Before hook:", isfunctionhooked(my_func)) -- false

local old = hookfunction(my_func, function() end)
print("After hook:", isfunctionhooked(my_func)) -- true

hookfunction(my_func, old) -- restore original
print("After restore:", isfunctionhooked(my_func)) -- false (Но, скорее будет true, на что можно надеяться, когда ты восстанавливаешь функцию не через restorefunction💀)

Как проверяется в rUNC

Тест проверяет, что функция возвращает false для обычной функции, true после применения `hookfunction`, и снова false после восстановления.

replaceclosure

Заменяет код одной Luau-функции кодом другой. При этом новая функция получает доступ к upvalue'ам (внешним локальным переменным) оригинальной функции.

Внимание: Эта функция может легко привести к сбою, если новая функция неправильно работает с upvalue'ами старой.

Синтаксис

function replaceclosure(target: function, new: function)

Примеры

1. Изменение поведения и доступ к upvalue
local counter = 10
local function original()
    counter = counter + 1
    return "Original was called"
end

local function replacement()
    return "Replacement was called, counter is: " .. counter
end

replaceclosure(original, replacement)
print(original()) --> Replacement was called, counter is: 10

Как проверяется в rUNC

  • Подмена: Убеждается, что после замены вызов оригинальной функции теперь выполняет код новой.
  • Доступ к upvalue: Проверяет, что замененная функция может корректно читать upvalue'ы оригинала.
  • Защита C-функций: Удостоверяется, что попытка заменить C-функцию вызывает ошибку.

clonefunction

Создает полную копию (клон) Luau-функции. Клон имеет то же самое тело и upvalue'ы, но является отдельным объектом. Хуки, примененные к оригиналу после клонирования, не влияют на клон.

Синтаксис

function clonefunction(target: function): function

Примеры

1. Изоляция от хуков
local function original()
    print("Original function")
end

local cloned = clonefunction(original)

hookfunction(original, function() print("Hooked!") end)

original() --> Hooked!
cloned()   --> Original function

Как проверяется в rUNC

  • Общее окружение: Убеждается, что `getfenv(original)` и `getfenv(cloned)` совпадают.
  • Изоляция от `hookfunction`: После клонирования хукает оригинал и проверяет, что клон остался неизменным.
  • Работа с C-функциями: Убеждается, что попытка клонировать C-функцию не вызывает ошибку (проверка эмуляции).

newlclosure

Создает новое Luau-замыкание из существующей Luau-функции. Это похоже на clonefunction, но является более низкоуровневой операцией. Новый lclosure разделяет код и upvalue'ы с оригиналом.

Синтаксис

function newlclosure(target: function): function

Примеры

1. Создание нового Luau замыкания
local count = 0
local function increment()
    count = count + 1
    return count
end

local lclosure_copy = newlclosure(increment)

print(increment())       --> 1
print(lclosure_copy())   --> 2
print(islclosure(lclosure_copy)) --> true

Как проверяется в rUNC

  • Успешное создание: Проверяет, что функция создает новое замыкание и что islclosure возвращает true.
  • Общие upvalues: Убеждается, что вызов оригинала и нового замыкания влияет на один и тот же upvalue.
  • Ошибка на C-функциях: Проверяет, что попытка использовать на C-функции вызывает ошибку.

checkcaller

Проверяет контекст вызова. Возвращает `true`, если вызов происходит из среды инжектора. Возвращает `false`, если вызов инициирован из самого клиента, следственно игрой, а не Executor.

Синтаксис

function checkcaller(): boolean

Примеры

1. Защита от вызовов `Kick` с подробнейшим объяснением и проверкой кому принадлежит kick
local Players = cloneref(game:GetService("Players")) --> Получаем сервис Players через cloneref (Зачем? Прочти мой документационный пост про cloneref :D)
local lp = Players.LocalPlayer                      

local old --> Переменная для хранения оригинальной функции __namecall
old = hookmetamethod(game, "__namecall", newcclosure(function(self, ...)
    local method = getnamecallmethod()  --> Получаем имя вызываемого метода ("Kick")
    if self == lp and method and method:lower() == "kick" then --> Проверяем, что метод вызывается на LocalPlayer и это Kick
        if checkcaller() then   --> Если вызов из кода Executor, значит...
            warn("Попытка кика со стороны Executor была заблокирована!!! Нахуя себя кикать?") --> Логируем, что кик был от executor и посылаем нахер
            return --> Блокируем выполнение
        else  --> Если вызов из игры (Клиент попытался кикнуть)
            warn("хахаахахахаха лошок ебаный захотел кикнуть со стороны клиента") --> Логируем, что кик был от клиента, а не от Executor
            return --> Блокируем выполнение
        end
    end
    return old(self, ...) --> Если условия не совпали — вызываем оригинальный __namecall
end))

task.delay(2, function() --> Ждём 2 секунды, чтобы хук успел установиться (На всякий, вдруг твой инжектор Velocity :D)
    warn(">>> TEST: вызываем Kick от инжектора")
    lp:Kick("Если ты видишь это сообщение то это значит одно: A - твой инжектор не обладает hookmetamethod или функция крайне плохо сделана...") --> Этот вызов должен быть перехвачен хуком и заблокирован
end)

Как проверяется в rUNC

Тест проводит множество проверок: базовый вызов, вызов из C-кода через `__namecall`, вызов из `newcclosure` и стабильность.

getrawmetatable

Возвращает метатаблицу объекта, даже если она защищена свойством __metatable.

Синтаксис

function getrawmetatable(obj: table | userdata): table

Примеры

1. Обход защиты __metatable
local t = {}
local mt = { __metatable = "LOCKED" }
setmetatable(t, mt)

print(getmetatable(t)) --> LOCKED
print(getrawmetatable(t) == mt) --> true

Как проверяется в rUNC

Проверяет работу с обычной таблицей, `Instance` и сервисами. Создает таблицу с защитой `__metatable` и проверяет, что `getrawmetatable` успешно ее получает.

setrawmetatable

Устанавливает метатаблицу для объекта, обходя защиту `__metatable`.

Синтаксис

function setrawmetatable(obj: table | userdata, mt: table | nil): boolean

Примеры

1. Замена защищенной метатаблицы
local t = {}
setmetatable(t, { __metatable = "LOCKED" })

local new_mt = { __index = function() return "bypassed!" end }
setrawmetatable(t, new_mt)
print(t.anything) --> bypassed!

Как проверяется в rUNC

Проверяет, что `setrawmetatable` успешно устанавливает новую метатаблицу на защищенный объект и что она действительно работает.

hookmetamethod

Перехватывает вызовы метаметодов (`__index`, `__namecall`, и др.) для заданного объекта. Это один из самых мощных способов изменения поведения Roblox API.

Синтаксис

function hookmetamethod(obj: userdata, method: string, hook: function): function -- Возвращает оригинал

Примеры

1. Перехват `game:GetService()`
local old_namecall
old_namecall = hookmetamethod(game, "__namecall", function(self, ...)
    if getnamecallmethod():lower() == "getservice" then
        print("GetService вызван для:", ...)
    end
    return old_namecall(self, ...)
end)

game:GetService("Players")

Как проверяется в rUNC

Тест проверяет хуки на несколько ключевых метаметодов: __newindex, __tostring, __index, и __namecall, а также возможность их восстановления.

getgenv / getrenv / getsenv

Предоставляют доступ к различным таблицам окружения.

  • getgenv(): Глобальное окружение Executor среды.
  • getrenv(): Глобальное окружение Roblox, врата getrenv() к getfenv().
  • getsenv(script): Локальное окружение конкретного скрипта.

Примеры

1. Чтение окружения getsenv
local animate = game.Players.LocalPlayer.Character:FindFirstChild("Animate")
if animate then
    local env = getsenv(animate)
    print(typeof(env.onSwimming)) --> function
end
2. Работа с getgenv
local g = getgenv()
g.testValue = 123
print(getgenv().testValue) --> 123
3. Работа с getrenv
local r = getrenv()
print(r.game) --> Ugc
r._customFlag = true
print(getrenv()._customFlag) --> true

Как проверяется в rUNC

  • getgenv / getrenv: Проверяет, возвращается ли таблица и сохраняются ли в ней изменения.
  • getsenv: Проверяет получение окружения для активного LocalScript, ошибку на неактивном и nil для ModuleScript.

getthreadidentity / setthreadidentity

Функции для управления уровнем "идентичности" (контекста безопасности) текущего потока. Уровень идентичности — это число от 0 до 8.

Примеры

1. Изменение идентичности в новом потоке
print("Уровень потока сейчас:", getthreadidentity())

task.spawn(function()
    print("Новый поток (Уровень на данный момент):", getthreadidentity())
    setthreadidentity(6)
    print("Новый поток (После изменения):", getthreadidentity()) --> 6
end)

task.wait(0.1)
print("Основной поток уровня не был нарушен:", getthreadidentity())

Как проверяется в rUNC

Тест проводит исчерпывающую проверку: стабильность, диапазон, изоляцию потоков, работу в `pcall` и быстрое переключение.

getscripts

Возвращает таблицу всех существующих в игре скриптовых объектов (LocalScript, Script, ModuleScript), независимо от того, запущены они или нет.

Синтаксис

function getscripts(): table

Примеры

1. Поиск всех скриптов по имени
local scripts_list = getscripts()
print("Всего скриптов:", #scripts_list)

local foundAnimate = false
for _, script_obj in ipairs(scripts_list) do
    if typeof(script_obj) == "Instance" and script_obj:IsA("LocalScript") and script_obj.Name:find("Animate") then
        print("Нашёл Animate script:", script_obj:GetFullName())
        foundAnimate = true
    end
end

local player = game.Players.LocalPlayer
local charAnimate = player.Character and player.Character:FindFirstChild("Animate")

if not charAnimate or not charAnimate:IsA("LocalScript") then
    warn("Эмуляция getscripts: Animate не найден в персонаже")
elseif not foundAnimate then
    warn("Фальшивый getscripts: Animate есть в персонаже, но отсутствует в списке getscripts")
else
    print("Animate найден и в персонаже, и в списке getscripts")
end

Как проверяется в rUNC

Создает новый LocalScript и затем проверяет, что getscripts находит этот свежесозданный скрипт в возвращенном списке.

getrunningscripts

Возвращает таблицу всех скриптов, которые в данный момент исполняются. В отличие от getscripts, эта функция не включает скрипты, которые отключены (Disabled = true) или еще не были запущены.

Синтаксис

function getrunningscripts(): table

Примеры

1. Мониторинг активных скриптов
local running_scripts = getrunningscripts()
print("Всего запущенных скриптов:", #running_scripts)

for _, s in ipairs(running_scripts) do
    print("- " .. s:GetFullName())
end

local player = game.Players.LocalPlayer
local vehicleCameraPath = player:FindFirstChild("PlayerScripts")
    and player.PlayerScripts:FindFirstChild("PlayerModule")
    and player.PlayerScripts.PlayerModule:FindFirstChild("CameraModule")
    and player.PlayerScripts.PlayerModule.CameraModule:FindFirstChild("VehicleCamera")

if not vehicleCameraPath or not vehicleCameraPath:IsA("ModuleScript") then
    warn("Тупорылая эмуляция getrunningscripts: VehicleCamera не найден")
else
    print("VehicleCamera найден:", vehicleCameraPath:GetFullName())
end

Как проверяется в rUNC

Находит известный работающий скрипт (Animate), проверяет, что не включает неактивные скрипты, и что общее число скриптов больше нуля.

getloadedmodules

Возвращает таблицу всех ModuleScript, которые были загружены хотя бы раз через require().

Синтаксис

function getloadedmodules(): table

Примеры

1. Поиск существующего модуля и require к нему
local ok, modules = pcall(getloadedmodules)
if not ok or type(modules) ~= "table" then
    warn("getloadedmodules отсутствует или эмулирован")
    return
end

local count = 0
print("=== Список загруженных ModuleScript ===")
for _, module in ipairs(modules) do
    if typeof(module) == "Instance" and module:IsA("ModuleScript") then
        count += 1
        print(count .. ".", module.Name, "→", module:GetFullName())
    end
end
print("Всего загруженных модулей:", count)

local player = game.Players.LocalPlayer
local cameraUIPath = player:FindFirstChild("PlayerScripts")
    and player.PlayerScripts:FindFirstChild("PlayerModule")
    and player.PlayerScripts.PlayerModule:FindFirstChild("CameraModule")
    and player.PlayerScripts.PlayerModule.CameraModule:FindFirstChild("CameraUI")

if not cameraUIPath or not cameraUIPath:IsA("ModuleScript") then
    warn("Примитивная эмуляция getloadedmodules: CameraUI не найден")
else
    local okReq, result = pcall(require, cameraUIPath)
    if not okReq then
        warn("Примитивная эмуляция getloadedmodules: require(CameraUI) не сработал")
    else
        print("CameraUI найден и успешно загружен через require")
    end
end

Как проверяется в rUNC

Проверяет, что известный загруженный модуль присутствует в списке, а свежесозданный, незагруженный — отсутствует.

getscriptbytecode

Возвращает скомпилированный байт-код скрипта в виде строки.

Синтаксис

function getscriptbytecode(script: BaseScript): string?

Примеры

1. Чтение байт-кода
local Players = game:GetService("Players")
local lp = Players.LocalPlayer

local char = lp.Character or lp.CharacterAdded:Wait()
local animate = char:WaitForChild("Animate")

local bytecode = getscriptbytecode(animate)
if bytecode then
    print("Bytecode length:", #bytecode)  --> 12365
else
    warn("Не удалось получить байткод Animate")
end

Как проверяется в rUNC

Убеждается, что для скрипта с кодом (Animate) возвращается непустая строка, а для скрипта без байт-кода — nil или пустая строка.

getscriptclosure

Возвращает главное замыкание (функцию) скрипта. По сути, это "скомпилированный" результат, который можно выполнить.

Синтаксис

function getscriptclosure(script: BaseScript): function?

Примеры

1. Выполнение скрипта "Animate" на существование Closure
local animate = game.Players.LocalPlayer.Character:WaitForChild("Animate")
local func = getscriptclosure(animate)
print("Closure доступен:", func ~= nil) --> true

Как проверяется в rUNC

Проверяет, что для скрипта с кодом (Animate) возвращается function, а для пустого — nil.

getscripthash

Возвращает хэш (SHA-384) байт-кода скрипта. Это надежный способ проверить, был ли скрипт изменен.

Синтаксис

function getscripthash(script: BaseScript): string?

Примеры

1. Проверка на получение и изменение хеша
local Players = game:GetService("Players")
local lp = Players.LocalPlayer
local char = lp.Character or lp.CharacterAdded:Wait()
local animate = char:WaitForChild("Animate")

local current_hash = getscripthash(animate)
print("→ Текущий хэш Animate:", current_hash)

local known_hash = current_hash
if current_hash ~= known_hash then
    warn("Animate script изменил хеш!!")
else
    print("Animate script hash имеет один и тот же хеш, всё нормально.")
end

Как проверяется в rUNC

Проверяет, что возвращаемое значение является валидным хэшем SHA-384. Тестирует, что для скрипта без байт-кода возвращается nil.

getfunctionhash

Возвращает хэш (SHA-384) байт-кода Luau-функции. Работает напрямую с функциями в памяти.

Синтаксис

function getfunctionhash(func: function): string

Примеры

1. Сравнение двух функций
local function a() return 1 end
local function b() return 1 end -- Другая функция, но с тем же кодом

print(getfunctionhash(a) == getfunctionhash(b)) --> true

Как проверяется в rUNC

Проверяет, что возвращается корректный хэш. Убеждается, что разные функции имеют разные хэши, а идентичные — одинаковые. Проверяет ошибку на C-функциях.

getcallingscript

Возвращает script, из которого была вызвана текущая функция. Если вызов был инициирован C-кодом, возвращает nil.

Синтаксис

function getcallingscript(): BaseScript?

Примеры

1. Логирование вызовов из __newindex
local old
old = hookmetamethod(game, "__newindex", function(self, key, value)
    if not checkcaller() then
        local caller = getcallingscript()
        warn("__newindex доступ из скрипта:", caller and caller:GetFullName() or "Unknown") --> Как правило это будет PlayerScripts.RbxCharacterSounds
        hookmetamethod(game, "__newindex", old)
        return old(self, key, value)
    end
    return old(self, key, value)
end)

print(getcallingscript())

Как проверяется в rUNC

Проверяет, что прямой вызов из C-потока возвращает nil, а вызов из Luau-функции возвращает текущий скрипт.

queue_on_teleport

Регистрирует строку с Lua-кодом, которая будет выполнена после того, как игрок телепортируется в другое место (place) внутри той же игры (universe).

Синтаксис

function queue_on_teleport(code: string)

Примеры

1. Телепорт и print() после телепорта
local TeleportService = game:GetService("TeleportService")
local Players = game:GetService("Players")
local lp = Players.LocalPlayer

queue_on_teleport([[
    print("→ Код из очереди выполнился после телепорта в ту же игру!")
]])

TeleportService:Teleport(game.PlaceId, lp)

Как проверяется в rUNC

Проверяет, что вызов с валидной строкой кода не вызывает ошибок.

getgc

Возвращает таблицу со всеми объектами (функции, таблицы, userdata и т.д.), которые в данный момент находятся в памяти и отслеживаются сборщиком мусора (Garbage Collector). Может включать или не включать функции в зависимости от аргумента.

Синтаксис

function getgc(includeFunctions: boolean?): table

Примеры

1. Поиск всех объектов Part и проверка на эмуляцию
local marker = Instance.new("Folder")
marker.Name = "Иван Золо"

local gcObjects = {}
local foundMarker = false
local markerIndex

for i, v in ipairs(getgc(true)) do
    if v == marker then
        foundMarker = true
        markerIndex = i
    end
    if typeof(v) == "Instance" and v.ClassName == "Part" then
        table.insert(gcObjects, v)
    end
end

marker:Destroy()

if not foundMarker then
    print("Эмуляция getgc")
else
    print("Маркер найден в getgc под индексом", markerIndex)
    print("Нашёл", #gcObjects, "объектов Part в памяти")
end
2. Поиск скрытых функций
local function SecretAdminFunction()
    print("→ Запущена функция 1")
end

local function HiddenDebugTool()
    print("→ Запущена фунция 2")
end

local function UltraSecureRoutine()
    print("→ Запущена функция 3")
end

local markerFunc = function() end

local foundMarker = false
local foundTargets = {}

for _, v in ipairs(getgc(false)) do
    if v == markerFunc then
        foundMarker = true
    end
    if type(v) == "function" then
        local info = debug.getinfo(v)
        if info and info.name == "SecretAdminFunction" then
            table.insert(foundTargets, "SecretAdminFunction")
            v()
        elseif info and info.name == "HiddenDebugTool" then
            table.insert(foundTargets, "HiddenDebugTool")
            v()
        elseif info and info.name == "UltraSecureRoutine" then
            table.insert(foundTargets, "UltraSecureRoutine")
            v()
        end
    end
end

if not foundMarker then
    print("Эмуляция getgc")
else
    if #foundTargets > 0 then
        print("Найдены и вызваны функции:", table.concat(foundTargets, ", "))
    else
        print("Маркер найден, но целевые функции отсутствуют")
    end
end

Как проверяется в rUNC

  • getgc(false): Проверяет, что находит функции, но не таблицы.
  • getgc(true): Проверяет, что находит все тестовые объекты: функцию, таблицу и userdata.

getnilinstances

Возвращает таблицу всех объектов Instance, у которых нет родителя (Parent == nil). Это подмножество того, что вернет getinstances.

Синтаксис

function getnilinstances(): table

Примеры

1. Очистка "мусорных" объектов c проверкой на эмуляцию
local marker = Instance.new("Folder")
marker.Name = "Коржик"
marker.Parent = nil

local cleaned_count = 0
local foundMarker = false
local markerIndex

for i, inst in ipairs(getnilinstances()) do
    if inst == marker then
        foundMarker = true
        markerIndex = i
    end
    if not inst:IsDescendantOf(game) and inst.ClassName ~= "GameSettings" then
        local ok = pcall(function()
            inst:Destroy()
        end)
        if ok then
            cleaned_count += 1
        end
    end
end

marker:Destroy()

if not foundMarker then
    print("Эмуляция getnilinstances")
else
    print("Маркер найден в getnilinstances под индексом", markerIndex)
    print("Очищено nil-объектов:", cleaned_count)
end

Как проверяется в rUNC

Убеждается, что объект без родителя присутствует в списке, а объект с родителем — нет.

getinstances

Возвращает таблицу всех Instance, существующих в памяти, независимо от того, есть у них родитель или нет.

Синтаксис

function getinstances(): table

Примеры

1. Глобальный поиск экземпляров ProximityPrompt с проверкой на эмуляцию
local part = Instance.new("Part")
part.Size = Vector3.new(4, 1, 4)
part.Position = Vector3.new(0, 5, 0)
part.Anchored = true
part.Parent = workspace

local prompt = Instance.new("ProximityPrompt")
prompt.ActionText = "Нажми меня"
prompt.ObjectText = "Тестовый объект"
prompt.Enabled = true
prompt.Parent = part

local marker = Instance.new("Folder")
marker.Name = "Печенье"
marker.Parent = workspace

local foundMarker = false
local markerIndex

for i, inst in ipairs(getinstances()) do
    if inst == marker then
        foundMarker = true
        markerIndex = i
    end
    if inst:IsA("ProximityPrompt") and inst.Enabled then
        print("Найден активный prompt:", inst:GetFullName())
    end
end

marker:Destroy()

if not foundMarker then
    print("Эмуляция getinstances")
else
    print("Маркер найден в getinstances под индексом", markerIndex)
end

Как проверяется в rUNC

Убеждается, что свежесозданный Instance без родителя находится в списке.

getreg

Возвращает таблицу реестра Lua. Это низкоуровневая структура, в которой хранятся все "живые" объекты, включая потоки (thread), функции, таблицы и userdata.

Синтаксис

function getreg(): table

Примеры

1. Поиск и закрытие потока
local my_thread1 = task.spawn(function() -- PS: Найдёт множество лишних потоков, это нормально!
    while true do
        task.wait(1)
    end
end)

local my_thread2 = coroutine.create(function()
    while true do
        task.wait(2)
    end
end)
coroutine.resume(my_thread2)

local my_thread3 = task.spawn(function()
    for i = 1, 5 do
        task.wait(0.5)
    end
end)

local function isRealGetReg()
    local ok, reg = pcall(getreg)
    if not ok or type(reg) ~= "table" then
        return false, "getreg вернул не таблицу"
    end
    local hasThreadType, hasFunctionType = false, false
    for _, v in pairs(reg) do
        local t = type(v)
        if t == "thread" then hasThreadType = true end
        if t == "function" then hasFunctionType = true end
        if hasThreadType and hasFunctionType then
            return true
        end
    end
    return false, "В реестре нет ожидаемых типов"
end

local okReg, reason = isRealGetReg()
if not okReg then
    print("Эмуляция getreg:", reason)
else
    for _, value in pairs(getreg()) do
        if type(value) == "thread" and coroutine.status(value) == "suspended" then
            print("Найден зависший поток:", tostring(value), "статус:", coroutine.status(value))
            if value == my_thread1 then
                print("→ Это my_thread1 (бесконечный цикл с ожиданием 1 сек)")
            elseif value == my_thread2 then
                print("→ Это my_thread2 (корутина с ожиданием 2 сек)")
            elseif value == my_thread3 then
                print("→ Это my_thread3 (короткий цикл на 5 итераций)")
            else
                print("→ Это неизвестный поток")
            end
            coroutine.close(value)
            print("Поток закрыт")
        end
    end
end

Как проверяется в rUNC

Проверяет, что находит созданный поток, и что его можно закрыть через coroutine.close.

cache.* (invalidate, iscached, replace)

Набор функций для управления внутренним кэшем ссылок на Instance Roblox.

  • cache.iscached(inst): Проверяет, находится ли объект в кэше.
  • cache.invalidate(inst): Удаляет объект из кэша. Следующее обращение к нему (например, workspace.Part) создаст новую ссылку.
  • cache.replace(old_inst, new_inst): Заменяет один объект в кэше другим.

Примеры

1. Инвалидация кэша
local part1 = workspace.Part
cache.invalidate(workspace.Part)
local part2 = workspace.Part

print(part1 == part2) --> false (ссылки теперь разные)
2. Проверка cache.iscached()
local part = workspace.Part
print("Кэширован ли Part:", cache.iscached(part)) --> true

cache.invalidate(part)
print("Кэширован ли Part после invalidate:", cache.iscached(part)) --> false
3. Замена объекта через cache.replace()
local oldPart = workspace.Part
local newFire = Instance.new("Fire")
newFire.Parent = workspace

cache.replace(oldPart, newFire)

local replaced = workspace.Part
print("После replace ссылка на Part изменилась:", replaced ~= oldPart) --> true

Как проверяется в rUNC

  • invalidate: Создает Part и получает на него ссылку. После вызова cache.invalidate снова получает ссылку и проверяет, что новая ссылка не равна старой.
  • iscached: Проверяет, что свежесозданный Part кэширован. Затем инвалидирует его и проверяет, что он больше не в кэше.
  • replace: Заменяет Part на Fire и проверяет, что ссылки на объекты стали разными.

getconnections

Возвращает таблицу всех объектов соединений (RBXScriptConnection), подключенных к данному сигналу.

Синтаксис

function getconnections(signal: RBXScriptSignal): table

Примеры

1. Вызов функции подключения и получение типа потока
local event = Instance.new("BindableEvent")

event.Event:Connect(function(arg)
    return "Сработало с аргументом: " .. tostring(arg)
end)

local connection = getconnections(event.Event)[1]

print(connection.Function("тест")) -- Сработало с аргументом: тест

connection:Fire("ещё тест")

print("Тип потока подключения:", typeof(connection.Thread)) -- thread
2. Ручной вызов обработчика
local remote = Instance.new("RemoteEvent")
remote.Name = "RemoteEvent"
remote.Parent = workspace

remote.OnClientEvent:Connect(function(arg1, arg2)
    print("Событие получено! Аргументы:", arg1, arg2)
end)

for _, conn in ipairs(getconnections(remote.OnClientEvent)) do
    if conn.Function then
        print("Вызываем функцию подключения напрямую...")
        conn.Function("arg1", 123)
    end
end

Как проверяется в rUNC

Проверяет возврат таблицы, валидность соединений, доступ к .Function, вызов .Fire(), и обработку C-соединений.

getcallbackvalue

Получает функцию обратного вызова (callback), назначенную свойству объекта, например, BindableFunction.OnInvoke или RemoteFunction.OnClientInvoke.

Синтаксис

function getcallbackvalue(target: Instance, property: string): function?

Примеры

1. Чтение OnInvoke с доп. проверкой
local getcallbackvalue = getcallbackvalue

local bf = Instance.new("BindableFunction")
bf.OnInvoke = function(a, b) return a + b end

local function safeGetCallback(obj, prop)
    if typeof(obj) ~= "Instance" or type(prop) ~= "string" then
        return nil
    end
    local cb = getcallbackvalue(obj, prop)
    if type(cb) ~= "function" then
        return nil
    end
    local ok, upv = pcall(debug.getupvalue, cb, 1)
    if ok and upv ~= nil and upv ~= obj then
        return nil
    end
    return cb
end

local callback = safeGetCallback(bf, "OnInvoke")
if callback then
    local result = callback(534, -4) 
    print(result) --> 530
else
    print("Callback вероятно спуфнут или просто отсутствует")
end

Как проверяется в rUNC

Проверяет успешное извлечение callback, его работоспособность, и корректную обработку nil для неустановленных или несуществующих свойств.

setreadonly / isreadonly

Функции для управления состоянием "только для чтения" у таблиц.

  • setreadonly(tbl, state): Устанавливает или снимает с таблицы tbl флаг "только для чтения".
  • isreadonly(tbl): Проверяет, является ли таблица tbl "только для чтения".

Примеры

1. Защита конфигурационной таблицы
local config = {
    version = "1.0",
    enabled = true
}
setreadonly(config, true)
print(isreadonly(config)) --> true

local success, err = pcall(function()
    config.version = "1.1" -- Это вызовет ошибку
end)

print(success) --> false
print(config.version) --> 1.0
2. Временное снятие защиты
local config = config or {
    enabled = true
}

setreadonly(config, false)
config.enabled = false
setreadonly(config, true)

print("config.enabled =", config.enabled) -- false

Как проверяется в rUNC

Устанавливает флаг и проверяет блокировку записи. Затем снимает флаг и проверяет, что запись снова возможна.

setscriptable / isscriptable

Функции для управления "скриптуемостью" (доступностью из скриптов) скрытых или защищенных свойств Instance.

  • setscriptable(inst, prop, state): Делает свойство prop объекта inst доступным или недоступным для скриптов.
  • isscriptable(inst, prop): Проверяет, является ли свойство prop доступным.

Примеры

1. Чтение и изменение скрытого свойства InternalHeadScale
local humanoid = game.Players.LocalPlayer.Character:WaitForChild("Humanoid")

print("До снятия защиты — scriptable?:", isscriptable(humanoid, "InternalHeadScale"))

setscriptable(humanoid, "InternalHeadScale", true)
print("После снятия защиты — scriptable?:", isscriptable(humanoid, "InternalHeadScale"))

print("InternalHeadScale до:", humanoid.InternalHeadScale)
humanoid.InternalHeadScale = humanoid.InternalHeadScale + 0.1
print("InternalHeadScale после:", humanoid.InternalHeadScale)

setscriptable(humanoid, "InternalHeadScale", false)
print("После возврата защиты — scriptable?:", isscriptable(humanoid, "InternalHeadScale"))

Как проверяется в rUNC

Проверяет для Humanoid.InternalHeadScale, что оно изначально нескриптуемо, становится скриптуемым после setscriptable(true) (и его можно изменить), и снова становится нескриптуемым после setscriptable(false).

gethiddenproperty / sethiddenproperty

Функции для прямого чтения и записи скрытых свойств Instance, обходя стандартные проверки доступа. В отличие от setscriptable, они не меняют флаг доступности, а работают напрямую.

В текущей версии rUNC этот тест отключен, так как в некоторых средах он может приводить к сбою.

  • gethiddenproperty(inst, prop): Возвращает значение свойства и boolean, указывающий, является ли оно скрытым.
  • sethiddenproperty(inst, prop, value): Устанавливает значение скрытого свойства.

Примеры

1. Чтение и изменение DataCost
-- Создаём тестовый Part
local part = Instance.new("Part")
part.Parent = workspace

-- Пробуем прочитать скрытое свойство DataCost
local ok, value = pcall(function()
    return gethiddenproperty(part, "DataCost")
end)

print("DataCost доступен для чтения:", ok, "значение:", value)

-- Проверяем, можно ли записать (но не меняем, если read-only)
local ok2 = pcall(function()
    if value ~= nil then
        sethiddenproperty(part, "DataCost", value + 50)
    end
end)

print("DataCost доступен для записи:", ok2 and "да" or "нет")

Как проверяется в rUNC

Проверяет чтение обычных и скрытых свойств, а также запись в скрытое свойство 'DataCost' и убеждается, что обычная запись по-прежнему вызывает ошибку.

get/setsimulationradius

Функции для чтения и изменения радиуса симуляции физики для игрока.

Примеры

1. Увеличение радиуса симуляции
local originalRadius = getsimulationradius()
print("Original radius:", originalRadius)

setsimulationradius(1024)
print("New radius:", getsimulationradius()) --> 1024

Как проверяется в rUNC

Читает исходный радиус, устанавливает новое значение, а затем снова читает его, чтобы убедиться, что оно изменилось.

firetouchinterest

Искусственно вызывает событие касания (.Touched или .TouchEnded) между двумя объектами. Позволяет симулировать физический контакт без реального перемещения объектов.

Синтаксис

function firetouchinterest(part1: BasePart, part2: BasePart, toggle: number|boolean)

toggle: 0 или true для Touched, 1 или false для TouchEnded.

Примеры

1. Активация ловушки
-- Создаём персонажа (берём уже существующего у LocalPlayer)
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()

-- По последней информации разные Executors не хотят работать с этим тестом 
-- и отдают что-то по типу: Primitives belong to different or invalid worlds

-- Создаём триггер
local trap_trigger = Instance.new("Part")
trap_trigger.Name = "TrapTrigger"
trap_trigger.Size = Vector3.new(5, 1, 5)
trap_trigger.Position = Vector3.new(0, 5, 0)
trap_trigger.Anchored = true
trap_trigger.Transparency = 0.5
trap_trigger.BrickColor = BrickColor.new("Bright red")
trap_trigger.Parent = workspace

-- Подключаем обработчик касания
trap_trigger.Touched:Connect(function(hit)
    if hit and hit.Parent == character then
        print("Trap activated!")
    end
end)

-- Имитируем, что персонаж коснулся триггера
firetouchinterest(trap_trigger, character:WaitForChild("HumanoidRootPart"), 0) 

Как проверяется в rUNC

Тест создает две части и подписывается на события Touched и TouchEnded у одной из них.

  • Учет CanTouch: Устанавливает CanTouch = false и проверяет, что firetouchinterest не вызывает событие.
  • Вызов Touched: Устанавливает CanTouch = true и проверяет, что вызов с toggle=0 или toggle=true инкрементирует счетчик Touched.
  • Вызов TouchEnded: Проверяет, что вызов с toggle=1 или toggle=false инкрементирует счетчик TouchEnded.
  • Обработка ошибок: Убеждается, что вызов с неверными типами аргументов (например, nil или {}) вызывает ошибку.

fireclickdetector

Программно симулирует клик мыши или наведение на объект с ClickDetector.

Синтаксис

function fireclickdetector(cd: ClickDetector, distance: number?, event: string?)

event: Может быть "MouseClick" (по умолчанию), "RightMouseClick", "MouseHoverEnter", "MouseHoverLeave".

Примеры

1. Проверки на обработчик
-- Создаём новый ClickDetector (детектор кликов)
local click_detector = Instance.new("ClickDetector")

-- Обработчик клика левой кнопкой мыши
click_detector.MouseClick:Connect(function(player)
    print(`{player.Name} Fired M1`)
end)

-- Обработчик клика правой кнопкой мыши
click_detector.RightMouseClick:Connect(function(player)
    print(`{player.Name} Fired M2`)
end)

-- Обработчик наведения курсора на объект
click_detector.MouseHoverEnter:Connect(function(player)
    print(`{player.Name} Fired HoverEnter`)
end)

-- Обработчик ухода курсора с объекта
click_detector.MouseHoverLeave:Connect(function(player)
    print(`{player} Fired HoverLeave`)
end)

-- Симулируем клик ЛКМ по ClickDetector
fireclickdetector(click_detector, 0, "MouseClick")

-- Симулируем клик ПКМ по ClickDetector
fireclickdetector(click_detector, 0, "RightMouseClick")

-- Симулируем наведение курсора на объект
fireclickdetector(click_detector, 0, "MouseHoverEnter")

-- Симулируем уход курсора с объекта
fireclickdetector(click_detector, 0, "MouseHoverLeave")
2. Симуляция наведения мыши
local info_object = workspace:FindFirstChild("InfoObject")
if not info_object then
    info_object = Instance.new("Part")
    info_object.Name = "InfoObject"
    info_object.Size = Vector3.new(2, 1, 2)
    info_object.Position = Vector3.new(0, 3, 0)
    info_object.Anchored = true
    info_object.Parent = workspace
end

local info_detector = info_object:FindFirstChildOfClass("ClickDetector")
if not info_detector then
    info_detector = Instance.new("ClickDetector")
    info_detector.Parent = info_object
end

print("Наводим курсор на объект, чтобы показать подсказку")
fireclickdetector(info_detector, 0, "MouseHoverEnter")

task.wait(2)

print("Убираем курсор с объекта")
fireclickdetector(info_detector, 0, "MouseHoverLeave")

Как проверяется в rUNC

Последовательно вызывает fireclickdetector для MouseClick, RightMouseClick, MouseHoverEnter, MouseHoverLeave и проверяет, что соответствующие события сработали.

fireproximityprompt

Симулирует срабатывание ProximityPrompt от лица LocalPlayer.

Синтаксис

function fireproximityprompt(prompt: ProximityPrompt)

Примеры

1. Автоматическая проверка на работоспособность
local part = Instance.new("Part")
part.Size = Vector3.new(2, 1, 2)
part.Position = Vector3.new(0, 3, 0)
part.Anchored = true
part.Name = "CollectableItem"
part.Parent = workspace

local item_prompt = Instance.new("ProximityPrompt")
item_prompt.ActionText = "Collect"
item_prompt.ObjectText = "Item"
item_prompt.HoldDuration = 0
item_prompt.Parent = part

print("Активируем ProximityPrompt для объекта:", part.Name)
fireproximityprompt(item_prompt)
print("ProximityPrompt был успешно вызван")

Как проверяется в rUNC

Проверяет, что вызов не вызывает ошибок и что событие Triggered срабатывает с LocalPlayer в качестве аргумента.

replicatesignal

Используется для удаленной репликации событий ввода, таких как MouseWheelForward/Backward. Реплицирует сигнал на сервер с переданными аргументами, если это возможно. Аргументы должны соответствовать сигнатуре самого сигнала — при неверных аргументах будет выброшена ошибка.

Синтаксис

function replicatesignal(signal: RBXScriptSignal, ...: any?)

Примеры

1. Репликация взаимодействия с ClickDetector
-- Создаём тестовый Part с ClickDetector
local test_part = Instance.new("Part")
test_part.Name = "TestClickPart"
test_part.Size = Vector3.new(4, 1, 4)
test_part.Position = Vector3.new(0, 5, 0)
test_part.Anchored = true
test_part.Parent = workspace

local detector = Instance.new("ClickDetector")
detector.Parent = test_part

-- Реплицируем событие MouseActionReplicated с корректными аргументами
replicatesignal(detector.MouseActionReplicated, game.Players.LocalPlayer, 0)
task.wait(0.1)

print("MouseClickReplicated =", game.Players.LocalPlayer:GetAttribute("MouseClickReplicated"))
2. Проверка аргументов на UI‑элементе
-- Создаём тестовый UI с Frame
local player = game.Players.LocalPlayer
local gui = Instance.new("ScreenGui")
gui.Name = "TestGui"
gui.Parent = player:WaitForChild("PlayerGui")

local frame = Instance.new("Frame")
frame.Size = UDim2.new(0, 200, 0, 100)
frame.Position = UDim2.new(0.5, -100, 0.5, -50)
frame.BackgroundColor3 = Color3.fromRGB(255, 200, 200)
frame.Parent = gui

-- Эти вызовы вызовут ошибку, так как аргументы не соответствуют сигнатуре события
pcall(function() replicatesignal(frame.MouseWheelForward) end)
pcall(function() replicatesignal(frame.MouseWheelForward, 121) end)

-- Корректный вызов с нужными аргументами
replicatesignal(frame.MouseWheelForward, 121, 214)
task.wait(0.1)

print("MouseWheelForwardReplicated =", player:GetAttribute("MouseWheelForwardReplicated"))

Как проверяется в rUNC

Проверяет, что вызов с корректными аргументами не вызывает ошибок, а с неполными — вызывает.

getfpscap / setfpscap

Функции для чтения и установки ограничения кадров в секунду (FPS) в Roblox.

  • setfpscap(fps): Устанавливает ограничение FPS на указанное значение fps (число).
  • getfpscap(): Возвращает текущее ограничение FPS как число.

Синтаксис

function setfpscap(fps: number)
function getfpscap(): number

Примеры

1. Чтение текущего FPS cap
local currentFpsCap = getfpscap()
print("Current FPS Cap:", currentFpsCap)
2. Изменение FPS cap
-- Сохраняем текущее значение
local oldCap = getfpscap()

-- Устанавливаем новый cap
setfpscap(60)
print("New FPS Cap:", getfpscap())

-- Возвращаем старое значение
setfpscap(oldCap)
print("Restored FPS Cap:", getfpscap())

Как проверяется в rUNC

Читает cap, сверяет его с реальным FPS, устанавливает новый cap, проверяет что реальный FPS изменился, затем восстанавливает исходное значение.

messagebox

Отображает системное диалоговое окно (message box).

  • messagebox(text, caption, type): Показывает системное окно с сообщением text, заголовком caption и типом окна type (целое число, определяющее иконку и кнопки).
  • Возвращает: Целое число, представляющее ответ пользователя (например, код нажатой кнопки).

Синтаксис

function messagebox(text: string, caption: string, type: number): number

Примеры

1. Простое окно подтверждения
local response = messagebox("Do you want to continue?", "Confirmation", 4)

if response == 6 then -- 6 обычно соответствует кнопке "Yes"
    print("Пользователь выбрал: Да")
elseif response == 7 then -- 7 обычно соответствует кнопке "No"
    print("Пользователь выбрал: Нет")
else
    print("Пользователь закрыл окно или выбрал другой вариант")
end
2. Информационное сообщение
messagebox("Operation completed successfully.", "Info", 0)

Как проверяется в rUNC

Проверяет, что вызов не вызывает ошибок, и определяет, является ли вызов синхронным (блокирующим) или асинхронным.

setclipboard

Функция для записи текста в буфер обмена пользователя.

  • setclipboard(text): Устанавливает содержимое буфера обмена в указанный текст text (строка).

Синтаксис

function setclipboard(text: string)

Примеры

1. Копирование текста в буфер обмена
-- Записываем текст в буфер обмена
setclipboard("Copied text")

print("Текст был скопирован в буфер обмена.")
2. Копирование динамически сгенерированного текста
-- Генерируем случайный текст и копируем его
local random_text = "Hello from rUNC! " .. math.random()
setclipboard(random_text)

print("В буфер обмена записано:", random_text)

Как проверяется в rUNC

Записывает случайное число в буфер обмена через setclipboard и проверяет, что вызов не вызывает ошибок.

Эмуляция мыши

Набор функций для программной симуляции движений и кликов мыши.

  • mouse1/2press/release/click()
  • mousemoveabs(x, y), mousemoverel(dx, dy)
  • mousescroll(dx, dy)

Как проверяется в rUNC

Создает UI-кнопку под курсором и проверяет, что вызовы `mouse1click`, `mouse1press`/`release`, `mouse2click` и `mouse2press`/`release` действительно вызывают соответствующие события `MouseButton1Click`, `MouseButton1Down`/`Up` и т.д. Остальные функции проверяются на отсутствие ошибок при вызове.

Actors API

Набор функций для работы с параллельными вычислениями в Roblox с использованием Actor. API позволяет выполнять код в отдельных глобальных состояниях (Lua VM), что полезно для распределения нагрузки, изоляции задач и обхода некоторых ограничений движка. Передача данных между актором и основным потоком осуществляется через каналы связи.

  • getactors(): Возвращает список всех Actor в игре, в которых можно выполнить код.
  • isparallel(): Проверяет, выполняется ли текущий код в параллельном режиме.
  • run_on_actor(actor, code, [channel_data]): Выполняет указанный код в контексте актора. Третий аргумент может быть любым значением, кроме таблиц и функций (они принадлежат другой Lua VM).
  • create_comm_channel(): Создаёт канал связи между основным потоком и актором, возвращает ID канала и BindableEvent для передачи данных.
  • getactorthreads(): Возвращает список потоков акторов, доступных для выполнения кода.
  • run_on_thread(actor_thread, code, [channel_data]): Выполняет код в указанном потоке актора.

Синтаксис

function getactors(): table<number, Actor>
function isparallel(): boolean
function run_on_actor(actor: Actor?, script: string, [channel_data: any])
function create_comm_channel(): (number, BindableEvent)
function getactorthreads(): table<number, thread>
function run_on_thread(actor_thread: thread, script: string, [channel_data: any])

Примеры

1. Получение списка акторов
for index, actor in getactors() do
    print(index, actor)
end
2. Выполнение кода в первом акторе
local actors = getactors()
if #actors > 0 then
    run_on_actor(actors[1], 'print("Hello World from Actor!")')
else
    warn("Акторы не найдены в этой игре")
end
3. Передача данных через канал связи
local actors = getactors()
if #actors > 0 then
    local comm_id, event = create_comm_channel()
    event.Event:Connect(function(data)
        print("Сообщение от актора:", data)
    end)

    run_on_actor(actors[1], [=[
        local channel = get_comm_channel(...)
        channel:Fire("Hello World!")
    ]=], comm_id)
end
4. Проверка параллельного режима
print(isparallel() and "В параллельном режиме" or "В обычном режиме")
5. Работа с потоками акторов
for index, thread in getactorthreads() do
    print(index, thread)
end

local threads = getactorthreads()
if #threads > 0 then
    run_on_thread(threads[1], "print('Hello from Actor Thread!')")
end

Как проверяется в rUNC

Тест проверяет базовую работоспособность: getactors возвращает таблицу, isparallel возвращает boolean, а create_comm_channel возвращает ID и BindableEvent. Проверка выполнения кода на акторах (run_on_actor) тестируется на отсутствие ошибок.

Drawing

Библиотека для рендеринга 2D‑примитивов (линий, кругов, текста и т.д.) прямо на экране. Позволяет создавать и управлять графическими объектами поверх окна Roblox, изменять их свойства и удалять при необходимости.

Синтаксис

function Drawing.new(type: string, collect: boolean?): DrawingObject

type: Тип создаваемого объекта ("Line", "Circle", "Square", "Triangle", "Quad", "Text", "Image")
collect: (необязательно) Автоматически ли удалять объект при очистке.

Примеры

1. Рисование линии и текста
-- Создаём линию
local line = Drawing.new("Line")
line.From = Vector2.new(100, 100)
line.To = Vector2.new(200, 200)
line.Color = Color3.new(1, 0, 0) -- красный
line.Thickness = 2
line.Visible = true

-- Создаём текст
local text = Drawing.new("Text")
text.Text = "Hello, World!"
text.Position = Vector2.new(150, 150)
text.Color = Color3.new(0, 1, 0) -- зелёный
text.Size = 18
text.Font = Drawing.Fonts.UI
text.Visible = true

-- Удаляем объекты через 5 секунд
task.delay(5, function()
    line:Remove()
    text:Remove()
end)
2. Рисование круга
local circle = Drawing.new("Circle")
circle.Position = Vector2.new(300, 300)
circle.Radius = 50
circle.Filled = false
circle.Color = Color3.new(0, 0, 1) -- синий
circle.Thickness = 3
circle.Visible = true
3. Очистка всех объектов
-- Удаляет все объекты, созданные через Drawing
Drawing.clear()

-- Также можно очистить внутренний кэш
cleardrawcache()

Как проверяется в rUNC

  • Создание объекта: Проверяет, что Drawing.new("Circle") успешно выполняется и что результат проходит проверку isrenderobj.

debug.(get/set)upvalue(s)

Функции для интроспекции и модификации "upvalues" (внешних локальных переменных) Luau‑функции.

  • debug.getupvalues(func): Возвращает таблицу всех upvalue'ов функции.
  • debug.getupvalue(func, index): Возвращает upvalue по его индексу.
  • debug.setupvalue(func, index, value): Устанавливает новое значение для upvalue.

Примеры

1. Чтение и изменение upvalue
-- Функция, создающая замыкание с upvalue
local function makeDummy()
    local UpFunction = function()
        print("Мурзик 555")
    end

    local function DummyFunction()
        UpFunction()
    end

    return DummyFunction
end

local DummyFunction = makeDummy()

print("До подмены:")
DummyFunction() -- Мурзик 555

-- Читаем первый upvalue
local Retrieved = debug.getupvalue(DummyFunction, 1)
if type(Retrieved) == "function" then
    print("Upvalue найден, подменяем...")
    debug.setupvalue(DummyFunction, 1, function()
        print("Барсик 52")
    end)
else
    print("Upvalue не найден или это не функция")
end

print("После подмены:")
DummyFunction() -- Барсик 52
2. Получение всех upvalue'ов
local function outer()
    local a, b = 10, "test"
    return function()
        return a, b
    end
end

local fn = outer()
local upvalues = debug.getupvalues(fn)
for i, v in ipairs(upvalues) do
    print("Upvalue #" .. i, v)
end

Как проверяется в rUNC

  • Чтение: getupvalues и getupvalue вызываются для тестовой функции, и проверяется, что они возвращают правильные значения.
  • Запись: setupvalue используется для изменения upvalue. Затем тестовая функция вызывается снова, чтобы убедиться, что изменение вступило в силу. Также проверяется смена типа upvalue.
  • Граничные случаи: Тестируется поведение с функциями без upvalue'ов и с некорректными индексами.
  • C‑функции: Проверяется, что все три функции вызывают ошибку при попытке использовать их на C‑функциях.

debug.(get/set)constant(s)

Функции для интроспекции и модификации таблицы констант Luau‑функции. Константы — это литералы (числа, строки и т.д.), которые "зашиты" в байт‑код функции.

  • debug.getconstants(func): Возвращает таблицу всех констант.
  • debug.getconstant(func, index): Возвращает константу по индексу.
  • debug.setconstant(func, index, value): Заменяет константу новым значением.

Примеры

1. Изменение строки в функции
local function getFuncType(func)
    if islclosure(func) then
        return "Lua"
    else
        return "C"
    end
end

-- Функция с константами
local function demo()
    local a = "Hello"
    local b = "force_const"
    local c = (true or false)
    local d = ("nil_marker")
    return a, b, c, d
end

print("Тип функции demo:", getFuncType(demo))

print("\n=== До подмены ===")
print(demo())

-- Получаем константы
local constants = debug.getconstants(demo)
print("\nКонстанты в функции:")
for i, v in ipairs(constants) do
    if type(v) == "function" then
        print("["..i.."]", v, "(function, "..getFuncType(v)..")")
    else
        print("["..i.."]", v, "("..type(v)..")")
    end
end

-- Подменяем: все строки → "Павел Дуров"
for i, v in ipairs(constants) do
    if type(v) == "string" then
        debug.setconstant(demo, i, "Павел Дуров")
    end
end

print("\n=== После подмены ===")
print(demo())

-- Проверка на [C] или [Lua]
print("\nТип функции print:", getFuncType(print))
print("Тип функции math.sin:", getFuncType(math.sin))

Как проверяется в rUNC

Проверяет, что getconstants находит все типы констант (строки, числа, функции). Проверяет, что setconstant успешно меняет константу и это отражается на поведении функции.

debug.(get/set)stack

Функции для низкоуровневой работы со стеком вызовов.

  • debug.getstack(level, index): Получает локальную переменную со стека. level — уровень вложенности вызова (1 — текущая функция, 2 — та, что её вызвала, и т.д.), index — номер переменной.
  • debug.setstack(level, index, value): Устанавливает новое значение для локальной переменной на стеке. Тип нового значения должен совпадать с типом старого.

Примеры

1. Изменение переменной в родительской функции
local function parent(a, b)
    print("[parent] До подмены:", a, b)

    local function child()
        -- level = 2 → стек родителя
        -- index = 1 → первый аргумент (a)
        debug.setstack(2, 1, 666)

        -- index = 2 → второй аргумент (b)
        debug.setstack(2, 2, "кошка")
    end

    child()

    print("[parent] После подмены:", a, b)
end

-- Вызов: до подмены → 10, собака; после подмены → 666, кошка
parent(10, "собака")

Как проверяется в rUNC

  • Запись в родительский стек: Проверяет, что вызов debug.setstack с level=2 успешно изменяет локальную переменную в вызывающей функции.
  • Запись в текущий стек: Проверяет, что level=1 корректно изменяет переменную в текущей функции.
  • Несовпадение типов: Удостоверяется, что попытка установить значение другого типа вызывает ошибку.
  • C‑функции: Проверяет, что вызов на C‑фрейме стека вызывает ошибку.

debug.getproto(s)

Функции для работы с "прототипами" функций (шаблонами вложенных функций).

  • debug.getprotos(func): Возвращает таблицу всех прототипов (шаблонов) внутренних функций.
  • debug.getproto(func, index, active): Получает конкретный прототип. Если active=false, возвращается неактивный прототип, который нельзя вызвать. Если active=true, возвращается таблица активных экземпляров этого прототипа.

Примеры

1. Получение вложенной функции
local function container()
    local function innerOne()
        return "Привет из innerOne"
    end
    local function innerTwo()
        return "Привет из innerTwo"
    end
    return innerOne
end

-- Получаем все прототипы функции container
local protos = debug.getprotos(container)
print("Всего прототипов:", #protos)

for i, proto in ipairs(protos) do
    print(string.format("[%d] Прототип: %s", i, tostring(proto)))
    local consts = debug.getconstants(proto)
    if #consts > 0 then
        print("   Константы:", table.concat(consts, ", "))
    else
        print("   Констант нет")
    end
end

-- Получаем конкретный прототип по индексу (неактивный!!!)
local proto1 = debug.getproto(container, 1)
print("\nПрототип #1 (неактивный):", proto1)

-- Получаем активную функцию из прототипа
local activeFuncs = debug.getproto(container, 1, true)
print("Активные функции из прототипа #1:", #activeFuncs)

for i, f in ipairs(activeFuncs) do
    print("  Активная функция #" .. i .. " вызов ->", f())
end

Как проверяется в rUNC

Проверяет получение неактивных и активных прототипов, их вызов, а также ошибку на C‑функциях.

debug.setmetatable

Версия setmetatable из библиотеки debug, которая игнорирует защиту __metatable. Функционально идентична setrawmetatable.

Синтаксис

function debug.setmetatable(obj: table, mt: table|nil)

Примеры

1. Замена защищённой метатаблицы
-- Создаём таблицы с заблокированной метатаблицей
local pot = {}
local asus = {}

setmetatable(pot, { __metatable = "LOCKED", __tostring = function() return "Горшок" end })
setmetatable(asus, { __metatable = "LOCKED", __tostring = function() return "Асус" end })

print("До обхода защиты:")
print("pot:", pot)   -- Горшок
print("asus:", asus) -- Асус

-- Попытка обычной замены метатаблицы — не сработает
local ok, err = pcall(setmetatable, pot, { __tostring = function() return "Хакнутый горшок" end })
print("Обычная замена метатаблицы:", ok, err)

-- Обход защиты через debug.setmetatable
debug.setmetatable(pot, {
    __tostring = function() return "Горшок взломан" end,
    speak = function() return "Горшок 666" end
})

debug.setmetatable(asus, {
    __tostring = function() return "Асус взломан" end,
    speak = function() return "Асус легенда" end
})

print("\nПосле обхода защиты:")
print("pot:", pot)
print("asus:", asus)

-- Вызываем «методы» из новых метатаблиц
print("pot говорит:", getmetatable(pot).speak())
print("asus говорит:", getmetatable(asus).speak())

-- Проверим, что __metatable больше не LOCKED
print("\nТекущая метатаблица pot:", getmetatable(pot))
print("Текущая метатаблица asus:", getmetatable(asus))

Как проверяется в rUNC

Тест аналогичен test_setrawmetatable:

  • Подтверждение защиты: Убеждается, что обычная setmetatable не работает.
  • Обход защиты: Проверяет, что debug.setmetatable успешно устанавливает новую метатаблицу.
  • Проверка эффекта: Убеждается, что новая метатаблица активна и работает.

debug.getinfo

Возвращает таблицу с информацией о функции или уровне стека вызовов (имя, количество upvalue'ов, строка определения и т.д.).

Синтаксис

function debug.getinfo(target: function | number, flags: string?): table

Примеры

1. Информация о функции
local function my_func(a, b, ...)
    local x = 123
    return a + b + x
end

local ok, info = pcall(debug.getinfo, my_func, "nSluaf")

if ok and info then
    print("Имя:", info.name) --> my_func
    print("Источник:", info.source) --> "", то есть пусто
    print("Строка определения:", info.linedefined) --> nil
    print("Последняя строка:", info.lastlinedefined) --> nil
    print("Upvalues:", info.nups) --> 0
    print("Параметров:", info.nparams) --> nil
    print("Vararg:", info.isvararg) -- true/false или nil
    print("Функция:", info.func) --> function: 0x...
else
    print("Ошибка при получении информации:", info)
end
2. Информация о вызывающей функции
local function get_caller_info()
    -- "nf" → n = имя, f = сама функция
    local info = debug.getinfo(2, "nf") -- 2 = вызывающая функция
    return info.name, info.func
end

local function LadaGranta()
    local caller_name, caller_func = get_caller_info()
    print("Я вызвана функцией:", caller_name) --> LadaGranta
    print("Userdata функции:", caller_func) --> function: 0x...
end

LadaGranta()

Как проверяется в rUNC

  • Информация о функции: Вызывает getinfo для тестовой функции с разными флагами и проверяет, что поля (what, source, linedefined, nups, name) содержат корректные значения.
  • Информация по уровню стека: Вызывает getinfo с числовым аргументом (уровнем стека) и проверяет, что получает корректную информацию о текущей (level=1) и вызывающей (level=2) функциях.
  • C‑функции: Убеждается, что вызов getinfo для C‑функции вызывает ошибку.

Другие debug-функции

Набор дополнительных отладочных функций.

  • debug.setname(func, name): Устанавливает имя для функции, видимое в debug.getinfo.
  • debug.isvalidlevel(level): Проверяет, существует ли указанный уровень в стеке вызовов.

Синтаксис

function debug.setname(func: function, name: string)
function debug.isvalidlevel(level: number): boolean

Примеры

1. Переименование функции через debug.setname
local function my_function()
    return "Привет!"
end

print("Имя до:", debug.getinfo(my_function).name) -- my_function или nil

debug.setname(my_function, "Горшок")

print("Имя после:", debug.getinfo(my_function).name) -- Горшок
2. Проверка уровня стека через debug.isvalidlevel
print(debug.isvalidlevel(1))   -- true, текущий уровень стека существует
print(debug.isvalidlevel(100)) -- false, такого уровня нет

Как проверяется в rUNC

  • debug.setname: Устанавливает имя и проверяет через debug.getinfo, что оно изменилось.
  • debug.isvalidlevel: Проверяет, что возвращает true для валидного уровня и false для невалидного.

crypt.base64encode / crypt.base64decode

Функции для кодирования и декодирования строк в формат Base64.

  • crypt.base64encode(data): Кодирует строку.
  • crypt.base64decode(encoded_data): Декодирует строку.

Примеры

1. Простое кодирование и декодирование
local original = "Hello, Roblox!"
local encoded = crypt.base64encode(original)
print("Encoded:", encoded) --> SGVsbG8sIFJvYmxveCE=

local decoded = crypt.base64decode(encoded)
print("Decoded:", decoded) --> Hello, Roblox!

Как проверяется в rUNC

  • Round-trip: Кодирует строку, затем декодирует результат и проверяет, что он совпадает с оригиналом.
  • Известные значения: Кодирует и декодирует заранее известные строки и сверяет результат с ожидаемым, чтобы проверить корректность самого алгоритма.

crypt.encrypt / crypt.decrypt

Функции для симметричного шифрования и дешифрования данных с использованием AES.

  • crypt.encrypt(data, key, iv?, mode?): Шифрует данные. Возвращает зашифрованную строку (в Base64) и использованный IV (в Base64).
  • crypt.decrypt(ciphertext, key, iv, mode?): Расшифровывает данные, зашифрованные с помощью crypt.encrypt.

Синтаксис

function crypt.encrypt(data: string, key: string, iv: string?, mode: string?): (string, string)
function crypt.decrypt(ciphertext: string, key: string, iv: string, mode: string?): string

Примеры

1. Шифрование и дешифрование сообщения (AES-GCM)
-- Генерируем ключ и IV нужной длины
local key = crypt.generatekey(32)  -- 32 байта для AES-256
local iv = crypt.generatekey(12)   -- 12 байт для GCM

local plaintext = "Это секретное сообщение."

-- Шифруем
local ciphertext = crypt.encrypt(plaintext, key, iv, "aes-gcm")
print("Encrypted (base64):", crypt.base64encode(ciphertext))

-- Расшифровываем
local decrypted = crypt.decrypt(ciphertext, key, iv, "aes-gcm")
print("Decrypted:", decrypted)
2. Шифрование с автоматической генерацией IV (AES-CBC по умолчанию)
-- Генерируем ключ (Base64)
local key = crypt.generatekey(32)

-- Шифруем, IV сгенерируется автоматически
local encrypted, iv = crypt.encrypt("Секретное сообщение", key)
print("Encrypted:", encrypted)
print("IV:", iv)

-- Расшифровываем
local decrypted = crypt.decrypt(encrypted, key, iv)
print("Decrypted:", decrypted)

Как проверяется в rUNC

  • Round-trip: Генерирует ключ, шифрует строку, расшифровывает её тем же ключом и проверяет, что результат совпадает с оригиналом.
  • Неверный ключ: Пытается расшифровать данные с другим ключом и убеждается, что результат не совпадает с оригиналом.

crypt.generatekey / crypt.generatebytes

Функции для генерации криптографически стойких случайных данных.

  • crypt.generatekey(): Генерирует ключ для использования в crypt.encrypt/decrypt.
  • crypt.generatebytes(length): Генерирует случайную строку байт указанной длины.

Примеры

1. Генерация ключа и случайных данных
-- Генерируем новый ключ
local new_key = crypt.generatekey()
print("Сгенерированный ключ (base64):", crypt.base64encode(new_key))

-- Генерируем 32-байтный вектор инициализации (IV)
local random_iv = crypt.generatebytes(32)
print("Длина сгенерированного IV:", #random_iv) --> 44 (в base64)

Как проверяется в rUNC

  • generatekey: Проверяет, что функция возвращает непустую строку.
  • generatebytes: Проверяет, что функция возвращает строку, и что её длина в точности равна запрошенной.

crypt.hash

Вычисляет хэш строки, используя указанный алгоритм.

Синтаксис

function crypt.hash(data: string, algorithm: string): string

Примеры

1. Хэширование пароля
local password = "password123"
local hashed_password = crypt.hash(password, "sha512")
print("Hashed:", crypt.base64encode(hashed_password))

Как проверяется в rUNC

  • Успешное выполнение: Проверяет, что функция возвращает строку.
  • Детерминированность: Хэширует одну и ту же строку дважды и убеждается, что результаты полностью совпадают.

lz4compress / lz4decompress

Функции для быстрого сжатия и распаковки данных с использованием алгоритма LZ4.

  • lz4compress(data): Сжимает строку.
  • lz4decompress(compressed_data, original_size): Распаковывает строку. Требует знания исходного размера данных.

Примеры

1. Сжатие и распаковка текста
local original_text = table.concat({string.rep("roblox ", 100)}, "")
local original_size = #original_text

local compressed = lz4compress(original_text)
print(string.format("Original: %d bytes, Compressed: %d bytes", original_size, #compressed))
-- Пример вывода: Original: 700 bytes, Compressed: 19 bytes

local decompressed = lz4decompress(compressed, original_size)
print("Round-trip successful:", original_text == decompressed) --> true

Как проверяется в rUNC

  • Round-trip: Сжимает строку, затем распаковывает её, и проверяет, что результат в точности совпадает с исходной строкой.

request / http_request

Отправляет HTTP(S) запрос и возвращает ответ.

  • httpget(url): Выполняет HTTP GET-запрос и возвращает тело ответа в виде строки.
  • httppost(url, data, content_type?): Выполняет HTTP POST-запрос с указанными данными и типом содержимого.
  • request(options): Выполняет HTTP-запрос с расширенными параметрами (метод, заголовки, тело, куки и т.д.).
  • http.request(options): Альтернативный способ вызова request через таблицу http.

Примеры

1. Простой GET-запрос
local body = httpget("https://httpbin.org/get")
print("GET response body:", body)
2. Простой POST-запрос
local body = httppost(
    "https://httpbin.org/post",
    "key=value&test=123",
    "application/x-www-form-urlencoded"
)
print("POST response body:", body)
3. Запрос с расширенными параметрами
local response = request({
    Url = "https://httpbin.org/post",
    Method = "POST",
    Headers = {["Content-Type"] = "application/json"},
    Body = '{"name": "Горшок"}',
    Cookies = {session = "abc123"}
})

print("Success:", response.Success)
print("Status:", response.StatusCode, response.StatusMessage)
print("Body:", response.Body)
4. Обработка ошибки 404
local response = request({
    Url = "https://httpbin.org/status/404",
    Method = "GET"
})

print("Success:", response.Success) -- false
print("Status:", response.StatusCode) -- 404
print("Body:", response.Body)
5. Обработка невалидного URL
local ok, err = pcall(function()
    return httpget("ht!tp://invalid-url")
end)

print("OK:", ok)
print("Error:", err)

Как проверяется в rUNC

  • GET-запрос: Отправляется запрос на https://httpbin.org/get и проверяется, что ответ содержит ожидаемые данные.
  • POST-запрос: Отправляется запрос на https://httpbin.org/post с телом и заголовками, затем проверяется, что сервер получил корректные данные.
  • Расширенные параметры: Проверяется, что request корректно передаёт метод, заголовки, тело и куки.
  • Ошибка 404: Проверяется, что Success = false и StatusCode = 404.
  • Невалидный URL: Проверяется, что функция выбрасывает ошибку при передаче некорректного адреса.

Файловые операции

Набор функций для работы с файлами: writefile, readfile, appendfile, delfile, isfile.

Примеры

1. Создание и чтение файла
-- Записываем текст в файл
writefile("test.txt", "Привет, мир!")

-- Читаем содержимое файла
local content = readfile("test.txt")
print("Содержимое файла:", content)
2. Добавление данных в файл
-- Добавляем строку в конец файла
appendfile("test.txt", "\nНовая строка")

-- Проверяем результат
print(readfile("test.txt"))
3. Проверка существования файла
if isfile("test.txt") then
    print("Файл существует")
else
    print("Файл не найден")
end
4. Удаление файла
-- Удаляем файл
delfile("test.txt")

-- Проверяем, что файл удалён
print("Файл существует после удаления:", isfile("test.txt"))

Как проверяется в rUNC

Тест последовательно выполняет все операции, проверяя создание, чтение, добавление, перезапись и удаление файла.

Операции с папками

Набор функций для управления папками: makefolder, isfolder, listfiles, delfolder.

Примеры

1. Создание и проверка существования папки
-- Создаём папку
makefolder("MyFolder")

-- Проверяем, что папка существует
if isfolder("MyFolder") then
    print("Папка успешно создана")
else
    print("Папка не найдена")
end
2. Получение списка файлов в папке
-- Создаём тестовые файлы
writefile("MyFolder/file1.txt", "Содержимое 1")
writefile("MyFolder/file2.txt", "Содержимое 2")

-- Получаем список файлов
local files = listfiles("MyFolder")
print("Файлы в папке:")
for _, file in ipairs(files) do
    print(file)
end
3. Удаление папки
-- Удаляем папку
delfolder("MyFolder")

-- Проверяем, что папка удалена
print("Папка существует после удаления:", isfolder("MyFolder"))

Как проверяется в rUNC

Тест проверяет создание, листинг содержимого и удаление папки.

loadfile

Читает файл, содержащий Lua‑код, и компилирует его в функцию.

Синтаксис

function loadfile(filename: string): function | nil, string

filename — путь к файлу с Lua‑кодом.
Возвращает скомпилированную функцию или nil и сообщение об ошибке, если файл не удалось загрузить или скомпилировать.

Примеры

1. Загрузка и выполнение корректного Lua‑кода из файла
-- Создаём файл с корректным Lua‑кодом
writefile("test_script.lua", [[
    return function(name)
        return "Привет, " .. name .. "!"
    end
]])

-- Загружаем файл
local chunk, err = loadfile("test_script.lua")
if not chunk then
    error("Ошибка загрузки: " .. err)
end

-- Выполняем загруженный код, получаем функцию
local greet = chunk()
print(greet("Горшок")) -- Привет, Горшок!
2. Обработка ошибки при некорректном коде
-- Перезаписываем файл с ошибочным Lua‑кодом
writefile("test_script.lua", [[
    return function()
        local a = 10 +
    end
]])

-- Пытаемся загрузить файл
local chunk, err = loadfile("test_script.lua")
if not chunk then
    print("Ошибка при компиляции:", err)
else
    print("Неожиданно удалось загрузить файл")
end

Как проверяется в rUNC

  • Корректный код: Создаёт файл с рабочим Lua‑кодом, загружает его через loadfile, выполняет и проверяет результат.
  • Некорректный код: Перезаписывает файл с синтаксической ошибкой, вызывает loadfile и убеждается, что возвращается nil и сообщение об ошибке.

getcustomasset

Преобразует локальный путь к файлу в формат rbxasset://, который можно использовать в Roblox API для загрузки аудио, моделей, изображений интерфейса и других типов ассетов.

Внутренне файл копируется в директорию контента игры и становится доступен по сгенерированному URL.

Синтаксис

function getcustomasset(path: string): string

Примеры

1. Загрузка и воспроизведение локального звука
-- Скачиваем и сохраняем mp3-файл
local encoded = game:HttpGet("https://example.com/sound_base64.txt")
writefile("ExampleSound.mp3", crypt.base64decode(encoded))

-- Получаем asset ID
local asset_id = getcustomasset("ExampleSound.mp3")
print("Asset ID:", asset_id) -- rbxasset://...

-- Создаём и воспроизводим звук
local sound = Instance.new("Sound")
sound.Parent = workspace
sound.SoundId = asset_id
sound.Volume = 0.35
sound:Play()
2. Использование изображения в UI
-- Сохраняем локальный PNG
writefile("Icon.png", game:HttpGet("https://example.com/icon.png"))

-- Получаем asset ID
local icon_asset = getcustomasset("Icon.png")

-- Создаём ImageLabel с этим изображением
local image = Instance.new("ImageLabel")
image.Size = UDim2.new(0, 100, 0, 100)
image.Image = icon_asset
image.Parent = game.Players.LocalPlayer:WaitForChild("PlayerGui")

Как проверяется в rUNC

  • Создаёт временный файл с тестовыми данными.
  • Вызывает getcustomasset для этого файла.
  • Проверяет, что возвращаемая строка начинается с rbxasset:// и является корректным asset ID.

WebSocket

Клиентский класс для работы с WebSocket‑соединениями в Lua.

Конструктор, события и методы

  • WebSocket.New(url) / WebSocket.new(url) / WebSocket.connect(url) / WebSocket.Connect(url) — создаёт новое WebSocket‑соединение и возвращает объект WebSocketClient.
  • ws:Send(message) / ws:send(message) — отправляет сообщение на сервер.
  • ws:Close() / ws:close() — закрывает соединение.
  • ws.OnMessage — событие, вызываемое при получении сообщения от сервера.
  • ws.OnClose — событие, вызываемое при закрытии соединения.

Примеры

1. Простое подключение и обмен сообщениями
-- Создаём новое соединение
local ws = WebSocket.New("ws://echo.websocket.org")

-- Обработчик входящих сообщений
ws.OnMessage:Connect(function(message)
    print("Получено:", message)
end)

-- Обработчик закрытия соединения
ws.OnClose:Connect(function()
    print("Соединение закрыто")
end)

-- Отправляем сообщение
ws:Send("Привет, сервер!")

-- Закрываем соединение через 5 секунд
task.delay(5, function()
    ws:Close()
end)
2. Эхо‑сервер: отправка ответа на каждое сообщение
local ws = WebSocket.connect("ws://example.com/socket")

ws.OnMessage:Connect(function(message)
    print("Получено:", message)
    ws:Send("Эхо: " .. message)
end)

ws.OnClose:Connect(function()
    print("Соединение закрыто сервером")
end)

ws:Send("Первое сообщение")

Как проверяется в rUNC

Тесты для WebSocket исключены из rUNC из‑за проблем со стабильностью. Раздел носит информационный характер.