gamesensical read-only
/

gamesensical — read-only API

CS2 Dev · обновлено 14.10.2026. Слой совместимости следует контрактам gamesensical, адаптируя их к внешнему чтению CS2. Это поддержанное подмножество API; оригинальная документация не означает, что любая её функция доступна здесь. Существующие events, render, schema, config, thread и ui продолжают работать.

События и жизненный цикл

ВызовПоведение
client.set_event_callback(name, fn)Зарегистрировать функцию; повторная регистрация той же функции не дублирует вызовы
client.unset_event_callback(name, fn)Снять именно эту функцию
client.delay_call(seconds, fn, ...)Отложенный вызов с аргументами; 0–86400 секунд, без блокировки кадра

Доступны paint, paint_ui, shutdown и собственное событие read_only_tick. paint и paint_ui вызываются каждый кадр оверлея, в том числе вне матча. read_only_tick — обновление оверлея, а не серверный тик или usercmd. shutdown вызывается при выгрузке/reload.

Неизвестное событие вызывает Lua-ошибку. setup_command, run_command, net_update_end, player_death и другие игровые события не имитируются. Ошибки callbacks попадают в менеджер; остальные функции события могут продолжить работу. Лимит — 64 callbacks на событие и действующий бюджет примерно 250 000 инструкций на вызов.

entity — чтение игроков

ВызовРезультат
entity.get_local_player()Индекс локального игрока или nil
entity.get_players(enemies_only?)Таблица индексов живых игроков; true оставляет противников
entity.is_alive(index)Boolean
entity.is_enemy(index)Boolean относительно локального игрока
entity.get_player_name(index)Имя или nil
entity.get_origin(index)x, y, z или nil
entity.get_player_weapon(index)Индекс активного оружия или nil
entity.get_steam64(index)SteamID строкой без потери 64-битной точности или nil
entity.get_classname(index)Совместимый идентификатор CCSPlayer для игрока; ключ каталога CS2 для оружия
entity.get_prop(index, property, array_index?)Прочитанное значение; неизвестное свойство или отсутствующая сущность → nil
entity.hitbox_position(index, hitbox)x, y, z соответствующего сустава скелета или nil
entity.get_bounding_box(index)left, top, right, bottom, alpha; при отсутствии проекции alpha = 0

Снимки собираются на следующем overlay-кадре после запроса. Первый запрос может вернуть пустой список или nil. Индексы берутся из списка сущностей; оружие имеет собственный индекс, а не индекс владельца. Проверяйте данные после смены карты, смерти и отключения.

get_prop поддерживает m_iHealth, m_ArmorValue, m_fFlags, m_iTeamNum, m_bIsScoped, m_bHasHelmet, m_vecOrigin, m_vecAbsOrigin, m_vecVelocity, m_vecAbsVelocity, m_hActiveWeapon. Векторы возвращают три числа; индекс компонента начинается с 0. Для индекса оружия доступны m_iClip1 и m_iItemDefinitionIndex.

hitbox_position сопоставляет hitbox ID CS:GO с суставами CS2. Это приближение позиции, а не центр точной collision-капсулы. Bounding box тоже рассчитывается по скелету и origin.

client — камера, время и трассировки

ВызовРезультат
client.screen_size()width, height в пикселях
client.eye_position()Текущий origin камеры x, y, z, иначе nil
client.camera_angles()pitch, yaw, иначе nil; аргументы запрещены, запись углов недоступна
client.key_state(vk)Удерживается ли Windows virtual key 1–255
client.latency()Ping локального игрока в секундах, иначе nil
client.timestamp()Время оверлея в миллисекундах
client.unix_time()Unix-время в секундах
client.system_time()hours, minutes, seconds, milliseconds Windows
client.random_int(min, max)Случайное целое
client.random_float(min, max)Случайное число
client.log(...), client.error_log(...)Сообщение в лог скрипта; аргументы объединяются
client.color_log(r, g, b, ...)То же сообщение; RGB-форматирование консоли не воспроизводится
client.visible(x, y, z)Видимость по статическому BVH карты или nil
client.trace_line(skip_index, x, y, z, x2, y2, z2)fraction, index; fraction 0–1, index всегда -1 для статического мира

Трассировки учитывают загруженную статическую геометрию карты. Игроки, подвижные двери, разрушаемые объекты и дым не трассируются; skip_index не меняет статический результат. Если BVH или камера недоступны, вернётся nil.

globals — игровые значения

globals.realtime() возвращает время оверлея в секундах. globals.curtime(), tickcount(), framecount(), frametime(), absoluteframetime() и maxplayers() читают игровые globals и могут вернуть nil вне матча или при неудачном чтении. globals.mapname() возвращает карту или nil.

globals.tickinterval и счётчики команд не предоставляются: значения не подменяются догадками. Для длительности overlay-кадра существует client.frame_time() из базового API.

