Lua SuperGPS - динамическая метка на миникарте с сервером

Статус
В этой теме нельзя размещать новые ответы.

Иван22134

Новичок
Автор темы
3
7
Автор: Иван22134 (vk.com/ivanshamsiev)
Кратко: Мод сырой, выкладываю для переделывания другими мододелами. Мод открывает возможность для работы с сервером, асинхронными запросами, и даёт массу возможностей для изменения и переделки под свои нужды (Полиция, банды, криминал)
Что мод делает: Позволяет создать динамическую метку с вашим местоположением на карте, а также возможность увидеть вашу метку другому обладателю этого мода.



Мод планировался как помощь LSPD на сервере Revolution, а суть его была в реализации режима погони. Но в процессе разработки выяснилось, что получить местоположение игрока за пределами видимости невозможно, и, как следствие, невозможно поставить на него метку.
Потенциальные возможности этого мода ограничены только вашей фантазией.

Как уже писалось ранее, мод демонстрирует работу с сервером, реализованную в четырёх функциях:
  1. new() - посылает серверу GET запрос с вашим ником и координатами, а на сервере PHP файл обрабатывает эти данные и заносит их в .json файл. Т.е. теперь на сервере есть массив, содержащий ваш ник и координаты.
  2. update() - стандартно активируется в первой функции. Она циклична, и каждую секунду посылает запросы, аналогичные функции new(), но в этом случае запросы посылаются другому файлу .php, который уже знает, что массив с вашими данными создан, и его просто нужно обновить.
  3. delete() - посылает запрос с вашим ником на удаление массива с вашими данными - т.е. останавливает функцию update(), прекращается передача ваших координат и удаляет массив ваших данных с сервера.
  4. check(checkname) - если на сервере присутствует массив с ником checkname, то функция каждую секунду запрашивать у сервера координаты, а также создаёт динамическую метку с местоположением цели на карте в виде машинки.

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

В моде также присутствует функция перевода текста из формата UTF-8 в ANSI, и обратно. Это сделано по той причине, что САМП с какого-то перепугу почему-то принимал информацию с сервера (переменная body) в неверной кодировке (да ещё и вставлял в начале текста три нижних черты (___), что в коде уже учтено).



Что было использовано в процессе написания:
Куча статеек в интернете
Асинхронные HTTP запросы
Для работы с сетью - библиотка lua_requests (Распаковать в lib)
Для работы асинхронных запросов - библиотека Lanes (В архиве есть папка lanes, её содержимое нужно перекинуть в lib, остальное сжечь на костре в полнолуние)


Также для использования необходим сервер с поддержкой php (например) и немного усилий в освоении начал.
(Но если вам таки лень что-то изучать, пишите мне в vk, договоримся)

Разрешаю редактирование, модифицирование и вообще хоть насилуйте этого мода с указанием исходника.

P.S.: Буду не против, если кто-нибудь запилит обзорчик, т.к. самому что-то пилить лень


Код мода:
Lua:
http = require("socket.http")
ev = require "lib.samp.events"

php = "https://адрес_вашего_сайта_с_поддержкой_php"
nickname = ""
marker = nil
updthread = nil
ThatsAll = false
StopCheck = false

posX = 0
posY = 0
posZ = 0

myid = 0


function main()
    if not isSampfuncsLoaded() or not isSampLoaded() then return end
    while not isSampAvailable() do
        wait(200)
    end
    sampAddChatMessage("Мод MyTest запущен", 0xCC0000)
    sampRegisterChatCommand("inew", new)
    sampRegisterChatCommand("idelete", delete)
    sampRegisterChatCommand("icheck", check)
    sampRegisterChatCommand("istopcheck", function() StopCheck = true end)

    _, myid = sampGetPlayerIdByCharHandle(PLAYER_PED)
    nickname = sampGetPlayerNickname(myid)

    posX, posY, posZ = getCharCoordinates(PLAYER_PED)
    wait(-1)
end

function new()
    posX, posY, posZ = getCharCoordinates(PLAYER_PED)
    posX = tonumber(string.format("%.1f", posX))
    posY = tonumber(string.format("%.1f", posY))
    posZ = tonumber(string.format("%.1f", posZ))
    async_http_request('GET', php .. "/new.php" .. "?name=" .. nickname .. "&cordx=" .. posX .. "&cordy=" .. posY .. "&cordz=" .. posZ, nil,
  function(nobody) -- вызовется при успешном выполнении и получении ответа
        print("Сработал успешный ответ")
        ThatsAll = false
        body = Utf8ToAnsi(nobody.text)
        body = string.gsub(body, "___", "")
        print(body)
        update()
  end,
  function(err) -- вызовется при ошибке, err - текст ошибки. эту функцию можно не указывать
        print("Сработала ошибка")
    print(err)
  end)
