Вопросы по 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
 
Последнее редактирование:

Dmitriy Makarov

25.05.2021
Проверенный
2,500
1,131
Lua:
if sampTextdrawIsExists(ID_Текстдрава) then
    sampSendClickTextdraw(ID_Текстдрава)
end
ID текстдравов могут повторяться. Где-то краем ушка слышал, что дополнительно проверяют координаты текстдрава, чтобы не кликнуть на левый текстдрав с таким же ID. Но это уже с помощью onShowTextDraw (Или как там событие называется)
 
  • Нравится
Реакции: ShitKatsan

accord-

Потрачен
437
79
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
ImGui::TogleButton это кастомная функа, там используется ImGui::InvisibleButton, так что логично если Button
Нету InvisibleButton, мне именно цвет ползунка поменять
1651038164774.png
, imgui если что
 

Smeruxa

Известный
1,359
721
Так я не понимаю, тебе на луа или на с++ надо
Причем тут это?

та ну, так не интерсно)
У тебя поток прошлый не завершается, скорее всего, поэтому рисуется снова, теперь разбирайся
P.s. да, там break нету почему-то, ты ведь перенес это в поток, а потом это как отдельная хуйня, так еще и беск цикл херачнул, оно будет работать всегда, т.е. в конце тебе надо поставить break, сейчас с тулса своего скину как я реализовал
P.s. Тупо объяснил, короче
Когда ты вызываешь функцию, ты создаешь новый поток, в потоке пишешь беск. цикл, а потом когда ты тепаешься - цикл не завершается. Текст у тебя рисуется тогда, когда курсор включен, а ты когда тепаешься - его отключаешь, НО цикл у тебя - не завершается. В следующий раз, когда ты тепнешься куда-то, у тебя уже два потока будет, т.е. будет два текста, т.к. у тебя включен курсор и т.д.
Lua:
    lua_thread.create(function()
        while true do
            if cursorEnabled then
                local mode = sampGetCursorMode()
                if mode == 0 then
                    showCursor(true)
                end
                local sx, sy = getCursorPos()
                local sw, sh = windowCoordinates[1], windowCoordinates[2]
                local color = join_argb(255, elements.colors.colorClickWarpText.r, elements.colors.colorClickWarpText.g, elements.colors.colorClickWarpText.b)
                if sx >= 0 and sy >= 0 and sx < sw and sy < sh then
                    local posX, posY, posZ = convertScreenCoordsToWorld3D(sx, sy, 700.0)
                    local camX, camY, camZ = getActiveCameraCoordinates()
                    local result, colpoint = processLineOfSight(camX, camY, camZ, posX, posY, posZ, true, true, false, true, false, false, false)
                    if result and colpoint.entity ~= 0 then
                        local normal = colpoint.normal
                        local pos = Vector3D(colpoint.pos[1], colpoint.pos[2], colpoint.pos[3]) - (Vector3D(normal[1], normal[2], normal[3]) * 0.1)
                        local zOffset = 300
                        if normal[3] >= 0.5 then zOffset = 1 end
                        local result, colpoint2 = processLineOfSight(pos.x, pos.y, pos.z + zOffset, pos.x, pos.y, pos.z - 0.3, true, true, false, true, false, false, false)
                        if result then
                            pos = Vector3D(colpoint2.pos[1], colpoint2.pos[2], colpoint2.pos[3] + 1)
                            local curX, curY, curZ  = getCharCoordinates(playerPed)
                            local dist              = getDistanceBetweenCoords3d(curX, curY, curZ, pos.x, pos.y, pos.z)
                            local hoffs             = renderGetFontDrawHeight(fonts.clickWarp)
                            sy = sy - 2
                            sx = sx - 2
                            renderFontDrawText(fonts.clickWarp, string.format("%0.2fm", dist), sx, sy - hoffs, color)
                            local tpIntoCar = nil
                            if colpoint.entityType == 2 then
                                local car = getVehiclePointerHandle(colpoint.entity)
                                if doesVehicleExist(car) and (not isCharInAnyCar(playerPed) or storeCarCharIsInNoSave(playerPed) ~= car) then
                                    displayVehicleName(sx, sy - hoffs * 2, getNameOfVehicleModel(getCarModel(car)))
                                    if isKeyDown(VK_RBUTTON) then
                                        tpIntoCar = car
                                    end
                                    renderFontDrawText(fonts.clickWarp, "Hold right mouse button to teleport into the car", sx, sy - hoffs * 3, color)
                                end
                            end
                            createPointMarker(pos.x, pos.y, pos.z)
                            if isKeyDown(VK_LBUTTON) then
                                if tpIntoCar then
                                    if not jumpIntoCar(tpIntoCar) then
                                        teleportPlayer(pos.x, pos.y, pos.z)
                                        local veh = storeCarCharIsInNoSave(playerPed)
                                        local cordsVeh = {getCarCoordinates(veh)}
                                        setCarCoordinates(veh, cordsVeh[1], cordsVeh[2], cordsVeh[3])
                                        cursorEnabled = false
                                        showCursor(false)
                                        removePointMarker()
                                        break
                                    end
                                else
                                    if isCharInAnyCar(playerPed) then
                                        local norm = Vector3D(colpoint.normal[1], colpoint.normal[2], 0)
                                        local norm2 = Vector3D(colpoint2.normal[1], colpoint2.normal[2], colpoint2.normal[3])
                                        rotateCarAroundUpAxis(storeCarCharIsInNoSave(playerPed), norm2)
                                        pos = pos - norm * 1.8
                                        pos.z = pos.z - 1.1
                                    end
                                    teleportPlayer(pos.x, pos.y, pos.z)
                                    cursorEnabled = false
                                    showCursor(false)
                                    removePointMarker()
                                    break
                                end
                                while isKeyDown(VK_LBUTTON) do wait(0) end
                                cursorEnabled = false
                                showCursor(false)
                                removePointMarker()
                                break
                            end
                        end
                    end
                end
            end
            wait(0)
            removePointMarker()
        end
        cursorEnabled = false
        showCursor(false)
        removePointMarker()
    end)