renderer — рисование

Рисуйте из paint / paint_ui. Вне этих событий примитивы совместимого renderer пропускаются. Координаты — экранные пиксели, цвета RGBA 0–255.

ВызовНазначение
renderer.world_to_screen(x, y, z)screen_x, screen_y или nil
renderer.line(x1, y1, x2, y2, r, g, b, a)Линия
renderer.rectangle(x, y, w, h, r, g, b, a)Заполненный прямоугольник
renderer.gradient(x, y, w, h, r1, g1, b1, a1, r2, g2, b2, a2, horizontal)Градиент
renderer.triangle(x1, y1, x2, y2, x3, y3, r, g, b, a)Заполненный треугольник
renderer.circle(x, y, r, g, b, a, radius, start_degrees, percentage)Заполненный круг/сектор
renderer.circle_outline(x, y, r, g, b, a, radius, start_degrees, percentage, thickness)Контур круга/дуги
renderer.text(x, y, r, g, b, a, flags, max_width, ...)Текст с обводкой и ограничением ширины; 0 отключает ограничение
renderer.measure_text(flags, ...)width, height текста
renderer.indicator(r, g, b, a, ...)Индикатор слева; возвращает экранный y

percentage — 0–1. Флаги текста: c — центр, r — справа, - — маленький, + — большой. Другие шрифтовые флаги, загрузка изображений/текстур, SVG и собственных шрифтов не реализованы.

ui — собственные элементы меню

Элементы появляются под скриптом во вкладке Lua. tab и container принимаются для совместимости исходника; они не встраивают элементы в меню CS2. Значения находятся в памяти скрипта и сбрасываются после reload.

ВызовЗначение ui.get(ref)
ui.new_checkbox(tab, container, name)Boolean, по умолчанию false
ui.new_slider(tab, container, name, min, max, initial?, tooltip?, unit?, scale?, tooltips?)Целое в диапазоне min–max
ui.new_color_picker(tab, container, name, r?, g?, b?, a?)Четыре целых r, g, b, a
ui.new_combobox(tab, container, name, ...)Строка выбранного варианта; варианты также можно передать таблицей
ui.new_multiselect(tab, container, name, ...)Таблица выбранных строк
ui.new_listbox(tab, container, name, items)Индекс, начиная с 0; визуально отображается списком выбора
ui.new_textbox(tab, container, name)Строка
ui.new_string(name, initial?)Строка без видимого элемента
ui.new_hotkey(tab, container, name, inline?, default_key?)Удерживается ли выбранная клавиша
ui.new_label(tab, container, name)Текст метки
ui.new_button(tab, container, name, callback)Кнопка вызывает callback; ui.get для кнопки не используйте

ui.set(ref, value, ...) меняет только эти контролы: checkbox — boolean, slider — число, combobox — строка, multiselect — строки или таблица, color picker — четыре числа RGBA. Неверная ссылка/тип/вариант вызывает Lua-ошибку. ui.set для кнопки вызывает её callback; для hotkey принимает virtual key 0–255.

ui.name(ref) возвращает имя, ui.set_visible(ref, bool) меняет видимость, ui.set_callback(ref, fn) задаёт callback изменения. ui.update(ref, ...) заменяет варианты combobox/listbox/multiselect и сбрасывает выбор. ui.is_menu_open() и ui.mouse_position() читают состояние оверлея.

Лимит — 128 контролов на скрипт. Hotkey пока работает только при удержании; строковые режимы hotkey, встроенные ui.reference, координаты меню, tooltip/scale-форматирование слайдеров и inline-раскладка не реализованы. Не меняйте контрол рекурсивно из его callback.

Пример: подписи игроков

local enabled = ui.new_checkbox("VISUALS", "Other ESP", "Read-only player labels")
local tint = ui.new_color_picker("VISUALS", "Other ESP", "Label RGBA", 120, 200, 255, 210)
ui.set(enabled, true)

client.set_event_callback("paint", function()
    if not ui.get(enabled) then return end
    local r, g, b, a = ui.get(tint)
    for _, id in ipairs(entity.get_players(true)) do
        local x, y, z = entity.get_origin(id)
        if x then
            local sx, sy = renderer.world_to_screen(x, y, z + 80)
            if sx then
                renderer.text(sx, sy, r, g, b, a, "c", 0, entity.get_player_name(id))
            end
        end
    end
end)

Что отсутствует

entity.set_prop, FFI, запись памяти, client.exec, создание интерфейсов, vtable-вызовы, client.find_signature, изменение usercmd и запись camera angles не экспортируются. Неподдержанные функции не выдают фиктивный успешный результат. Lua io, os, debug, loadfile, dofile и загрузка нативных библиотек отключены. Сохраняйте явные проверки nil и переносите скрипты с учётом описанных отличий.