end

function update()
    while ThatsAll == false do
        wait(1000)
        posX, posY, posZ = getCharCoordinates(PLAYER_PED)
        posX = tonumber(string.format("%.1f", posX))
        posY = tonumber(string.format("%.1f", posY))
        posZ = tonumber(string.format("%.1f", posZ))
        async_http_request('GET', php .. "/update.php" .. "?name=" .. nickname .. "&cordx=" .. posX .. "&cordy=" .. posY .. "&cordz=" .. posZ, nil,
        function(nobody) -- вызовется при успешном выполнении и получении ответа
            print("Сработал успешный ответ")
            body = Utf8ToAnsi(nobody.text)
            body = string.gsub(body, "___", "")
            print(body)
            if string.find(body, "Погоня не существует") then ThatsAll = true end
        end,
        function(err) -- вызовется при ошибке, err - текст ошибки. эту функцию можно не указывать
            print("Сработала ошибка")
            print(err)
        end)
    end
end

function delete()
    async_http_request('GET', php .. "/delete.php" .. "?name=" .. nickname, nil,
    function(nobody) -- вызовется при успешном выполнении и получении ответа
        print("Сработал успешный ответ")
        body = Utf8ToAnsi(nobody.text)
        body = string.gsub(body, "___", "")
        if string.find(body, "Погоня удалена") then
            print("Погоня окончена")
            ThatsAll = true
            removeBlip(marker)
        end
    end,
    function(err) -- вызовется при ошибке, err - текст ошибки. эту функцию можно не указывать
        print("Сработала ошибка")
        print(err)
    end)
end

function check(checkname)
    StopCheck = false
    function mm()
        while StopCheck == false do
            wait(1000)
            async_http_request('GET', php .. "/check.php" .. "?name=" .. nickname .. "&checkname=" .. checkname, nil,
            function(nobody) -- вызовется при успешном выполнении и получении ответа
                print("Сработал успешный ответ")
                body = Utf8ToAnsi(nobody.text)
                body = string.gsub(body, "___", "")
                print(body)
                removeBlip(marker)
                if string.find(body, "Погоня не существует") then StopCheck = true
                else a, _, b, _, c = string.match(body, "(%S+)(%s)(%S+)(%s)(%S+)")
                    marker = addSpriteBlipForCoord(a, b, c, 55)
                end
            end,
            function(err) -- вызовется при ошибке, err - текст ошибки. эту функцию можно не указывать
                print("Сработала ошибка")
                print(err)
            end)
        end
        wait(2000)
        removeBlip(marker)
    end
    updthread = lua_thread.create(mm)
end





local lanes = require('lanes').configure()

function async_http_request(method, url, args, resolve, reject)
    local request_lane = lanes.gen('*', {package = {path = package.path, cpath = package.cpath}}, function()
        local requests = require 'requests'
        local ok, result = pcall(requests.request, method, url, args)
        if ok then
            result.json, result.xml = nil, nil -- cannot be passed through a lane
            return true, result
        else
            return false, result -- return error
        end
    end)
    if not reject then reject = function() end end
    lua_thread.create(function()
        local lh = request_lane()
        while true do
            local status = lh.status
            if status == 'done' then
                local ok, result = lh[1], lh[2]
                if ok then resolve(result) else reject(result) end
                return
            elseif status == 'error' then
                return reject(lh[1])
            elseif status == 'killed' or status == 'cancelled' then
                return reject(status)
            end
            wait(0)
        end
    end)
end



