Исходник Гайд Как сделать управление игрой через Telegram + отправка уведомлений

Otvertka1337

Известный
13
2
фулл код дай и логи
Lua:
-- зависимости: effil, encoding, mimgui, requests, dkjson

local effil = require 'effil'
local encoding = require 'encoding'
local imgui = require 'mimgui'
local ffi = require 'ffi'
local sampev = require 'lib.samp.events'
-- lua-promises minified
-- https://github.com/zserge/lua-promises
do
  local a={}local b={}b.__index=b;local c=0;local d=1;local e=2;local f=3;local g=4;local function h(b,i)i=i or g;for j,k in ipairs(b.queue)do if i==f then k:resolve(b.value)else k:reject(b.value)end end;b.state=i end;local function l(k)if type(k)=='table'then local m=getmetatable(k)return m~=nil and type(m.__call)=='function'end;return type(k)=='function'end;local function n(b,o,p,q,r)if type(b)=='table'and type(b.value)=='table'and l(o)then local s=false;local t,u=pcall(o,b.value,function(v)if s then return end;s=true;b.value=v;p()end,function(v)if s then return end;s=true;b.value=v;q()end)if not t and not s then b.value=u;q()end else r()end end;local function w(b)local o;if type(b.value)=='table'then o=b.value.next end;n(b,o,function()b.state=d;w(b)end,function()b.state=e;w(b)end,function()local t;local v;if b.state==d and l(b.success)then t,v=pcall(b.success,b.value)elseif b.state==e and l(b.failure)then t,v=pcall(b.failure,b.value)if t then b.state=d end end;if t~=nil then if t then b.value=v else b.value=v;return h(b)end end;if b.value==b then b.value=pcall(error,'resolving promise with itself')return h(b)else n(b,o,function()h(b,f)end,function(i)h(b,i)end,function()h(b,b.state==d and f)end)end end)end;local function x(b,i,y)if b.state==0 then b.value=y;b.state=i;w(b)end;return b end;function b:resolve(y)return x(self,d,y)end;function b:reject(y)return x(self,e,y)end;function a.new(z)if l(z)then local A=a.new()local t,u=pcall(z,A)if not t then A:reject(u)end;return A end;z=z or{}local A;A={next=function(self,p,q)local o=a.new({success=p,failure=q,extend=z.extend})if A.state==f then o:resolve(A.value)elseif A.state==g then o:reject(A.value)else table.insert(A.queue,o)end;return o end,state=0,queue={},success=z.success,failure=z.failure}A=setmetatable(A,b)if l(z.extend)then z.extend(A)end;return A end;function a.all(B)local A=a.new()if#B==0 then return A:resolve({})end;local C="resolve"local D=#B;local E={}local function F(j,G)return function(y)E[j]=y;if not G then C="reject"end;D=D-1;if D==0 then A[C](A,E)end;return y end end;for j=1,D do B[j]:next(F(j,true),F(j,false))end;return A end;function a.map(B,H)local A=a.new()local E={}local function I(j)if j>#B then A:resolve(E)else H(B[j]):next(function(J)table.insert(E,J)I(j+1)end,function(u)A:reject(u)end)end end;I(1)return A end;function a.first(B)local A=a.new()for K,v in ipairs(B)do v:next(function(J)A:resolve(J)end,function(u)A:reject(u)end)end;return A end;
  _G['promise'] = a;
end

-- async-http: effil thread for processing request
function requestRunner()
  return effil.thread(function(method, url, args)
    local requests = require 'requests'
    local dkjson = require 'dkjson'
    local result, response = pcall(requests.request, method, url, dkjson.decode(args))
    if result then
      response.json, response.xml = nil, nil
      return true, response
    else
      return false, response
    end
  end)
end

function handleAsyncHttpRequestThread(runner, resolve, reject)
  local status, err
  repeat
    status, err = runner:status()
    wait(0)
  until status ~= 'running'
  if not err then
    if status == 'completed' then
      local result, response = runner:get()
      if result then
        resolve(response)
      else
        reject(response)
      end
      return
    elseif status == 'canceled' then
      return reject(status)
    end
  else
    return reject(err)
  end
end