end
 
Последнее редактирование:
  • Нравится
Реакции: sat0ry

shrug228

Активный
212
75
Через asyncHttpResponse получаю данные и перевожу в JSON:
Lua:
asyncHttpRequest('GET', url, nil, function (response)
    sampAddChatMessage(decodeJson(response.text)['current']['weather']['main'], -1) -- attempt to index field 'current'
end)
Как из них получить current.weather.main (для наглядности ниже обрезанная структура ответа):
JSON:
{
  "lat": 33.44,
  "lon": -94.04,
  "timezone": "America/Chicago",
  "timezone_offset": -21600,
  "current": {
    "dt": 1618317040,
    "sunrise": 1618282134,
    "sunset": 1618333901,
    "temp": 284.07,
    "feels_like": 282.84,
    "pressure": 1019,
    "humidity": 62,
    "dew_point": 277.08,
    "uvi": 0.89,
    "clouds": 0,
    "visibility": 10000,
    "wind_speed": 6,
    "wind_deg": 300,
    "weather": [
      {
        "id": 500,
        "main": "Rain",
        "description": "light rain",
        "icon": "10d"
      }
    ],
    "rain": {
      "1h": 0.21
    }
  }
]

Через asyncHttpResponse получаю данные и перевожу в JSON:
Lua:
asyncHttpRequest('GET', url, nil, function (response)
    sampAddChatMessage(decodeJson(response.text)['current']['weather']['main'], -1) -- attempt to index field 'current'
end)
Как из них получить current.weather.main (для наглядности ниже обрезанная структура ответа):
JSON:
{
  "lat": 33.44,
  "lon": -94.04,
  "timezone": "America/Chicago",
  "timezone_offset": -21600,
  "current": {
    "dt": 1618317040,
    "sunrise": 1618282134,
    "sunset": 1618333901,
    "temp": 284.07,
    "feels_like": 282.84,
    "pressure": 1019,
    "humidity": 62,
    "dew_point": 277.08,
    "uvi": 0.89,
    "clouds": 0,
    "visibility": 10000,
    "wind_speed": 6,
    "wind_deg": 300,
    "weather": [
      {
        "id": 500,
        "main": "Rain",
        "description": "light rain",
        "icon": "10d"
      }
    ],
    "rain": {
      "1h": 0.21
    }
  }
]
Я долбоеб, делал неправильно запрос, соответственно и на выходе данные не совсем те, что мне нужно.
 
Последнее редактирование:

shtron

Новичок
4
0
Всем привет. Как можно отловить когда игра ставится на паузу? Вижу, что есть метод isGamePaused(), но сам скрипт ведь не выполняется во время паузы. Как тут быть? Было бы здорово на это дело хук иметь, но что-то не нашел
 

Dmitriy Makarov