local ansi_decode={
  [128]='\208\130',[129]='\208\131',[130]='\226\128\154',[131]='\209\147',[132]='\226\128\158',[133]='\226\128\166',
  [134]='\226\128\160',[135]='\226\128\161',[136]='\226\130\172',[137]='\226\128\176',[138]='\208\137',[139]='\226\128\185',
  [140]='\208\138',[141]='\208\140',[142]='\208\139',[143]='\208\143',[144]='\209\146',[145]='\226\128\152',
  [146]='\226\128\153',[147]='\226\128\156',[148]='\226\128\157',[149]='\226\128\162',[150]='\226\128\147',[151]='\226\128\148',
  [152]='\194\152',[153]='\226\132\162',[154]='\209\153',[155]='\226\128\186',[156]='\209\154',[157]='\209\156',
  [158]='\209\155',[159]='\209\159',[160]='\194\160',[161]='\209\142',[162]='\209\158',[163]='\208\136',
  [164]='\194\164',[165]='\210\144',[166]='\194\166',[167]='\194\167',[168]='\208\129',[169]='\194\169',
  [170]='\208\132',[171]='\194\171',[172]='\194\172',[173]='\194\173',[174]='\194\174',[175]='\208\135',
  [176]='\194\176',[177]='\194\177',[178]='\208\134',[179]='\209\150',[180]='\210\145',[181]='\194\181',
  [182]='\194\182',[183]='\194\183',[184]='\209\145',[185]='\226\132\150',[186]='\209\148',[187]='\194\187',
  [188]='\209\152',[189]='\208\133',[190]='\209\149',[191]='\209\151'
}
local utf8_decode={
  [128]={[147]='\150',[148]='\151',[152]='\145',[153]='\146',[154]='\130',[156]='\147',[157]='\148',[158]='\132',[160]='\134',[161]='\135',[162]='\149',[166]='\133',[176]='\137',[185]='\139',[186]='\155'},
  [130]={[172]='\136'},
  [132]={[150]='\185',[162]='\153'},
  [194]={[152]='\152',[160]='\160',[164]='\164',[166]='\166',[167]='\167',[169]='\169',[171]='\171',[172]='\172',[173]='\173',[174]='\174',[176]='\176',[177]='\177',[181]='\181',[182]='\182',[183]='\183',[187]='\187'},
  [208]={[129]='\168',[130]='\128',[131]='\129',[132]='\170',[133]='\189',[134]='\178',[135]='\175',[136]='\163',[137]='\138',[138]='\140',[139]='\142',[140]='\141',[143]='\143',[144]='\192',[145]='\193',[146]='\194',[147]='\195',[148]='\196',
    [149]='\197',[150]='\198',[151]='\199',[152]='\200',[153]='\201',[154]='\202',[155]='\203',[156]='\204',[157]='\205',[158]='\206',[159]='\207',[160]='\208',[161]='\209',[162]='\210',[163]='\211',[164]='\212',[165]='\213',[166]='\214',
    [167]='\215',[168]='\216',[169]='\217',[170]='\218',[171]='\219',[172]='\220',[173]='\221',[174]='\222',[175]='\223',[176]='\224',[177]='\225',[178]='\226',[179]='\227',[180]='\228',[181]='\229',[182]='\230',[183]='\231',[184]='\232',
    [185]='\233',[186]='\234',[187]='\235',[188]='\236',[189]='\237',[190]='\238',[191]='\239'},
  [209]={[128]='\240',[129]='\241',[130]='\242',[131]='\243',[132]='\244',[133]='\245',[134]='\246',[135]='\247',[136]='\248',[137]='\249',[138]='\250',[139]='\251',[140]='\252',[141]='\253',[142]='\254',[143]='\255',[144]='\161',[145]='\184',
    [146]='\144',[147]='\131',[148]='\186',[149]='\190',[150]='\179',[151]='\191',[152]='\188',[153]='\154',[154]='\156',[155]='\158',[156]='\157',[158]='\162',[159]='\159'},[210]={[144]='\165',[145]='\180'}
}

local nmdc = {
  [36] = '$',
  [124] = '|'
}

function AnsiToUtf8(s)
  local r, b = ''
  for i = 1, s and s:len() or 0 do
    b = s:byte(i)
    if b < 128 then
      r = r..string.char(b)
    else
      if b > 239 then
        r = r..'\209'..string.char(b - 112)
      elseif b > 191 then
        r = r..'\208'..string.char(b - 48)
      elseif ansi_decode[b] then
        r = r..ansi_decode[b]
      else
        r = r..'_'
      end
    end
  end
  return r
end

function Utf8ToAnsi(s)
  local a, j, r, b = 0, 0, ''
  for i = 1, s and s:len() or 0 do
    b = s:byte(i)
    if b < 128 then
      if nmdc[b] then
        r = r..nmdc[b]
      else
        r = r..string.char(b)
      end
    elseif a == 2 then
      a, j = a - 1, b
    elseif a == 1 then
      a, r = a - 1, r..utf8_decode[j][b]
    elseif b == 226 then
      a = 2
    elseif b == 194 or b == 208 or b == 209 or b == 210 then
      j, a = b, 1
    else
      r = r..'_'
    end
  end
  return r
end
 

Вложения

  • SuperGPS.lua
    8.9 KB · Просмотры: 87

Иван22134

Новичок
Автор темы
3
7
Идея неплохая, реализация гавно. Вместо запроса раз в секунду лучше использовать лонгпул запрос.
Принт через строку, ужас конечно. Вместо 3х гет аргументов можно было отправить строку, да и вообще весь запрос через строку лучше и резать её уже на сервере.
Про лонгпул согласен, но реализовать не смог, ручки кривоваты. А насчёт всего запроса через строку - дело вкуса
 

wD.D159

Известный
Друг
446
479
Не плохо было бы прикрепить скринов, а то вот прочитал, и как-то не очень представил данную разработку. Хоть идея и хорошая.
 
Статус
В этой теме нельзя размещать новые ответы.