function asyncHttpRequest(method, url, args, resolve, reject)
  assert(type(method) == 'string', '"method" expected string')
  assert(type(url) == 'string', '"url" expected string')
  assert(type(args) == 'table', '"args" expected table')
  local thread = requestRunner()(method, url, encodeJson(args))
  if not resolve then resolve = function() end end
  if not reject then reject = function() end end
 
  return {
    effilRequestThread = thread;
    luaHttpHandleThread = lua_thread.create(handleAsyncHttpRequestThread, thread, resolve, reject);
  }
end

encoding.default = 'CP1251'
u8 = encoding.UTF8

local TELEGRAM_BOT_API_HOST = 'https://api.telegram.org'
local TELEGRAM_BOT_METHOD_PATTERN = TELEGRAM_BOT_API_HOST .. '/bot%s/%s'

local telegram = {
  error = nil;
  token = 'token';
  next_update_id = -1;
  timeout = 30;
}

function table.assign(target, def, deep)
  for k, v in pairs(def) do
    if target[k] == nil then
      if type(v) == 'table' then
        target[k] = {}
        table.assign(target[k], v)
      else
        target[k] = v
      end
    elseif deep and type(v) == 'table' and type(target[k]) == 'table' then
      table.assign(target[k], v, deep)
    end
  end
  return target
end

