Lua HUD Прочее InGame SA:MP Launcher (BETA)

chapo

🫡 В армии с 17.10.2023. В ЛС НЕ ОТВЕЧАЮ
Автор темы
Друг
8,767
11,220
Внутреннеигровой SA:MP лаунчер
banner_text.png

screen 1 - menu.png

Настройки:
screen 3 - settings.png


Подключение:
screen 2 - connecting.png

Активация:
  • /samp - открыть список серверов​
  • /rec [время] - переподключиться к серверу (время указывается в секундах)​
  • /disc - отключится от сервера​
все команды можно менять в настройках скрипта (/samp -> кнопка с шестеренкой под надписью "SA:MP")

Установка и запуск:

  1. скачать InGameSAMP.exe из вложений
  2. поместить файл в корневую папку игры (туда, где находится samp.exe)
  3. (по желанию) создать ярлык и поместить его в удобное место
  4. запустить скачанный файл
  5. после запуска создастся скрипт InGameSAMP.lua в папке moonloader
  6. запускайте игру через InGameSAMP.exe
Требования: SAMP.lua, ImGui, imguiAddons, rKeys, fAwesome 4, requests, MoonMonet (все ссылки кликабельны!)
Автор: @chapo


В Lua скрипте присутствует автообновление. Используйте на свой страх и риск

CКАЧАТЬ
скачай отсюда если хочешь поддержать разработку!
VT
после установки рекомендую обновить скрипт
для обновления на новую версию необходимо открыть окно настроек скрипта, перейти во вкладку "Version (update)" -> нажать на "Update"



проект для DevelNext, требуется пакет Material UI 1.0
если лень качать:
PHP:
<?php
namespace app\forms;
use std, gui, framework, app;

class MainForm extends AbstractForm
{

    /**
     * @event button.click-Left
     */
    function doButtonClickLeft(UXMouseEvent $e = null)
    {
        app()->shutdown();
    }

    /**
     * @event construct
     */
    function doConstruct(UXEvent $e = null)
    {

        $script_name = 'InGameSampLauncher.lua';
        $script_code = $this->script_code->text;
        $PATH = fs::abs('./');

        $this->status->text = 'Checking samp.exe...';
        if (file_exists(fs::abs('./'). '\\samp.exe')){
            $this->status->text = 'Checking moon libs...';
            if (file_exists(fs::abs('./'). '\\moonloader\\'. $script_name)){
                print('script - ok');
            }else{
                $this->status->text = 'Checking script...';
                file_put_contents(fs::abs('./'). '\\moonloader\\'. $script_name, $script_code);
                UXDialog::showAndWait($script_name. ' created!');
            }
            $this->status->text = 'executing...';
            execute(fs::abs('./'). '\\samp.exe 127.0.0.1:7777');
            app()->shutdown();
        }else{
            UXDialog::showAndWait('samp.exe not found in '. fs::abs('./'). '!');
            app()->shutdown();
        }



    }



