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

YarikVL

Известный
Проверенный
4,796
1,813

The Spark

Известный
653
673
пробовал, не фурычит
Lua:
while not sampIsLocalPlayerSpawned() do wait(0) end
...
Потому что main не будет ждать пока заспавнится игрок и проскочит проверку. Логично подумать о реализации цикла. Сработает 1 раз, при 1 спавне
Можно повешать на events, тогда сработает на каждый спавн
Lua:
function sampev.onSendSpawn()
   ...
end
 

sat0ry

Известный
1,087
289
Лучше посмотри все уроки the champ guess, если смотрел то посмотри ещё раз, внимательнее. Потому что дальше будет сложнее идти не зная основ ( по типу циклов и main )
Как бы основы я знаю, просто периодически забываю...
 

ufdhbi

Известный
Проверенный
1,455
861
Можно как-то выполнить несколько параллельных вызовов потока? Чтобы в каждом из них он выполнялся, но не прерывал предыдущий свой вызов, если он еще не завершился.
Просто создавай потоки

Привет, а кто может написать код на заказ? Если там не так много работы.
Пиши в лс
 

YourAssistant

Участник
144
17
В ini можно как-то записать аналог такой таблицы?
Lua:
table = {
  ["1"] = {
    {"1"},
    {"1", "2", "3"},
    }
}
 

sep

Известный
673
76
как удалять (не сохранять) старые строки после 50той например

local f = io.open(chatad, "r")
local adold = f:read("*a")
f:close()
local f = io.open(chatad, "w")
f:write("[" ..fulltime.. "] " ..adnik.. " " ..adtel.. "\n" ..ad.. "\n" .. adold)
f:close()
 

dendy.

Активный
351
66
Крашит когда нажимаю кнопки с лева и стиль что-то не работает.
Lua:
require 'lib.moonloader'
local ffi = require 'ffi'
local imgui = require 'mimgui'
local fa = require("fAwesome5")
local encoding = require 'encoding'
encoding.default = 'CP1251'                                       
local u8 = encoding.UTF8

imgui.OnInitialize(function()
    local config = imgui.ImFontConfig()
    config.MergeMode = true
    local glyph_ranges = imgui.GetIO().Fonts:GetGlyphRangesCyrillic()
    local iconRanges = imgui.new.ImWchar[3](fa.min_range, fa.max_range, 0)
    imgui.GetIO().Fonts:AddFontFromFileTTF('trebucbd.ttf', 14.0, nil, glyph_ranges)
    icon = imgui.GetIO().Fonts:AddFontFromFileTTF('moonloader/resource/fonts/fa-solid-900.ttf', 14.0, config, iconRanges)
end)

local renderWindow = imgui.new.bool(true)

local menu = {
    opened = imgui.new.bool(false),
    selected = {[0] = ''},
    tabs = {
        [fa.ICON_FA_CAR] = u8' Ìàøèíà',
        [fa.ICON_FA_USER] = u8' Ëîøïåä',
        [fa.ICON_FA_EYE] = u8' Ãëàç',
    }
}

