Вопросы по Lua скриптингу

Общая тема для вопросов по разработке скриптов на языке программирования Lua, в частности под MoonLoader.
  • Задавая вопрос, убедитесь, что его нет в списке частых вопросов и что на него ещё не отвечали (воспользуйтесь поиском).
  • Поищите ответ в теме посвященной разработке Lua скриптов в MoonLoader
  • Отвечая, убедитесь, что ваш ответ корректен.
  • Старайтесь как можно точнее выразить мысль, а если проблема связана с кодом, то обязательно прикрепите его к сообщению, используя блок [code=lua]здесь мог бы быть ваш код[/code].
  • Если вопрос связан с MoonLoader-ом первым делом желательно поискать решение на wiki.

Частые вопросы

Как научиться писать скрипты? С чего начать?
Информация - Гайд - Всё о Lua скриптинге для MoonLoader(https://blast.hk/threads/22707/)
Как вывести текст на русском? Вместо русского текста у меня какие-то каракули.
Изменить кодировку файла скрипта на Windows-1251. В Atom: комбинация клавиш Ctrl+Shift+U, в Notepad++: меню Кодировки -> Кодировки -> Кириллица -> Windows-1251.
Как получить транспорт, в котором сидит игрок?
Lua:
local veh = storeCarCharIsInNoSave(PLAYER_PED)
Как получить свой id или id другого игрока?
Lua:
local _, id = sampGetPlayerIdByCharHandle(PLAYER_PED) -- получить свой ид
local _, id = sampGetPlayerIdByCharHandle(ped) -- получить ид другого игрока. ped - это хендл персонажа
Как проверить, что строка содержит какой-то текст?
Lua:
if string.find(str, 'текст', 1, true) then
-- строка str содержит "текст"
end
Как эмулировать нажатие игровой клавиши?
Lua:
local game_keys = require 'game.keys' -- где-нибудь в начале скрипта вне функции main

setGameKeyState(game_keys.player.FIREWEAPON, -1) -- будет сэмулировано нажатие клавиши атаки
Все иды клавиш находятся в файле moonloader/lib/game/keys.lua.
Подробнее о функции setGameKeyState здесь: lua - setgamekeystate | BlastHack — DEV_WIKI(https://www.blast.hk/wiki/lua:setgamekeystate)
Как получить id другого игрока, в которого целюсь я?
Lua:
local valid, ped = getCharPlayerIsTargeting(PLAYER_HANDLE) -- получить хендл персонажа, в которого целится игрок
if valid and doesCharExist(ped) then -- если цель есть и персонаж существует
  local result, id = sampGetPlayerIdByCharHandle(ped) -- получить samp-ид игрока по хендлу персонажа
  if result then -- проверить, прошло ли получение ида успешно
    -- здесь любые действия с полученным идом игрока
  end
end
Как зарегистрировать команду чата SAMP?
Lua:
-- До бесконечного цикла/задержки
sampRegisterChatCommand("mycommand", function (param)
     -- param будет содержать весь текст введенный после команды, чтобы разделить его на аргументы используйте string.match()
    sampAddChatMessage("MyCMD", -1)
end)
Крашит игру при вызове sampSendChat. Как это исправить?
Это происходит из-за бага в SAMPFUNCS, когда производится попытка отправки пакета определенными функциями изнутри события исходящих RPC и пакетов. Исправления для этого бага нет, но есть способ не провоцировать его. Вызов sampSendChat изнутри обработчика исходящих RPC/пакетов нужно обернуть в скриптовый поток с нулевой задержкой:
Lua:
function onSendRpc(id)
  -- крашит:
  -- sampSendChat('Send RPC: ' .. id)

  -- норм:
  lua_thread.create(function()
    wait(0)
    sampSendChat('Send RPC: ' .. id)
  end)
end
 
Последнее редактирование:

Vintik

Через тернии к звёздам
Проверенный
1,493
955
При создании объекта через lua за пределами игровой карты их не видно. Можно как-то исправить это?
Пробовал эмуляцией RPC?

как получить данные из
OnPlayerEnterDynamicArea хуком? @

ChromiusJ

Эта функция, как я понял, обрабатывается на стороне сервера, а не игрового клиента.
Тебе нужно, чтобы срабатывал скрипт при входе в какую-либо область?
Используй функцию getCharCoordinates() в цикле.
Или в чём суть задачи?

help!
SAMP 0.3.7 R3-1 CRMP
Lua:
function getAimPacketData()
    local aimptr = allocateMemory(31)
    local _, pid = sampGetPlayerIdByCharHandle(PLAYER_PED)
    sampStorePlayerAimData(pid, aimptr)
    pdata[counter].mode = memory.getuint8(aimptr)
    pdata[counter].cx = memory.getfloat(aimptr + 1)
    pdata[counter].cy = memory.getfloat(aimptr + 5)
    pdata[counter].cz = memory.getfloat(aimptr + 9)
    pdata[counter].px = memory.getfloat(aimptr + 13)
    pdata[counter].py = memory.getfloat(aimptr + 17)
    pdata[counter].pz = memory.getfloat(aimptr + 21)
    pdata[counter].az = memory.getfloat(aimptr + 25)
    pdata[counter].zoom = memory.getuint8(aimptr + 29)
    pdata[counter].wstate = memory.getuint8(aimptr + 30)
    pdata[counter].unk = memory.getuint8(aimptr + 31)
    freeMemory(aimptr)
end
крашит полностью самп, без всяких окошек краша

UPD: Год назад вроде все воркало, сборка с библиотеками и версиями муна\функса та же вроде.
На данный момент перешарил интернет в поиске подробностей о "sampStorePlayerAimData"
Испробовал все версии муна, функса, клео
А какая задача?
 
Последнее редактирование:

UnikalnoeName

Известный
20
1

Vintik мне нужно взять координаты при заходе игрока в динамическую зону​

(коорды прописанные самим сервером) к примеру функция CreateDynamicSphere со стороны сервера, есть ли какие нибудь хуки?​

 

corner xyz

Участник
63
19
А какая задача
это скрипт который все пакеты сохраняет, потом можно воспроизвести на клиенте RakSamp

[RakBot] OnFoot/InCar Route Recording System

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

Maxim25012

Известный
277
101
неа, имею ввиду, можно ли как то дистанционно ее пиздить руками/оружием например?
Не. Насколько я понял, урон машине обрабатывается клиентом водителя, то есть урон машине наносится только тогда, когда это происходит локально у водителя, и его клиент должен самостоятельно отправлять изменившееся здоровье машины. Именно поэтому всякие ГМ на машины до сих пор работают.
 
  • Нравится
  • Грустно
Реакции: Vintik и minxty

Vintik

Через тернии к звёздам
Проверенный
1,493
955
неа, имею ввиду, можно ли как то дистанционно ее пиздить руками/оружием например?
Я ж и говорю, инициировать поломку автомобиля должен её водитель.
Чисто теоретически ты можешь сделать фейк-выстрел (либо выстрел не фейк, но изменить координаты выстрела; как в дамагере).
Как пример, фейк выстрел:
function cmd()
    -- это пример кода, естественно тебе надо будет самому придумать координаты начала выстрела (origin) и координаты цели (target)
    -- координаты надо выбрать такие, чтобы выстрел попадал в машину, тогда у водителя отобразится летящая пуля и он сам скажет серверу, мол, по мне попали
    local data = samp_create_sync_data('bullet', false)
    data.targetType = 1
    data.targetId = any_player_id
    data.origin.x, data.origin.y, data.origin.z = getActiveCameraCoordinates()
    data.target.x, data.target.y, data.target.z = target_x, target_y, target_z
    data.weaponId = getCurrentCharWeapon(PLAYER_PED)
    data.send()
end

function main()
    sampRegisterChatCommand('fake_shot', cmd)
end

Vintik мне нужно взять координаты при заходе игрока в динамическую зону​

(коорды прописанные самим сервером) к примеру функция CreateDynamicSphere со стороны сервера, есть ли какие нибудь хуки?​

Нет, это событие (OnPlayerEnterDynamicArea) обрабатывается исключительно на сервере. Клиент не знает динамических зон, которые создал сервер с помощью CreateDynamicSphere.
Ты можешь только догадываться где они есть и делать аналогичную проверку, исходя из своих координат. Например:
Зона в форме сферы вокруг точки:
local positionX, positionY, positionZ = getCharCoordinates(PLAYER_PED)
-- например, вокруг точки с координатами 12, 28, -35 с радиусом 55
distance = getDistanceBetweenCoords3d(12, 28, -35,    positionX, positionY, positionZ)
if distance <= 55 then
    -- значит ты находишься внутри сферы
else
    -- значит снаружи
end

это скрипт который все пакеты сохраняет, потом можно воспроизвести на клиенте RakSamp

[RakBot] OnFoot/InCar Route Recording System

сам скрипт для воспроизведения есть, переделанный под RakSamp, версия в которой нету считывания аима работает и записывает, но без синхры аима бот нормально ходить не может, его болтает во все стороны
Если задача сохранять AimData, то я бы это делал не так. Можно принудительно слать AimData и ловить её в событии onSendPacket (SAMP.Lua).
Lua:
-- В момент, когда тебе надо сохранить AimData
sampForceAimSync()



-- Ловишь в событии SAMP.Lua
local ev = require 'samp.events'

local pdata = {}

function ev.onSendAimSync(data)
    pdata = data
end
Формат таблицы data вот:
C++:
typedef struct AimSyncData {
    uint8_t   camMode;
    VectorXYZ camFront;
    VectorXYZ camPos;
    float     aimZ;
    uint8_t   camExtZoom : 6;
    uint8_t   weaponState : 2;
    uint8_t   aspectRatio;
} AimSyncData;
А дальше с pdata что хочешь, то и делай. Сохраняй в файл, добавляй в общую какую-то таблицу, воспроизводи — что угодно.
 
Последнее редактирование:
  • Нравится
  • Влюблен
Реакции: corner xyz и minxty

хромиус)

:steamhappy:
Друг
4,973
3,240
неа, имею ввиду, можно ли как то дистанционно ее пиздить руками/оружием например?
тут такое есть
 
  • Влюблен
Реакции: minxty

UnikalnoeName

Известный
20
1
Я ж и говорю, инициировать поломку автомобиля должен её водитель.
Чисто теоретически ты можешь сделать фейк-выстрел (либо выстрел не фейк, но изменить координаты выстрела; как в дамагере).
Как пример, фейк выстрел:
function cmd()
    -- это пример кода, естественно тебе надо будет самому придумать координаты начала выстрела (origin) и координаты цели (target)
    -- координаты надо выбрать такие, чтобы выстрел попадал в машину, тогда у водителя отобразится летящая пуля и он сам скажет серверу, мол, по мне попали
    local data = samp_create_sync_data('bullet', false)
    data.targetType = 1
    data.targetId = any_player_id
    data.origin.x, data.origin.y, data.origin.z = getActiveCameraCoordinates()
    data.target.x, data.target.y, data.target.z = target_x, target_y, target_z
    data.weaponId = getCurrentCharWeapon(PLAYER_PED)
    data.send()
end

function main()
    sampRegisterChatCommand('fake_shot', cmd)
end


Нет, это событие (OnPlayerEnterDynamicArea) обрабатывается исключительно на сервере. Клиент не знает динамических зон, которые создал сервер с помощью CreateDynamicSphere.
Ты можешь только догадываться где они есть и делать аналогичную проверку, исходя из своих координат. Например:
Зона в форме сферы вокруг точки:
local positionX, positionY, positionZ = getCharCoordinates(PLAYER_PED)
-- например, вокруг точки с координатами 12, 28, -35 с радиусом 55
distance = getDistanceBetweenCoords3d(12, 28, -35,    positionX, positionY, positionZ)
if distance <= 55 then
    -- значит ты находишься внутри сферы
else
    -- значит снаружи
end


Если задача сохранять AimData, то я бы это делал не так. Можно принудительно слать AimData и ловить её в событии onSendPacket (SAMP.Lua).
Lua:
-- В момент, когда тебе надо сохранить AimData
sampForceAimSync()



-- Ловишь в событии SAMP.Lua
local ev = require 'samp.events'

local pdata = {}

function ev.onSendAimSync(data)
    pdata = data
end
Формат таблицы data вот:
C++:
typedef struct AimSyncData {
    uint8_t   camMode;
    VectorXYZ camFront;
    VectorXYZ camPos;
    float     aimZ;
    uint8_t   camExtZoom : 6;
    uint8_t   weaponState : 2;
    uint8_t   aspectRatio;
} AimSyncData;
А дальше с pdata что хочешь, то и делай. Сохраняй в файл, добавляй в общую какую-то таблицу, воспроизводи — что угодно.
другой паблик можно OnPlayerEnterArea ?
 

UnikalnoeName

Известный
20
1
Я не понимаю твоего вопроса. Я же уже ответил полностью.
Назови конечную цель — и я скажу как тебе её реализовать.
цель: взять координаты X, Y и Z с радиусом из функции CreateDynamicSphere
где тут (Blast.hk) видел код где хуком брали другой паблик - OnPlayerStateChange
 

FreX

Активный
149
40
Как заменить самповский диалог на mimgui? Ну чтобы все и воркало. Если есть скрипт у вас киньте я сам разберусь