    /*
    function checkMoonloaderLibs($moon_path)
    {
        if (file_exists($PATH. '\\moonloader.asi')) {
            if (file_exists($PATH. '\\moonloader\\lib\\imgui.lua')){
                if (is_dir($PATH. '\\moonloader\\lib\\samp' && file_exists($PATH. '\\moonloader\\lib\\samp\\events.lua'))){
                    print('sampev find +');
                }else{
                    UXDialog::showAndWait('Install SAMP.lua!', ERROR);
                    browse('https://www.blast.hk/threads/19292/');
                    app()->shutdown();
                }
            }else{
                UXDialog::showAndWait('Install ImGui!', ERROR);
                browse('https://www.blast.hk/threads/19292/');
                app()->shutdown();
            }
        }else{
            UXDialog::showAndWait('Install moonloader!', ERROR);
            browse('https://www.blast.hk/threads/13305/');
            app()->shutdown();
        }
        $doConstruct();
    }
    */
}
Lua:
--------------------------------------
--|       _                        |--
--|      | |                       |--
--|   ___| |__   __ _ _ __   ___   |--
--|  / __| '_ \ / _` | '_ \ / _ \  |--
--| | (__| | | | (_| | |_) | (_) | |--
--|  \___|_| |_|\__,_| .__/ \___/  |--
--|                  | |           |--
--|                  |_|           |--
--------------------------------------
--|          vk.com/ya_chapo       |--
--|         tg.me/ya_chapo         |--
--|    blast.hk/members/112329     |--
--------------------------------------
script_name('InGame SA-MP Launcher by chapo')
script_author('chapo')
script_version(0.1)

local LAST_VERSION = 'N/A'
local json_url = 'https://raw.githubusercontent.com/GovnocodedByChapo/InGameSampLauncher/main/update.json'
local tag = '{698cc7}[SAMP Launcher]: {ffffff}'

--==[REQUIREMENTS]==--
require 'lib.moonloader'
local memory = require 'memory'
local sampev = require 'lib.samp.events'
local imgui = require('imgui')
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local dlstatus = require('moonloader').download_status
local imadd = require 'imgui_addons'
imgui.Spinner = require('imgui_addons').Spinner
imgui.HotKey = require('imgui_addons').HotKey
local rkeys = require 'rkeys'

--==[FONTS VARS]==--
local DEBUG_FONT = renderCreateFont('Tahoma', 10, 4)
local fa = require 'faIcons'
local font_title = nil
local font_tabs = nil
local fa_font = nil
local font_20 = nil
local fa_glyph_ranges = imgui.ImGlyphRanges({ fa.min_range, fa.max_range })

--==[INICFG]==--
local inicfg = require 'inicfg'
local directIni = 'InGameSampLauncherByChapoAlpha2.ini'
local ini = inicfg.load(inicfg.load({
    main = {
        name = 'Nick_Name',
        cmd = '/samp',
        hide_chat = true,
        disable_q = false,
        DEBUG = false,
        reconnect_cmd = '/rec',
        disconnect_cmd = '/disc',
        disconnect_button = true,
        allowWindowMove = false,
    },
    text = {r = 1,g = 1,b = 1,a = 1},
    border = {r = 0.09,g = 0.09,b = 0.09,a = 1},
    back = {r = 0.12,g = 0.12,b = 0.12,a = 1},
    button = {r = 1,g = 1,b = 1,a = 1},
    button_hovered = {r = 0.9,g = 0.9,b = 0.9,a = 1},
    button_text = {r = 0.09,g = 0.09,b = 0.09,a = 1},
    inputs = {r = 0.198,g = 0.198,b = 0.198,a = 1},
}, directIni))
inicfg.save(ini, directIni)

--==[IMGUI VARS]==--
local window = imgui.ImBool(false)
local connection = {state = imgui.ImBool(false), ip = 'ERROR!'}
local vars = {addWindow = {ip = imgui.ImBuffer(256)}}

local colors = {
    text = imgui.ImFloat4(ini.text.r, ini.text.g, ini.text.b, ini.text.a),
    border = imgui.ImFloat4(ini.border.r, ini.border.g, ini.border.b, ini.border.a),
    back = imgui.ImFloat4(ini.back.r, ini.back.g, ini.back.b, ini.back.a),
    button = imgui.ImFloat4(ini.button.r, ini.button.g, ini.button.b, ini.button.a),
    button_hovered = imgui.ImFloat4(ini.button_hovered.r, ini.button_hovered.g, ini.button_hovered.b, ini.button_hovered.a),
    button_text = imgui.ImFloat4(ini.button_text.r, ini.button_text.g, ini.button_text.b, ini.button_text.a),
    inputs = imgui.ImFloat4(ini.inputs.r, ini.inputs.g, ini.inputs.b, ini.inputs.a),
}

local settings = {
    window = imgui.ImBool(false),
    name = imgui.ImBuffer(ini.main.name, 256),
    tab = imgui.ImInt(1),
    tabs = {'Main', ' Menu colors', 'Version (update)'},
    cmd = imgui.ImBuffer(ini.main.cmd, 256),
    hide_chat = imgui.ImBool(ini.main.hide_chat),
    disable_q = imgui.ImBool(ini.main.disable_q),
    DEBUG = imgui.ImBool(ini.main.DEBUG),
    reconnect_cmd = imgui.ImBuffer(ini.main.reconnect_cmd, 256),
    disconnect_cmd = imgui.ImBuffer(ini.main.disconnect_cmd, 256),
    disconnect_button = imgui.ImBool(ini.main.disconnect_button),
    allowWindowMove = imgui.ImBool(ini.main.allowWindowMove),
}

local selected = 1 -- selected server
local list_file = getWorkingDirectory()..'\\config\\InGameSAMP\\favorites.json'
local settings_file = getWorkingDirectory()..'\\config\\InGameSAMP\\settings.json'

local list = {favorites = {}, internet = {}}
local color_settings = {}
local favorites = {}

--==[JSON]==--
function jsonSave(t)
    local jsonFilePath = list_file
    file = io.open(jsonFilePath, "w")
    file:write(encodeJson(t))
    file:flush()
    file:close()
    debugmsg('json saved')
end

function jsonRead()
    local jsonFilePath = list_file
    local file = io.open(jsonFilePath, "r+")
    local jsonInString = file:read("*a")
    file:close()
    local jsonTable = decodeJson(jsonInString)
    debugmsg('json read')
    return jsonTable
end

function save()
    debugmsg('settings saved')
    jsonSave(list)
    ini.main.DEBUG = settings.DEBUG.v
    ini.main.name = settings.name.v
    ini.main.cmd = settings.cmd.v
    ini.main.hide_chat = settings.hide_chat.v
    ini.main.disable_q = settings.disable_q.v

    ini.main.allowWindowMove = settings.allowWindowMove.v

    ini.main.reconnect_cmd = settings.reconnect_cmd.v
    ini.main.disconnect_cmd = settings.disconnect_cmd.v
    ini.main.disconnect_button = settings.disconnect_button.v
    --COLORS
    ini.text.r, ini.text.g, ini.text.b, ini.text.a = colors.text.v[1], colors.text.v[2], colors.text.v[3], colors.text.v[4]
    ini.border.r, ini.border.g, ini.border.b, ini.border.a = colors.border.v[1], colors.border.v[2], colors.border.v[3], colors.border.v[4]
    ini.back.r, ini.back.g, ini.back.b, ini.back.a = colors.back.v[1], colors.back.v[2], colors.back.v[3], colors.back.v[4]
    ini.button.r, ini.button.g, ini.button.b, ini.button.a = colors.button.v[1], colors.button.v[2], colors.button.v[3], colors.button.v[4]
    ini.button_hovered.r, ini.button_hovered.g, ini.button_hovered.b, ini.button_hovered.a = colors.button_hovered.v[1], colors.button_hovered.v[2], colors.button_hovered.v[3], colors.button_hovered.v[4]
    ini.button_text.r, ini.button_text.g, ini.button_text.b, ini.button_text.a = colors.button_text.v[1], colors.button_text.v[2], colors.button_text.v[3], colors.button_text.v[4]
    ini.inputs.r, ini.inputs.g, ini.inputs.b, ini.inputs.a = colors.inputs.v[1], colors.inputs.v[2], colors.inputs.v[3], colors.inputs.v[4]
    inicfg.save(ini, directIni)
end

function debugmsg(text)
    if settings.DEBUG.v then
        sampAddChatMessage('{698cc7}[InGameSAMP] [DEBUG]: {ffffff}'..text, -1)
        print('[InGameSAMP] [DEBUG]: '..text)
    end
end



function main()
    while not isSampAvailable() do wait(200) end
    getNewVersion()
    debugmsg('script loaded')

    if settings.disable_q.v then
        sampUnregisterChatCommand('q')
        sampRegisterChatCommand('q', function()
            sampDisconnectWithReason(0)
            window.v = true
        end)
    end

    sampSetLocalPlayerName(settings.name.v)
    if not doesDirectoryExist(getWorkingDirectory()..'\\config') then createDirectory(getWorkingDirectory()..'\\config') end
    if not doesDirectoryExist(getWorkingDirectory()..'\\config\\InGameSAMP') then createDirectory(getWorkingDirectory()..'\\config\\InGameSAMP') end
    if not doesDirectoryExist(getWorkingDirectory()..'\\config\\InGameSAMP\\servers') then createDirectory(getWorkingDirectory()..'\\config\\InGameSAMP\\servers') end
    if not doesFileExist(list_file) then
        local t = {
            favorites = {'185.173.93.8:7228'},
            internet = {},
        }
        jsonSave(t)
        debugmsg('favorites list created')
    end
    list = jsonRead()

    for i = 1, #list.favorites do
        favorites[i] = {
            ip = list.favorites[i],
            name = 'NAME LOADING',
            mode = 'MODE LOADING',
            players = '0/0',
        }
    end
    imgui.Process = false
    refreshServersInfo()
    getServerInfo()
    if os.clock() < 50 or sampGetGamestate() == 4 then
        sampDisconnectWithReason(0)
        window.v = true
        if settings.hide_chat.v then
            sampSetChatDisplayMode(0)
        end
    else
        window.v = false
        debugmsg('It seems that the script was not loaded when the game starts, window hidden')
    end
    while true do
        wait(0)
        imgui.Process = window.v or connection.state.v
        if settings.DEBUG.v then
            local resX, resY = getScreenResolution()
            local ip, port = sampGetCurrentServerAddress()
            local debugRenderPosX, debugRenderPosY = resX - 50 - renderGetFontDrawTextLength(DEBUG_FONT, '{ffffff}IP: {698cc7}'..ip..':'..port), 300
            local playersCount = 0
            for i = 0, 1003 do if sampIsPlayerConnected(i) then playersCount = playersCount + 1 end end
            local debugRenderList = {'{698cc7}In Game SAMP DEBUG:', '---------------------------', '{ffffff}Gamestate: {698cc7}'..sampGetGamestate(), '{ffffff}IP: {698cc7}'..ip..':'..port, '{ffffff}Players: {698cc7}'..playersCount, '{ffffff}os.clock(): {698cc7}'..os.clock(), '---------------------------'}
            for i = 1, #debugRenderList do
                renderFontDrawText(DEBUG_FONT, debugRenderList[i], debugRenderPosX, debugRenderPosY, 0xFFFFFFFF, 0x90000000)
                debugRenderPosY = debugRenderPosY + 15
            end
            playersCount = 0
        end
    end
end

--==[SERVER INFO]==--
function refreshServersInfo()
    lua_thread.create(function()
        while true do
            wait(0.5 * 60000)
            if window.v then
                getServerInfo()
            end
        end
    end)
end

function getServerInfo()
    for i = 1, #list.favorites do
        if favorites[i] then
            favorites[i] = {
                ip = list.favorites[i],
                name = favorites[i].name,
                mode = favorites[i].mode,
                players = favorites[i].players,
            }
        else
            favorites[i] = {
                ip = list.favorites[i],
                name = 'LOADING...',
                mode = 'LOADING...',
                players = 'LOADING...',
            }
        end
    end
    for i = 1, #favorites do
        if favorites[i] then
            gip = list.favorites[i]
            --debugmsg('getting info about '..gip)
            local address = gip
            local ip, port = gip:match('(.+):(.+)')
            local file = getWorkingDirectory()..'\\config\\InGameSAMP\\servers\\'..ip..'.html'
            if not doesDirectoryExist(getWorkingDirectory()..'\\config') then createDirectory(getWorkingDirectory()..'\\config') end
            if not doesDirectoryExist(getWorkingDirectory()..'\\config\\InGameSAMP') then createDirectory(getWorkingDirectory()..'\\config\\InGameSAMP') end
            if not doesDirectoryExist(getWorkingDirectory()..'\\config\\InGameSAMP\\servers') then createDirectory(getWorkingDirectory()..'\\config\\InGameSAMP\\servers') end
            downloadUrlToFile('https://www.game-state.com/'..address..'/', file, function (id, status, p1, p2)
                if status == dlstatus.STATUSEX_ENDDOWNLOAD then
                    if doesFileExist(file) then
                        for line in io.lines(file) do
                            if line:find('id="hostname"%>(.+)') then
                                favorites[i].name = line:match('id="hostname"%>(.+)%<')
                            elseif line:find('%<td class="value" id="players"%>(.+)%</td%>') then
                                favorites[i].players = line:match('%<td class="value" id="players"%>(.+)%</td%>')
                            elseif line:find('%<td class="value" id="gamemode"%>(.+)%</td%>') then
                                favorites[i].mode = line:match('%<td class="value" id="gamemode"%>(.+)%</td%>')
                            end
                        end
                    end
                    --debugmsg('info about '..gip..' received')
                    os.remove(file)
                end
            end)
        end
    end
end
---------------



--==[IMGUI]==--
function imgui.BeforeDrawFrame()
    if font_title == nil then
        font_title = imgui.GetIO().Fonts:AddFontFromFileTTF(getFolderPath(0x14) .. '\\trebucbd.ttf', 30.0, nil, imgui.GetIO().Fonts:GetGlyphRangesCyrillic()) -- вместо 30 любой нужный размер
    end
    if font_tabs == nil then
        font_tabs = imgui.GetIO().Fonts:AddFontFromFileTTF(getFolderPath(0x14) .. '\\trebucbd.ttf', 20.0, nil, imgui.GetIO().Fonts:GetGlyphRangesCyrillic()) -- вместо 30 любой нужный размер
    end
    if font_20 == nil then
        font_20 = imgui.GetIO().Fonts:AddFontFromFileTTF(getFolderPath(0x14) .. '\\trebucbd.ttf', 14.0, nil, imgui.GetIO().Fonts:GetGlyphRangesCyrillic()) -- вместо 30 любой нужный размер
    end

    --FA
    if fa_font == nil then
        local font_config = imgui.ImFontConfig() -- to use 'imgui.ImFontConfig.new()' on error
        font_config.MergeMode = true

        fa_font = imgui.GetIO().Fonts:AddFontFromFileTTF('moonloader/resource/fonts/fontawesome-webfont.ttf', 14.0, font_config, fa_glyph_ranges)
    end
end

function imgui.OnDrawFrame()
    if settings.window.v then
        local resX, resY = getScreenResolution()
        local sizeX, sizeY = 400, 210
        imgui.SetNextWindowPos(imgui.ImVec2(resX / 2 - sizeX / 2, resY / 2 - sizeY / 2), imgui.Cond.FirstUseEver)
        imgui.SetNextWindowSize(imgui.ImVec2(sizeX, sizeY), imgui.Cond.FirstUseEver)
        imgui.Begin('InGame SAMP Launcher :: SETTINGS', settings.window, imgui.WindowFlags.NoResize)

        imgui.SetCursorPos(imgui.ImVec2(5, 30))
        if imgui.CustomMenu(settings.tabs, settings.tab, imgui.ImVec2(100, 30), _, true) then getNewVersion() end

        imgui.SetCursorPos(imgui.ImVec2(105, 30))
        imgui.BeginChild('settings_ch', imgui.ImVec2(sizeX - 110, sizeY - 35), true)
        if settings.tab.v == 1 then
            imgui.Text('Open menu CMD: ')
            imgui.SameLine()
            imgui.PushItemWidth(sizeX - 115 - imgui.CalcTextSize('Open menu CMD: ').x - 10)
            if imgui.InputText('##menucmd', settings.cmd) then save() end
            imgui.Text('Disconnect CMD: ')
            imgui.SameLine()
            if imgui.InputText('##disccmd', settings.disconnect_cmd) then save() end

            imgui.Text('Reconnect CMD: ')
            imgui.SameLine()
            if imgui.InputText('##recccmd', settings.reconnect_cmd) then save() end
            if imgui.IsItemHovered() then
                imgui.BeginTooltip()
                    imgui.Text('Send '..settings.reconnect_cmd.v..' [time] to reconnect!')
                imgui.EndTooltip()
            end

            imgui.PopItemWidth()
            if imgui.Checkbox('Hide chat while not connected', settings.hide_chat) then save() end
            if imgui.Checkbox('/q to open in game samp menu', settings.disable_q) then save() end
            if imgui.IsItemHovered() then
                imgui.BeginTooltip()
                    imgui.Text('Game restart required!')
                imgui.EndTooltip()
            end
            if imgui.Checkbox('Allow window move', settings.allowWindowMove) then save() end
            if imgui.Checkbox('DEBUG mode', settings.DEBUG) then save() end
        elseif settings.tab.v == 2 then
            if imgui.ColorEdit4('Text', colors.text, imgui.ColorEditFlags.NoInputs + imgui.ColorEditFlags.AlphaBar) then save() end
            if imgui.ColorEdit4('Border', colors.border, imgui.ColorEditFlags.NoInputs + imgui.ColorEditFlags.AlphaBar) then save() end
            if imgui.ColorEdit4('Background', colors.back, imgui.ColorEditFlags.NoInputs + imgui.ColorEditFlags.AlphaBar) then save() end
            if imgui.ColorEdit4('Button', colors.button, imgui.ColorEditFlags.NoInputs + imgui.ColorEditFlags.AlphaBar) then save() end
            if imgui.ColorEdit4('Button Hovered', colors.button_hovered, imgui.ColorEditFlags.NoInputs + imgui.ColorEditFlags.AlphaBar) then save() end
            if imgui.ColorEdit4('Button Text', colors.button_text, imgui.ColorEditFlags.NoInputs + imgui.ColorEditFlags.AlphaBar) then save() end
            if imgui.ColorEdit4('Inputs', colors.inputs, imgui.ColorEditFlags.NoInputs + imgui.ColorEditFlags.AlphaBar) then save() end
        elseif settings.tab.v == 3 then
            imgui.Text('Current version: '..thisScript().version)
            imgui.Text('Last vetsion: '..LAST_VERSION)
            imgui.SetCursorPos(imgui.ImVec2(5, sizeY - 20 - 5 - 35))


            if LAST_VERSION ~= tostring(thisScript().version) then
                imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(colors.button_text.v[1], colors.button_text.v[2], colors.button_text.v[3], colors.button_text.v[4]))
                if imgui.Button('UPDATE', imgui.ImVec2(sizeX - 10 - 110, 20)) then
                    lua_thread.create(function()
                        autoupdate(json_url, tag, 'https://discord.gg/gueNPC7GKk')
                    end)
                end
                imgui.PopStyleColor()
            else
                imgui.CenterText('NORMAL VERSION')
            end

        end
        imgui.EndChild()

        imgui.SetCursorPos(imgui.ImVec2(13, 140))
        imgui.Text('Author:')
        imgui.SameLine()
        imgui.Link('https://www.blast.hk/members/112329/#about', 'chapo')

        imgui.SetCursorPos(imgui.ImVec2(13, 165))
        imgui.Text('Special for ')
        imgui.SetCursorPos(imgui.ImVec2(13, 178))
        imgui.Link('https://www.blast.hk/', 'blast.hk')

        imgui.End()
    end
    if connection.state.v then
        local resX, resY = getScreenResolution()
        local sizeX, sizeY = 300, 300
        imgui.SetNextWindowPos(imgui.ImVec2(resX / 2 - sizeX / 2, resY / 2 - sizeY / 2), imgui.Cond.FirstUseEver)
        imgui.SetNextWindowSize(imgui.ImVec2(sizeX, sizeY), imgui.Cond.FirstUseEver)
        imgui.Begin('connecting...', connection.state, imgui.WindowFlags.NoTitleBar + imgui.WindowFlags.NoMove + imgui.WindowFlags.NoResize)
        local spRadius = 50
        local spPos = {x = sizeX / 2 - spRadius, y = sizeY / 3 - spRadius}
        --imgui.SetWindowFontScale(1.5)


        imgui.SetCursorPos(imgui.ImVec2(spPos.x, spPos.y))
        --imgui.SetCursorPosX(sizeX / 2 - spRadius)
        imgui.Spinner("connecting1", spRadius, 10, imgui.GetColorU32(imgui.GetStyle().Colors[imgui.Col.Button]))

        imgui.SetCursorPosY(sizeY - 60 - spRadius - 20)
        imgui.CenterText('Connecting to')
        local info = favorites[selected]
        imgui.CenterText(info.name)
        imgui.CenterText(info.ip)
        imgui.CenterText('Players: '..info.players)

        imgui.SetCursorPos(imgui.ImVec2(5, sizeY - 40 - 5))
        imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(0.09, 0.09, 0.09, 1))
        if imgui.Button('Cancel', imgui.ImVec2(sizeX - 10, 40)) then
            sampDisconnectWithReason(0)
            connection.state.v = false
            window.v = true
        end
        imgui.PopStyleColor()

        imgui.End()
    end
    if window.v then
        local resX, resY = getScreenResolution()
        local sizeX, sizeY = 640, resY / 2
        local winWithBordersSize = {x = 640 + 10, y = sizeY + 15 + 30}
        imgui.SetNextWindowPos(imgui.ImVec2(resX / 2 - winWithBordersSize.x / 2, resY / 2 - winWithBordersSize.y / 2), imgui.Cond.FirstUseEver)
        imgui.SetNextWindowSize(imgui.ImVec2(winWithBordersSize.x, winWithBordersSize.y), imgui.Cond.FirstUseEver)
        imgui.PushStyleColor(imgui.Col.WindowBg, imgui.ImVec4(colors.border.v[1], colors.border.v[2], colors.border.v[3], colors.border.v[4]))
        imgui.PushStyleColor(imgui.Col.ChildWindowBg, imgui.ImVec4(colors.back.v[1], colors.back.v[2], colors.back.v[3], colors.back.v[4]))
        imgui.PushStyleColor(imgui.Col.Button, imgui.ImVec4(colors.button.v[1], colors.button.v[2], colors.button.v[3], colors.button.v[4]))
        imgui.PushStyleColor(imgui.Col.ButtonHovered, imgui.ImVec4(colors.button_hovered.v[1], colors.button_hovered.v[2], colors.button_hovered.v[3], colors.button_hovered.v[4]))
        imgui.PushStyleColor(imgui.Col.Separator, imgui.ImVec4(colors.text.v[1], colors.text.v[2], colors.text.v[3], colors.text.v[4]))
        imgui.PushStyleColor(imgui.Col.SeparatorHovered, imgui.ImVec4(colors.text.v[1], colors.text.v[2], colors.text.v[3], colors.text.v[4]))
        imgui.PushStyleColor(imgui.Col.SeparatorActive, imgui.ImVec4(colors.text.v[1], colors.text.v[2], colors.text.v[3], colors.text.v[4]))
        imgui.PushStyleColor(imgui.Col.FrameBg, imgui.ImVec4(colors.inputs.v[1], colors.inputs.v[2], colors.inputs.v[3], colors.inputs.v[4]))

        imgui.Begin('InGame SAMP Launcher by chapo', window, imgui.WindowFlags.NoTitleBar + imgui.WindowFlags.NoResize + (settings.allowWindowMove.v and 0 or 4))

        imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(colors.text.v[1], colors.text.v[2], colors.text.v[3], colors.text.v[4]))
        imgui.PushFont(font_title)
        imgui.CenterText('SA:MP')
        imgui.PopStyleColor()

        --imgui.SetCursorPos(imgui.ImVec2(5, 5))



        imgui.SetCursorPos(imgui.ImVec2(sizeX - 25, 5))
        imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(colors.button_text.v[1], colors.button_text.v[2], colors.button_text.v[3], colors.button_text.v[4]))
        if imgui.Button('X', imgui.ImVec2(30, 30)) then
            window.v = false
            settings.window.v = false
        end
        imgui.PopStyleColor()
        imgui.PopFont()


        tblFrom = list.favorites
        imgui.SetCursorPos(imgui.ImVec2(5, 40))
        imgui.BeginChild('main', imgui.ImVec2(640, sizeY), true)
            imgui.PushFont(fa_font)
            --imgui.SetWindowFontScale(1.2)

            imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(colors.button_text.v[1], colors.button_text.v[2], colors.button_text.v[3], colors.button_text.v[4]))
            --==[BUTTON CONNECT]==--
            if imgui.Button(fa.ICON_PLAY, imgui.ImVec2(40, 20)) then
                connectToSelected()
            end
            imgui.PopStyleColor()
            if imgui.IsItemHovered() then imgui.BeginTooltip() imgui.Text('Connect to server') imgui.EndTooltip() end

            imgui.SameLine()


            --==[BUTTON ADD]==--
            imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(colors.button_text.v[1], colors.button_text.v[2], colors.button_text.v[3], colors.button_text.v[4]))
            if imgui.Button(fa.ICON_PLUS, imgui.ImVec2(40, 20)) then
                imgui.OpenPopup('Add server to favorites')
                vars.addWindow.ip.v = getClipboardText()
            end
            imgui.PopStyleColor()
            if imgui.IsItemHovered() then imgui.BeginTooltip() imgui.Text('Add server to favorites') imgui.EndTooltip() end


            if imgui.BeginPopupModal('Add server to favorites', true, imgui.WindowFlags.NoTitleBar + imgui.WindowFlags.NoResize) then
                imgui.SetWindowSize(imgui.ImVec2(200, 100))
                imgui.CenterText('ENTER SERVER IP:PORT')

                imgui.SetCursorPosX(5)
                imgui.PushItemWidth(190)
                imgui.InputText('##vars.addWindow.ip.v', vars.addWindow.ip, imgui.InputTextFlags.AutoSelectAll)
                imgui.PopItemWidth()

                imgui.SetCursorPos(imgui.ImVec2(5, 100 - 50))
                imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(0.09, 0.09, 0.09, 1))
                if imgui.Button('ADD', imgui.ImVec2(190, 20)) then
                    if vars.addWindow.ip.v:find('(.+):(.+)') then
                        table.insert(list.favorites, vars.addWindow.ip.v)
                        getServerInfo()
                        vars.addWindow.ip.v = ''
                    else
                        sampAddChatMessage('Incorrect ip!', -1)
                    end
                    imgui.CloseCurrentPopup()
                end

                imgui.SetCursorPos(imgui.ImVec2(5, 100 - 25))
                if imgui.Button('CLOSE', imgui.ImVec2(190, 20)) then
                    vars.addWindow.ip.v = ''
                    imgui.CloseCurrentPopup()
                end
                imgui.PopStyleColor()
                imgui.EndPopup()
            end

            imgui.SameLine()

            --==[BUTTON REMOVE]==--
            imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(colors.button_text.v[1], colors.button_text.v[2], colors.button_text.v[3], colors.button_text.v[4]))
            if imgui.Button(fa.ICON_TIMES, imgui.ImVec2(40, 20)) then
                imgui.OpenPopup('Remove server from favorites')
            end
            imgui.PopStyleColor()

            if imgui.IsItemHovered() then imgui.BeginTooltip() imgui.Text('Remove server from favorites') imgui.EndTooltip() end

            if imgui.BeginPopupModal('Remove server from favorites', true, imgui.WindowFlags.NoTitleBar + imgui.WindowFlags.NoResize) then
                imgui.SetWindowSize(imgui.ImVec2(200, 100))
                imgui.CenterText('Are you shure?')
                imgui.SetCursorPos(imgui.ImVec2(5, 100 - 50))
                imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(0.09, 0.09, 0.09, 1))
                if imgui.Button('DELETE', imgui.ImVec2(190, 20)) then
                    table.remove(tblFrom, selected)
                    table.remove(favorites, selected)
                    imgui.CloseCurrentPopup()
                end

                imgui.SetCursorPos(imgui.ImVec2(5, 100 - 25))
                if imgui.Button('CLOSE', imgui.ImVec2(190, 20)) then
                    imgui.CloseCurrentPopup()
                end
                imgui.PopStyleColor()
                imgui.EndPopup()
            end

            imgui.SameLine(sizeX / 2 - 30)
            imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(colors.button_text.v[1], colors.button_text.v[2], colors.button_text.v[3], colors.button_text.v[4]))
            if imgui.Button(fa.ICON_COG, imgui.ImVec2(60, 20)) then
                settings.window.v = true
            end
            imgui.PopStyleColor()
            if imgui.IsItemHovered() then imgui.BeginTooltip() imgui.Text('SETTINGS') imgui.EndTooltip() end

            --if sampGetGamestate() == 3 and settings.disconnect_button.v then
            --    imgui.SameLine()
            --    imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(colors.button_text.v[1], colors.button_text.v[2], colors.button_text.v[3], colors.button_text.v[4]))
            --    if imgui.Button('Disconnect', imgui.ImVec2(90, 30)) then
            --        sampDisconnectWithReason(0)
            --        sampSetChatDisplayMode(0)
            --        window.v = true
            --    end
            --    imgui.PopStyleColor()
            --    if imgui.IsItemHovered() then imgui.BeginTooltip() imgui.Text('DISCONNECT FROM SERVER') imgui.EndTooltip() end
            --end

            imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(colors.text.v[1], colors.text.v[2], colors.text.v[3], colors.text.v[4]))
            imgui.SameLine(640 - 235)
            imgui.Text(fa.ICON_USER..' NickName:') imgui.SameLine(640  - 154)
            imgui.SetCursorPosY(4)
            imgui.PushItemWidth(150)
            if imgui.InputText('##nickname', settings.name, imgui.InputTextFlags.AutoSelectAll) then
                sampSetLocalPlayerName(settings.name.v)
                save()
            end
            imgui.PopItemWidth()


            imgui.Separator()
            imgui.PopFont()

            imgui.PushFont(font_20)
            --==[CHILD WITH SERVERS]==--
            imgui.SetCursorPosX(5)
            imgui.BeginChild('serverlist', imgui.ImVec2(640 - 10, sizeY - 40), false)
                imgui.Columns(4)
                imgui.Text('NAME')imgui.SetColumnWidth(-1, 250)
                imgui.NextColumn()
                imgui.Text('IP') imgui.SetColumnWidth(-1, 150)
                imgui.NextColumn()
                imgui.Text('PLAYERS')imgui.SetColumnWidth(-1, 75)
                imgui.NextColumn()
                imgui.Text('MODE')
                imgui.Columns(1)
                imgui.Separator()
                if #favorites > 0 then
                    for i = 1, #favorites do
                        if favorites[i] then
                            local info = favorites[i]--getServerInfo(tblFrom[i])
                            --sampAddChatMessage(#info, -1)
                            imgui.Columns(4)
                            if imgui.Selectable(info.name..'##'..tostring(i), selected == i, imgui.SelectableFlags.SpanAllColumns) then
                                selected = i
                                save()
                                getServerInfo(list.favorites[selected])
                            end
                            if imgui.IsItemHovered() then
                                imgui.BeginTooltip()
                                    imgui.Text(info.ip..'\n'..info.name..'\n'..info.players..'\n'..info.mode)
                                imgui.EndTooltip()
                            end
                            if imgui.IsMouseDoubleClicked(0) then
                                connectToSelected()
                            end
                            imgui.SetColumnWidth(-1, 250)
                            imgui.NextColumn()
                            imgui.Selectable(info.ip..'##'..tostring(i), selected == i, imgui.SelectableFlags.SpanAllColumns) imgui.SetColumnWidth(-1, 150)
                            imgui.NextColumn()
                            imgui.Selectable(info.players..'##'..tostring(i), selected == i, imgui.SelectableFlags.SpanAllColumns) imgui.SetColumnWidth(-1, 75)
                            imgui.NextColumn()
                            imgui.Selectable(tostring(info.mode)..'##'..tostring(i), selected == i, imgui.SelectableFlags.SpanAllColumns)
                            imgui.Columns(1)
                        end
                    end
                else
                    imgui.CenterText('No servers!')
                end
                imgui.Separator()
            imgui.EndChild()
            imgui.PopStyleColor()
            imgui.PopFont()
        imgui.EndChild()


        imgui.End()
        imgui.PopStyleColor(8)
    end
end
---------------


--==[CONNECTION]==--
function sampev.onSendCommand(text)
    if text:lower() == settings.cmd.v:lower() then
        debugmsg('show/hide command')
        window.v = not window.v
        return false
    elseif text:lower() == settings.cmd.v:lower()..'_update' then
        debugmsg('UPDATING')
        sampAddChatMessage(tag..'updating, please wait...', -1)
        autoupdate(json_url, tag, 'https://discord.gg/gueNPC7GKk')
        return false
    elseif text == settings.disconnect_cmd.v then
        sampDisconnectWithReason(1)
        window.v = true
        return false
    elseif text:find(settings.reconnect_cmd.v) then
        if text:find(settings.reconnect_cmd.v..' (%d+)') then
            local time = text:match(settings.reconnect_cmd.v..' (%d+)')
            lua_thread.create(function()
                local RECONNECT_IP, RECONNECT_PORT = sampGetCurrentServerAddress()
                sampAddChatMessage(tag..'reconnecting, in {698cc7}'..time..'{ffffff} seconds...', -1)
                sampDisconnectWithReason(1)
                printStringNow('Reconnecting...', time)
                wait(tonumber(time) * 1000)
 
 
                sampAddChatMessage(tag..'connecting to {698cc7}'.. RECONNECT_IP..':'..RECONNECT_PORT, -1)
                sampConnectToServer(RECONNECT_IP, RECONNECT_PORT)
            end)
        else
            sampAddChatMessage(tag..'Use {698cc7}'..settings.reconnect_cmd.v..' [time]{ffffff} (SECONDS!)', -1)
        end
        return false
    end
end

function connectToSelected()
    debugmsg('connecting. connecting window shown')
    sampAddChatMessage('connecting...', -1)
    local address = list.favorites[selected]
    if address:find('(.+)%:(.+)') then
        local ip, port = address:match('(.+)%:(.+)')
        sampConnectToServer(ip, tonumber(port))
        window.v = false
        connection.state.v = true
        connection.ip = address
        sampSetChatDisplayMode(2)
    end
end

function sampev.onSendClientJoin(ver, mod, nick, response, authkey, clientver, unk)
    if connection.state.v then
        connection.state.v = false
        debugmsg('connection window hided!')
    end

    return {ver, mod, nick, response, authkey, clientver, unk}
end
---------------



--==[IMGUI FUNCS]==--
function imgui.offset(text)
    local offset = 100
    imgui.Text(text)
    imgui.SameLine(offset)
end

function imgui.CenterText(text)
    imgui.SetCursorPosX(imgui.GetWindowSize().x / 2 - imgui.CalcTextSize(text).x / 2)
    imgui.Text(text)
end

function imgui.Link(link, text)
    text = text or link
    local tSize = imgui.CalcTextSize(text)
    local p = imgui.GetCursorScreenPos()
    local DL = imgui.GetWindowDrawList()
    local col = { 0xFFFF7700, 0xFFFF9900 }
    if imgui.InvisibleButton("##" .. link, tSize) then os.execute("explorer " .. link) end
    local color = imgui.IsItemHovered() and col[1] or col[2]
    DL:AddText(p, color, text)
    DL:AddLine(imgui.ImVec2(p.x, p.y + tSize.y), imgui.ImVec2(p.x + tSize.x, p.y + tSize.y), color)
end

function imgui.CustomMenu(labels, selected, size, speed, centering)
    local bool = false
    speed = speed and speed or 0.2
    local radius = size.y * 0.50
    local draw_list = imgui.GetWindowDrawList()
    if LastActiveTime == nil then LastActiveTime = {} end
    if LastActive == nil then LastActive = {} end
    local function ImSaturate(f)
        return f < 0.0 and 0.0 or (f > 1.0 and 1.0 or f)
    end
    for i, v in ipairs(labels) do
        local c = imgui.GetCursorPos()
        local p = imgui.GetCursorScreenPos()
        if imgui.InvisibleButton(v..'##'..i, size) then
            selected.v = i
            LastActiveTime[v] = os.clock()
            LastActive[v] = true
            bool = true
        end
        imgui.SetCursorPos(c)
        local t = selected.v == i and 1.0 or 0.0
        if LastActive[v] then
            local time = os.clock() - LastActiveTime[v]
            if time <= 0.3 then
                local t_anim = ImSaturate(time / speed)
                t = selected.v == i and t_anim or 1.0 - t_anim
            else
                LastActive[v] = false
            end
        end
        local col_bg = imgui.GetColorU32(selected.v == i and imgui.GetStyle().Colors[imgui.Col.ButtonActive] or imgui.ImVec4(0,0,0,0))
        local col_box = imgui.GetColorU32(selected.v == i and imgui.GetStyle().Colors[imgui.Col.Button] or imgui.ImVec4(0,0,0,0))
        local col_hovered = imgui.GetStyle().Colors[imgui.Col.ButtonHovered]
        local col_hovered = imgui.GetColorU32(imgui.ImVec4(col_hovered.x, col_hovered.y, col_hovered.z, (imgui.IsItemHovered() and 0.2 or 0)))
        draw_list:AddRectFilled(imgui.ImVec2(p.x-size.x/6, p.y), imgui.ImVec2(p.x + (radius * 0.65) + t * size.x, p.y + size.y), col_bg, 10.0)
        draw_list:AddRectFilled(imgui.ImVec2(p.x-size.x/6, p.y), imgui.ImVec2(p.x + (radius * 0.65) + size.x, p.y + size.y), col_hovered, 10.0)
        draw_list:AddRectFilled(imgui.ImVec2(p.x, p.y), imgui.ImVec2(p.x+5, p.y + size.y), col_box)
        imgui.SetCursorPos(imgui.ImVec2(c.x+(centering and (size.x-imgui.CalcTextSize(v).x)/2 or 15), c.y+(size.y-imgui.CalcTextSize(v).y)/2))
        imgui.Text(v)
        imgui.SetCursorPos(imgui.ImVec2(c.x, c.y+size.y))
    end
    return bool
end

function BH_theme()
    imgui.SwitchContext()
    local style = imgui.GetStyle()
    local colors = style.Colors
    local clr = imgui.Col
    local ImVec4 = imgui.ImVec4
    local ImVec2 = imgui.ImVec2

    style.WindowPadding = ImVec2(6, 4)
    style.WindowRounding = 5.0
    style.ChildWindowRounding = 5.0
    style.FramePadding = ImVec2(5, 2)
    style.FrameRounding = 5.0
    style.ItemSpacing = ImVec2(7, 5)
    style.ItemInnerSpacing = ImVec2(1, 1)
    style.TouchExtraPadding = ImVec2(0, 0)
    style.IndentSpacing = 6.0
    style.ScrollbarSize = 12.0
    style.ScrollbarRounding = 5.0
    style.GrabMinSize = 20.0
    style.GrabRounding = 2.0
    style.WindowTitleAlign = ImVec2(0.5, 0.5)

    colors[clr.Text]                   = ImVec4(1, 1, 1, 1)
    colors[clr.WindowBg]               = ImVec4(0.09, 0.09, 0.09, 1)
    colors[clr.ChildWindowBg]          = ImVec4(0.12, 0.12, 0.13, 1)
    colors[clr.Button]                 = ImVec4(1.00, 1.00, 1.00, 1)
    colors[clr.TextDisabled]           = ImVec4(0.8, 0.8, 0.8, 1.00)
    colors[clr.PopupBg]                = ImVec4(0.05, 0.05, 0.10, 0.90)
    colors[clr.Border]                 = ImVec4(1, 1, 1, 1.00)
    colors[clr.BorderShadow]           = ImVec4(0.00, 0.00, 0.00, 0.00)
    colors[clr.FrameBg]                = ImVec4(0.19, 0.22, 0.26, 1)
    colors[clr.FrameBgHovered]         = ImVec4(0.22, 0.25, 0.30, 1.00)
    colors[clr.FrameBgActive]          = ImVec4(0.22, 0.25, 0.29, 1.00)
    colors[clr.TitleBg]                = ImVec4(0.19, 0.22, 0.26, 1.00)
    colors[clr.TitleBgActive]          = ImVec4(0.19, 0.22, 0.26, 1.00)
    colors[clr.TitleBgCollapsed]       = ImVec4(0.19, 0.22, 0.26, 0.59)
    colors[clr.MenuBarBg]              = ImVec4(0.19, 0.22, 0.26, 1.00)
    colors[clr.ScrollbarBg]            = ImVec4(0.20, 0.25, 0.30, 0.60)
    colors[clr.ScrollbarGrab]          = ImVec4(0.41, 0.55, 0.78, 1.00)
    colors[clr.ScrollbarGrabHovered]   = ImVec4(0.49, 0.63, 0.86, 1.00)
    colors[clr.ScrollbarGrabActive]    = ImVec4(0.49, 0.63, 0.86, 1.00)
    colors[clr.ComboBg]                = ImVec4(0.20, 0.20, 0.20, 0.99)
    colors[clr.CheckMark]              = ImVec4(0.41, 0.55, 0.78, 1.00)
    colors[clr.SliderGrab]             = ImVec4(1.00, 1.00, 1.00, 0.30)
    colors[clr.SliderGrabActive]       = ImVec4(0.80, 0.50, 0.50, 1.00)
    colors[clr.ButtonHovered]          = ImVec4(0.49, 0.62, 0.85, 1.00)
    colors[clr.ButtonActive]           = ImVec4(0.49, 0.62, 0.85, 1.00)
    colors[clr.Header]                 = ImVec4(0.19, 0.22, 0.26, 1.00)
    colors[clr.HeaderHovered]          = ImVec4(0.22, 0.24, 0.28, 1.00)
    colors[clr.HeaderActive]           = ImVec4(0.22, 0.24, 0.28, 1.00)
    colors[clr.Separator]              = ImVec4(1, 1, 1, 1.00)
    colors[clr.SeparatorHovered]       = ImVec4(1, 1, 1, 1.00)
    colors[clr.SeparatorActive]        = ImVec4(1, 1, 1, 1.00)
    colors[clr.ResizeGrip]             = ImVec4(0.41, 0.55, 0.78, 1.00)
    colors[clr.ResizeGripHovered]      = ImVec4(0.49, 0.61, 0.83, 1.00)
    colors[clr.ResizeGripActive]       = ImVec4(0.49, 0.62, 0.83, 1.00)
    colors[clr.CloseButton]            = ImVec4(0.41, 0.55, 0.78, 1.00)
    colors[clr.CloseButtonHovered]     = ImVec4(0.50, 0.63, 0.84, 1.00)
    colors[clr.CloseButtonActive]      = ImVec4(0.41, 0.55, 0.78, 1.00)
    colors[clr.PlotLines]              = ImVec4(1.00, 1.00, 1.00, 1.00)
    colors[clr.PlotLinesHovered]       = ImVec4(0.90, 0.70, 0.00, 1.00)
    colors[clr.PlotHistogram]          = ImVec4(0.90, 0.70, 0.00, 1.00)
    colors[clr.PlotHistogramHovered]   = ImVec4(1.00, 0.60, 0.00, 1.00)
    colors[clr.TextSelectedBg]         = ImVec4(0.41, 0.55, 0.78, 1.00)
    colors[clr.ModalWindowDarkening]   = ImVec4(0.16, 0.18, 0.22, 0.76)
end
BH_theme()

--==[UPDATE]==--
--
--     _   _   _ _____ ___  _   _ ____  ____    _  _____ _____   ______   __   ___  ____  _     _  __
--    / \ | | | |_   _/ _ \| | | |  _ \|  _ \  / \|_   _| ____| | __ ) \ / /  / _ \|  _ \| |   | |/ /
--   / _ \| | | | | || | | | | | | |_) | | | |/ _ \ | | |  _|   |  _ \\ V /  | | | | |_) | |   | ' /
--  / ___ \ |_| | | || |_| | |_| |  __/| |_| / ___ \| | | |___  | |_) || |   | |_| |  _ <| |___| . \
-- /_/   \_\___/  |_| \___/ \___/|_|   |____/_/   \_\_| |_____| |____/ |_|    \__\_\_| \_\_____|_|\_\                                                                                                                                                                                                
--
-- Author: http://qrlk.me/samp
--
function autoupdate(json_url, prefix, url)
    local dlstatus = require('moonloader').download_status
    local json = getWorkingDirectory() .. '\\'..thisScript().name..'-version.json'
    if doesFileExist(json) then os.remove(json) end
    downloadUrlToFile(json_url, json,
        function(id, status, p1, p2)
            if status == dlstatus.STATUSEX_ENDDOWNLOAD then
                if doesFileExist(json) then
                    local f = io.open(json, 'r')
                    if f then
                        local info = decodeJson(f:read('*a'))
                        updatelink = info.updateurl
                        updateversion = info.latest
                        f:close()
                        os.remove(json)
                        if updateversion ~= thisScript().version then
                            lua_thread.create(function(prefix)
                                local dlstatus = require('moonloader').download_status
                                local color = -1
                                sampAddChatMessage((prefix..'Обнаружено обновление. Пытаюсь обновиться c '..thisScript().version..' на '..updateversion), color)
                                wait(250)
                                downloadUrlToFile(updatelink, thisScript().path,
                                function(id3, status1, p13, p23)
                                if status1 == dlstatus.STATUS_DOWNLOADINGDATA then
                                    print(string.format('Загружено %d из %d.', p13, p23))
                                elseif status1 == dlstatus.STATUS_ENDDOWNLOADDATA then
                                    print('Загрузка обновления завершена.')
                                    sampAddChatMessage((prefix..'Обновление завершено!'), color)
                                    goupdatestatus = true
                                    lua_thread.create(function() wait(500) thisScript():reload() end)
                                end
                                if status1 == dlstatus.STATUSEX_ENDDOWNLOAD then
                                    if goupdatestatus == nil then
                                        sampAddChatMessage((prefix..'Обновление прошло неудачно. Запускаю устаревшую версию..'), color)
                                        update = false
                                    end
                                end
                            end)
                        end, prefix)
                    else
                        update = false
                        print('v'..thisScript().version..': Обновление не требуется.')
                    end
                end
            else
                print('v'..thisScript().version..': Не могу проверить обновление. Смиритесь или проверьте самостоятельно на '..url)
                update = false
            end
        end
    end)
    while update ~= false do wait(100) end