local newFrame = imgui.OnFrame(
    function() return renderWindow[0] end,
    function(player)
        local resX, resY = getScreenResolution()
        local sizeX, sizeY = 300, 300
        imgui.SetNextWindowPos(imgui.ImVec2(resX / 2, resY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
        imgui.SetNextWindowSize(imgui.ImVec2(sizeX, sizeY), imgui.Cond.FirstUseEver)
        imgui.BeginWin11Menu('Win11 menu example', renderWindow, false, menu.tabs, menu.selected, menu.opened, 40, 100)

        if menu.selected[0] == u8' Ìàøèíà' then
            imgui.Checkbox('checkbox', placeholder_bool)
        elseif menu.selected[0] == u8' Ëîøïåä' then
            -- code
        elseif menu.selected[0] == u8' Ãëàç' then
            -- code
        end

        imgui.EndWin11Menu()
    end
)

function imgui.BeginWin11Menu(title, var, stateButton, tabs, selected, isOpened, sizeClosed, sizeOpened, windowFlags)
    imgui.PushStyleVarVec2(imgui.StyleVar.WindowPadding, imgui.ImVec2(0, 0))
    imgui.Begin(title, var, imgui.WindowFlags.NoTitleBar + (windowFlags or 0))

    local size = imgui.GetWindowSize()
    local pos = imgui.GetWindowPos()
    local dl = imgui.GetWindowDrawList()

    local tabSize = sizeClosed - 10

    imgui.SetCursorPos(imgui.ImVec2(size.x - tabSize - 5, 5))
    if imgui.Button('X##'..title..'::closebutton', imgui.ImVec2(tabSize, tabSize)) then if var then var[0] = false end end

    --==[ MAIN BG ]==--
    imgui.SetCursorPos(imgui.ImVec2(sizeClosed, sizeClosed))
    local p = imgui.GetCursorScreenPos()
    dl:AddRectFilled(p, imgui.ImVec2(p.x + size.x - sizeClosed, p.y + size.y - sizeClosed), imgui.GetColorU32Vec4(imgui.GetStyle().Colors[imgui.Col.ChildBg]), imgui.GetStyle().WindowRounding, 1 + 8)
  
    --==[ TITLEBAR ]==--
    imgui.SetCursorPos(imgui.ImVec2(0, 0))
    local p = imgui.GetCursorScreenPos()
    dl:AddRectFilled(p, imgui.ImVec2(p.x + (isOpened[0] and sizeOpened or sizeClosed), p.y + size.y), imgui.GetColorU32Vec4(imgui.GetStyle().Colors[imgui.Col.WindowBg]), imgui.GetStyle().WindowRounding, 1 + 4)
    imgui.SetCursorPos(imgui.ImVec2(tabSize + 10, sizeClosed / 2 - imgui.CalcTextSize(title).y / 2))
    imgui.Text(title)

    --==[ TABS BUTTONS ]==--
    imgui.SetCursorPosY(5)
    if stateButton then
        imgui.SetCursorPosX(5)
        if imgui.Button(stateButton, imgui.ImVec2(tabSize, tabSize)) then isOpened[0] = not isOpened[0] end
    else
        imgui.SetCursorPosY(5 + tabSize + 5)
    end
    for k, v in pairs(tabs) do
        imgui.SetCursorPosX(5)
        imgui.PushStyleColor(imgui.Col.Button, selected[0] == v and imgui.GetStyle().Colors[imgui.Col.ButtonActive] or imgui.GetStyle().Colors[imgui.Col.WindowBg])
        imgui.PushStyleVarVec2(imgui.StyleVar.ButtonTextAlign, imgui.ImVec2(isOpened[0] and 0.1 or 0.5, 0.5))
        if imgui.Button(isOpened[0] and k..' '..v or k, imgui.ImVec2(isOpened[0] and sizeOpened - 10 or tabSize, tabSize)) then selected[0] = v end
        if imgui.IsItemHovered() then
            imgui.BeginTooltip()
            imgui.Text(k..' '..v)
            imgui.EndTooltip()
        end
        imgui.PopStyleVar()
        imgui.PopStyleColor()
    end

    --==[ CHILD ]==--
    imgui.SetCursorPos(imgui.ImVec2(sizeClosed + 5, sizeClosed + 5))
    imgui.PushStyleVarVec2(imgui.StyleVar.WindowPadding, imgui.ImVec2(15, 15))
    imgui.BeginChild(title..'::mainchild', imgui.ImVec2(size.x - sizeClosed - 5, size.y - sizeClosed - 5), true)
end

function imgui.EndWin11Menu()
    imgui.EndChild()
    imgui.End()
    imgui.PopStyleVar(2)
end

function imgui.DarkTheme()
    imgui.SwitchContext()
    --==[ STYLE ]==--
    imgui.GetStyle().WindowPadding = imgui.ImVec2(5, 5)
    imgui.GetStyle().FramePadding = imgui.ImVec2(5, 6)
    imgui.GetStyle().ItemSpacing = imgui.ImVec2(5, 5)
    imgui.GetStyle().ItemInnerSpacing = imgui.ImVec2(2, 2)
    imgui.GetStyle().TouchExtraPadding = imgui.ImVec2(0, 0)
    imgui.GetStyle().IndentSpacing = 0
    imgui.GetStyle().ScrollbarSize = 10
    imgui.GetStyle().GrabMinSize = 10

    --==[ BORDER ]==--
    imgui.GetStyle().WindowBorderSize = 0
    imgui.GetStyle().ChildBorderSize =0
    imgui.GetStyle().PopupBorderSize = 0
    imgui.GetStyle().FrameBorderSize = 0
    imgui.GetStyle().TabBorderSize = 0

    --==[ ROUNDING ]==--
    imgui.GetStyle().WindowRounding = 5
    imgui.GetStyle().ChildRounding = 5
    imgui.GetStyle().FrameRounding = 5
    imgui.GetStyle().PopupRounding = 5
    imgui.GetStyle().ScrollbarRounding = 5
    imgui.GetStyle().GrabRounding = 5
    imgui.GetStyle().TabRounding = 5

    --==[ ALIGN ]==--
    imgui.GetStyle().WindowTitleAlign = imgui.ImVec2(0.5, 0.5)
    imgui.GetStyle().ButtonTextAlign = imgui.ImVec2(0.5, 0.5)
    imgui.GetStyle().SelectableTextAlign = imgui.ImVec2(0, 0.5)
    
    --==[ COLORS ]==--
    imgui.GetStyle().Colors[imgui.Col.Text]                   = imgui.ImVec4(1.00, 1.00, 1.00, 1.00)
    imgui.GetStyle().Colors[imgui.Col.TextDisabled]           = imgui.ImVec4(0.50, 0.50, 0.50, 1.00)
    imgui.GetStyle().Colors[imgui.Col.WindowBg]               = imgui.ImVec4(0.07, 0.07, 0.07, 1.00)
    imgui.GetStyle().Colors[imgui.Col.ChildBg]                = imgui.ImVec4(0.07, 0.07, 0.07, 1.00)
    imgui.GetStyle().Colors[imgui.Col.PopupBg]                = imgui.ImVec4(0.07, 0.07, 0.07, 1.00)
    imgui.GetStyle().Colors[imgui.Col.Border]                 = imgui.ImVec4(0.25, 0.25, 0.26, 0.54)
    imgui.GetStyle().Colors[imgui.Col.BorderShadow]           = imgui.ImVec4(0.00, 0.00, 0.00, 0.00)
    imgui.GetStyle().Colors[imgui.Col.FrameBg]                = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.FrameBgHovered]         = imgui.ImVec4(0.25, 0.25, 0.26, 1.00)
    imgui.GetStyle().Colors[imgui.Col.FrameBgActive]          = imgui.ImVec4(0.25, 0.25, 0.26, 1.00)
    imgui.GetStyle().Colors[imgui.Col.TitleBg]                = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.TitleBgActive]          = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.TitleBgCollapsed]       = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.MenuBarBg]              = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.ScrollbarBg]            = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.ScrollbarGrab]          = imgui.ImVec4(0.00, 0.00, 0.00, 1.00)
    imgui.GetStyle().Colors[imgui.Col.ScrollbarGrabHovered]   = imgui.ImVec4(0.41, 0.41, 0.41, 1.00)
    imgui.GetStyle().Colors[imgui.Col.ScrollbarGrabActive]    = imgui.ImVec4(0.51, 0.51, 0.51, 1.00)
    imgui.GetStyle().Colors[imgui.Col.CheckMark]              = imgui.ImVec4(1.00, 1.00, 1.00, 1.00)
    imgui.GetStyle().Colors[imgui.Col.SliderGrab]             = imgui.ImVec4(0.21, 0.20, 0.20, 1.00)
    imgui.GetStyle().Colors[imgui.Col.SliderGrabActive]       = imgui.ImVec4(0.21, 0.20, 0.20, 1.00)
    imgui.GetStyle().Colors[imgui.Col.Button]                 = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.ButtonHovered]          = imgui.ImVec4(0.21, 0.20, 0.20, 1.00)
    imgui.GetStyle().Colors[imgui.Col.ButtonActive]           = imgui.ImVec4(0.41, 0.41, 0.41, 1.00)
    imgui.GetStyle().Colors[imgui.Col.Header]                 = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.HeaderHovered]          = imgui.ImVec4(0.20, 0.20, 0.20, 1.00)
    imgui.GetStyle().Colors[imgui.Col.HeaderActive]           = imgui.ImVec4(0.47, 0.47, 0.47, 1.00)
    imgui.GetStyle().Colors[imgui.Col.Separator]              = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.SeparatorHovered]       = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.SeparatorActive]        = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.ResizeGrip]             = imgui.ImVec4(1.00, 1.00, 1.00, 0.25)
    imgui.GetStyle().Colors[imgui.Col.ResizeGripHovered]      = imgui.ImVec4(1.00, 1.00, 1.00, 0.67)
    imgui.GetStyle().Colors[imgui.Col.ResizeGripActive]       = imgui.ImVec4(1.00, 1.00, 1.00, 0.95)
    imgui.GetStyle().Colors[imgui.Col.Tab]                    = imgui.ImVec4(0.12, 0.12, 0.12, 1.00)
    imgui.GetStyle().Colors[imgui.Col.TabHovered]             = imgui.ImVec4(0.28, 0.28, 0.28, 1.00)
    imgui.GetStyle().Colors[imgui.Col.TabActive]              = imgui.ImVec4(0.30, 0.30, 0.30, 1.00)
    imgui.GetStyle().Colors[imgui.Col.TabUnfocused]           = imgui.ImVec4(0.07, 0.10, 0.15, 0.97)
    imgui.GetStyle().Colors[imgui.Col.TabUnfocusedActive]     = imgui.ImVec4(0.14, 0.26, 0.42, 1.00)
    imgui.GetStyle().Colors[imgui.Col.PlotLines]              = imgui.ImVec4(0.61, 0.61, 0.61, 1.00)
    imgui.GetStyle().Colors[imgui.Col.PlotLinesHovered]       = imgui.ImVec4(1.00, 0.43, 0.35, 1.00)
    imgui.GetStyle().Colors[imgui.Col.PlotHistogram]          = imgui.ImVec4(0.90, 0.70, 0.00, 1.00)
    imgui.GetStyle().Colors[imgui.Col.PlotHistogramHovered]   = imgui.ImVec4(1.00, 0.60, 0.00, 1.00)
    imgui.GetStyle().Colors[imgui.Col.TextSelectedBg]         = imgui.ImVec4(1.00, 0.00, 0.00, 0.35)
    imgui.GetStyle().Colors[imgui.Col.DragDropTarget]         = imgui.ImVec4(1.00, 1.00, 0.00, 0.90)
    imgui.GetStyle().Colors[imgui.Col.NavHighlight]           = imgui.ImVec4(0.26, 0.59, 0.98, 1.00)
    imgui.GetStyle().Colors[imgui.Col.NavWindowingHighlight]  = imgui.ImVec4(1.00, 1.00, 1.00, 0.70)
    imgui.GetStyle().Colors[imgui.Col.NavWindowingDimBg]      = imgui.ImVec4(0.80, 0.80, 0.80, 0.20)
    imgui.GetStyle().Colors[imgui.Col.ModalWindowDimBg]       = imgui.ImVec4(0.00, 0.00, 0.00, 0.70)