25.05.2021
Проверенный
2,500
1,131
Всем привет. Как можно отловить когда игра ставится на паузу? Вижу, что есть метод isGamePaused(), но сам скрипт ведь не выполняется во время паузы. Как тут быть? Было бы здорово на это дело хук иметь, но что-то не нашел
В начало кода:
script_properties("work-in-pause")
1651121135970.png


Нету InvisibleButton, мне именно цвет ползунка поменятьПосмотреть вложение 145216, imgui если что
Чтобы изменить цвет активного (true) ползунка:
Lua:
function style()
    imgui.SwitchContext()
    local style = imgui.GetStyle()
    local colors = style.Colors
    local clr = imgui.Col
    local ImVec4 = imgui.ImVec4
   
    -- Тут весь остальной стиль
    --

    -- А это уже цвет активного ползунка
    colors[clr.ButtonActive] = ImVec4(0.26, 0.59, 0.98, 1.00) -- Это, если не ошибаюсь, RGBA делённое на 255.
end
style()

Чтобы изменить цвет неактивного:
1. Заходишь в папку moonloader > lib > imgui_addons.lua
2. Ищешь на 230-й строчке вот такую строку:
Lua:
draw_list:AddCircleFilled(imgui.ImVec2(p.x + radius + t * (width - radius * 2.0), p.y + radius), radius - 0.75, imgui.GetColorU32(bool.v and imgui.GetStyle().Colors[imgui.Col.ButtonActive] or imgui.ImColor(150, 150, 150, 255):GetVec4()))
Там в конце этой строки, где: imgui.ImColor(150, 150, 150, 255):GetVec4())) меняешь цвет (Тут уже RGBA)

(Ну а цвет фона, если интересно: colors[clr.FrameBgHovered])
Screenshot_1.png


Не знаю, возможно и без такого гемора с библиотекой можно менять цвет, но я только такой вариант нашёл щас.
 
Последнее редактирование:
  • Нравится
Реакции: Z3roKwq и shtron

shtron

Новичок
4
0
Спасибо, со script_properties("work-in-pause") стало понятнее. Но вот одно из условий этой работы, чтобы игра была развернута. Можно ли как-то заставить скрипт работать ещё и тогда, когда игра свёрнута? Или как-то отловить сворачивание/разворачивание игры посредством lua?
 

CharleyJones

Известный
184
13
Кто знает как написать что бы после сообщения в чат "Вы заняли" происходил принудительный кик с сервера, что бы персонажа кикнуло с сервера. Server closed the connection.

И кто может перенести функцию консоли 0afb:1 которая тебя респавнит, в Lua формат. Только не sampSpawnPlayer(), эта функция респавнит только на последнюю точку где был заспавнен персонаж а не начальную.
 
Последнее редактирование:

ARMOR

Модератор по раксампу
Модератор
4,936
6,732
Кто знает как написать что бы после сообщения в чат "Вы заняли" происходил принудительный кик с сервера, что бы персонажа кикнуло с сервера. Server closed the connection.

И кто может перенести функцию консоли 0afb:1 которая тебя респавнит, в Lua формат. Только не sampSpawnPlayer(), эта функция респавнит только на последнюю точку где был заспавнен персонаж а не начальную.
Опкод 0AFB: это не спавн, а смена интерьёра для персонажа, т.е смена виртуального мира.
Вот две функции с помощью которых ты мржешь менять интерьер персу
sampSendInteriorChange(int id)
setCharInterior(Ped ped, int interior)
 

Dmitriy Makarov

25.05.2021
Проверенный
2,500
1,131
Спасибо, со script_properties("work-in-pause") стало понятнее. Но вот одно из условий этой работы, чтобы игра была развернута. Можно ли как-то заставить скрипт работать ещё и тогда, когда игра свёрнута? Или как-то отловить сворачивание/разворачивание игры посредством lua?
Не знаю, что ты там хочешь сделать, но нашёл вот такую функцию:
Но я подозреваю, что это будет работать, если SAMP в оконном режиме, а не полноэкранном, хотя могу ошибаться. Других способов не знаю.
 

shtron

Новичок
4
0
Dmitriy Makarov, пытался пользоваться этим методом, но так и есть, не работает. Но скорее всего из-за того, что скрипт тоже не работает, когда игра свёрнута. Хочу другому приложению сообщать когда игра на паузе или свернута. Думал перезаписывать отдельный файл, каждый раз когда это состояние меняется, но отловить сворачивание пока не получается