do
  function telegram.getUpdateTypes(update)
    local types = {}
    if update.message then
      table.insert(types, 'message')
      if update.message.chat.type == 'private' then
        table.insert(types, 'private_message')
      elseif update.message.chat.type == 'group' then
        table.insert(types, 'group_message')
      elseif update.message.chat.type == 'supergroup' then
        table.insert(types, 'supergroup_message')
      end
    elseif update.edited_message then
      table.insert(types, 'edited_message')
      if update.edited_message.chat.type == 'private' then
        table.insert(types, 'edited_private_message')
      elseif update.edited_message.chat.type == 'group' then
        table.insert(types, 'edited_group_message')
      elseif update.edited_message.chat.type == 'supergroup' then
        table.insert(types, 'edited_supergroup_message')
      end
    elseif update.callback_query then
      table.insert(types, 'callback_query')
    elseif update.inline_query then
      table.insert(types, 'inline_query')
    elseif update.channel_post then
      table.insert(types, 'channel_post')
    elseif update.edited_channel_post then
      table.insert(types, 'edited_channel_post')
    elseif update.chosen_inline_result then
      table.insert(types, 'chosen_inline_result')
    elseif update.shipping_query then
      table.insert(types, 'shipping_query')
    elseif update.pre_checkout_query then
      table.insert(types, 'pre_checkout_query')
    elseif update.poll then
      table.insert(types, 'poll')
    elseif update.poll_answer then
      table.insert(types, 'poll_answer')
    end
   
   
    setmetatable(types, {
      __index = function(self, key)
        if key == 'is' then
          return function(type)
            for i, t in ipairs(self) do
              if t == type then return true end
            end
          end
        end
      end
    })
    return types
  end;

  telegram.api = {};
 
  setmetatable(telegram.api, {
    __index = function(self, key)
      if (type(key) ~= 'string') then error('я ждал епта стрингу а ты тут мне хуету кидаешь') end
      return function (params, customRequestsOptions)
        customRequestsOptions = customRequestsOptions or {}
        local opts = table.assign(customRequestsOptions, { params = params }, true)
        local p = promise.new()
        asyncHttpRequest('POST', TELEGRAM_BOT_METHOD_PATTERN:format(telegram.token, key), opts, function (...)
          p:resolve(...)
        end, function (...)
          p:reject(...)
        end)
        return p
      end
    end
  })
  function telegram.startPollingUpdates()
    telegram.error = nil
    local args = { params = {} }
    local runner = requestRunner()
    while true do
      args.params.timeout = telegram.next_update_id > -1 and telegram.timeout or 0
      args.params.offset = telegram.next_update_id
      local thread = runner("POST", TELEGRAM_BOT_METHOD_PATTERN:format(telegram.token, 'getUpdates'), encodeJson(args))
      handleAsyncHttpRequestThread(thread, function (result)
        print(result.text)
        local json = decodeJson(result.text)
        if not json or not json.ok then
          telegram.error = string.format('Код ошибки: %d | Описание: %s', json.error_code and json.error_code or -1, json.description and json.description or 'Невозможно распарсить JSON')
          return wait(10000)
        end
        telegram.error = nil;
        if json.result and #json.result > 0 then
          local last_update = json.result[#json.result]
          if telegram.onUpdate then
            for idx, update in ipairs(json.result) do
              telegram.onUpdate(update)
            end
          end
          telegram.next_update_id = last_update.update_id + 1
        end
      end, function (result)
        print(result)
        print('asyncHttpRequest tg error', result)
        telegram.error = 'telegram unknown error'
        wait(10000)
      end)
      wait(0)
    end
  end
  telegram.pollingThread = lua_thread.create_suspended(telegram.startPollingUpdates)
end

function telegram.onUpdate(update)
  local types = telegram.getUpdateTypes(update)
  if types.is('message') then
    -- Если это сообщение, отправляем его в чат SAMP
    local message = update.message.text
    sampSendChat(message)
  elseif types.is('callback_query') then
    local payload = u8:decode(update.callback_query.data);
    if payload == 'prikol' then
      sampAddChatMessage('юзаю прикол из телеги лол', -1)
      telegram.api.answerCallbackQuery({
        callback_query_id = update.callback_query.id,
        text = u8'привет из гта самп 2023'
      })
    elseif payload:find('^say|') then
      local message = payload:match('^say|(.+)');
      if not message then return end
      sampSendChat(message)
      telegram.api.answerCallbackQuery({
        callback_query_id = update.callback_query.id
      })
    end
  end
end


imgui.OnInitialize(function ()
  imgui.GetIO().IniFilename = nil
end)
local windowOpen = imgui.new.bool(false)
local telegramUserId = imgui.new.char[64]('tyt id')
local tokenInput = imgui.new.char[256](telegram.token)
local mainWindow = imgui.OnFrame(
  function() return windowOpen[0] end,
  function ()
    local sizeX, sizeY = getScreenResolution()
    imgui.SetNextWindowPos(imgui.ImVec2(sizeX / 2, sizeY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
    imgui.SetNextWindowSize(imgui.ImVec2(450, 200), imgui.Cond.FirstUseEver)
    imgui.Begin(u8'гайд от егдвача', windowOpen)
    imgui.PushItemWidth(150)
    imgui.InputText(u8'chat id юзера', telegramUserId, 64)
    if imgui.InputText(u8'токен бота', tokenInput, 256) then
      telegram.token = ffi.string(tokenInput)
    end
    imgui.PopItemWidth()
    imgui.SameLine()
    if imgui.Button(u8'перезапустить поллинг') then
      telegram.pollingThread:terminate()
      telegram.pollingThread:run()
    end
    if imgui.Button(u8'тестовое сообщение') then
      local p = telegram.api.sendMessage({
        chat_id = ffi.string(telegramUserId);
        text = 'Script work';
        reply_markup = encodeJson({
          inline_keyboard = {
            {
              {
                text = u8'сказать "привет"';
                callback_data = u8'say|привет';
              };
              {
                text = u8'сказать "пока"';
                callback_data = u8'say|пока';
              };
            };
            {
              {
                text = u8'крутой прикол';
                callback_data = u8'prikol'
              };
            };
          }
        }, true)
      });
      p:next(function (response)
        print('test result:', response.text)
      end)
    end
    imgui.Text(u8'состояние поллинга: ' .. (telegram.error and u8(tostring(telegram.error)) or u8('все хорошо')))
    imgui.End()
  end
)

function main()
  repeat
    wait(0)
  until isSampAvailable()
  sampAddChatMessage('new telegram guide. /tgtest', -1)
  sampRegisterChatCommand('tgtest', function()
    windowOpen[0] = not windowOpen[0]
  end)
  telegram.pollingThread:run()
  wait(-1);
end


function onExitScript(quitGame)
  telegram.pollingThread:terminate()
end

function sampev.onServerMessage(color, text)
local chat_id = ffi.string(telegramUserId)
local message = string.format('Сообщение сервера: %s', text)
telegram.api.sendMessage({
chat_id = chat_id,
text = message
})
end
chatlog
[18:39:39.580613] (script) updated_telegram_guide.lua: {"ok":true,"result":[]}
[18:40:09.942758] (script) updated_telegram_guide.lua: {"ok":true,"result":[]}
 

hajcm

Новичок
10
0
1712132400394.png

Крашит, в мунлоге ошибок нет.