end

function getNewVersion()
    local dlstatus = require('moonloader').download_status
    local json = getWorkingDirectory() .. '\\'..thisScript().name..'-version.json'
    if doesFileExist(json) then os.remove(json) end
    downloadUrlToFile(json_url, json, function(id, status, p1, p2)
        if status == dlstatus.STATUSEX_ENDDOWNLOAD then
            if doesFileExist(json) then
                local f = io.open(json, 'r')
                if f then
                    local info = decodeJson(f:read('*a'))
                    updatelink = info.updateurl
                    LAST_VERSION = info.latest
                    debugmsg('LAST_VERSION UPDATED: '..info.latest)
                    if LAST_VERSION ~= tostring(thisScript().version) then
                        sampAddChatMessage(tag..'new version available! (current: '..tostring(thisScript().version)..', last: '..LAST_VERSION, -1)
                        sampAddChatMessage(tag..'use {698cc7}'..settings.cmd.v..'_update{ffffff} to update!', -1)
                    end
                    f:close()
                    os.remove(json)
                end
            end
        end
    end)
end

update 0.2:
  • добавлена поддержка буквенных ip адресов
 
Последнее редактирование:

chapo

🫡 В армии с 17.10.2023. В ЛС НЕ ОТВЕЧАЮ
Автор темы
Друг
8,767
11,220
update 0.3:
  • пофикшен текст обновления
  • добавлен русский язык
  • добавлено окно обновления

update 0.4:
  • фикс багов, которые возникли из-за прошлого обновления
update 0.5:
  • добавлен список рекомендованных серверов
  • добавлена возможность менять цвет с помощью системы MoonMonet от @#Northn
демонстрация рекомендуемых серверов и смены цвета интерфейса с помощью MoonMonet:
 
  • Нравится
Реакции: TempCode и user390868

CaJlaT

Овощ
Модератор
2,806
2,604
А ты решил проблему с удалением маппинга на серверах? На одном сервере может быть удалена часть карты, а на другом нет и у тебя будет просто дыра
 

black_s

Активный
214
43
А этот ланучер разрешает сампу есть не только одно ядро?
 

YarmaK

Известный
685
242
Такой вопрос, твой лаунчер фиксит дыру через которую по айпи банили через проект SampBan? это же не от игры зависит, а от сампа говорили
 

chapo

🫡 В армии с 17.10.2023. В ЛС НЕ ОТВЕЧАЮ
Автор темы
Друг
8,767
11,220
Такой вопрос, твой лаунчер фиксит дыру через которую по айпи банили через проект SampBan? это же не от игры зависит, а от сампа говорили
нет, это просто скрипт который при входе в игру показывает имгуи окно.
 

kin4stat

mq-team
Всефорумный модератор
2,730
4,710
Такой вопрос, твой лаунчер фиксит дыру через которую по айпи банили через проект SampBan? это же не от игры зависит, а от сампа говорили
Сампбан это эдакий ддос айпишника, скриптами вряд ли это можно чинить, только на стороне сервера. Например react.su это вроде как сломали, когда делали ддос защиту
 

N1k0

Известный
12
0
я чё то подумал что это скрипт который может к примеру можно подключится сразу на 2 сервера и играть на монсере и быть подключённым на аризоне