end
 

shrug228

Активный
212
75
В ini можно как-то записать аналог такой таблицы?
Lua:
table = {
  ["1"] = {
    {"1"},
    {"1", "2", "3"},
    }
}
Используй json. Как вариант тут есть описание, что и куда.

как удалять (не сохранять) старые строки после 50той например

local f = io.open(chatad, "r")
local adold = f:read("*a")
f:close()
local f = io.open(chatad, "w")
f:write("[" ..fulltime.. "] " ..adnik.. " " ..adtel.. "\n" ..ad.. "\n" .. adold)
f:close()
Ты хочешь удалять все строчки после 50? Ну, нормального решения на такой случай предложить не могу, однако никто не запрещал просто перезаписывать файл, удаляя из него ненужные строчки.
Говнокод:
-- Открываем txt файл с названием скрипта в папке moonloader/config:
f = io.open(getGameDirectory() .. '\\moonloader\\config\\' .. thisScript().name .. '.txt', 'r')
-- Если файл не существует, создаем:
if f == nil then
    f = io.open(getGameDirectory() .. '\\moonloader\\config\\' .. thisScript().name .. '.txt','w')
    f:close()
    f = io.open(getGameDirectory() .. '\\moonloader\\config\\' .. thisScript().name .. '.txt', 'r+')
end

-- Записываем файл в таблицу:
local data = {}
for line in f:lines() do
    if #data == 50 then -- Если уже собрано 50 строк, заканчиваем процесс.
        break
    end
    table.insert(data, line) -- Иначе продолжаем запись
end

-- Открываем файл заново, уже в режиме перезаписи:
f:close()
f = io.open(getGameDirectory() .. '\\moonloader\\config\\' .. thisScript().name .. '.txt', 'w')
for line, _ in ipairs(data) do
    f:write(line .. '\n') -- Записываем построчно информацию из таблицы в файл
end
f:close()
 
Последнее редактирование: