Binder by DonHomka | Dev Diary

AnWu

Guardian of Order
Автор темы
Всефорумный модератор
4,687
5,164
Всем привет. Думаю даннах тема будет полезна всем кто только начинает писать скрипты, а так же тем кто хочет узнать немного больше. В этой теме я буду вести дневник разработчика. Что будем делать? Делать будем биндер для которого я недавно выбирал название. В ходе разработки я буду описывать здесь о итогах дня (если я что-то делал вообще )0), о том как что работает и почему я принял такое решение (если это возможно передать словами).
Так же тема будет служить фидбеком, все предложения я прочитаю и решу годится или нет.

Начнем ...

Так как начинаю вести не с первого дня, опишу что уже есть.

Интерфейс.
Я уже давно думал над подобным интерфейсом, так как я начал играть в гта 5 и мне понравились таблички всякие там, я недолго думая придумал свою концепцию и начал её реализовывать.
Интерфейс написан на mImGui (Minimal ImGui) который уже был анонсирован, но в релизе его еще нет и по словам фипа неизвестно когда появится. Почему он? Всё просто. В мИмГуи версия 1.66, что есть хорошо.

Писать на стандартном имгуи конечно не собирался сразу, иначе я бы придумал скрипт патруль. Поэтому словив ярость берсерка я набросал первый эскиз и он мне зашел.
photo_2018-12-24_11-44-30.jpg

Всё написано на DrawList (imgui.GetWindowDrawList()), и в ходе разработки, когда дело дошло до скролла, я столкнулся с рядом проблем: полосы строк уходили за пределы зоны скролла, сам скролл ломался и по мере прокрутки вниз увеличивался (бесконечный скролл воистину).
Проблема решилась на следующий день. Первый пункт фиксился обновлением переменной DrawList для зоны скролла (Каждый begin / beginchild в имгуи имеет свой собственный драв лист, поэтому использовав драв лист чужого окна всё к хренам уезжало). Со второй я помучался подольше. Оказалось нельзя факсически указывать положение элементов на экране с помощью SetCursorScreenPos(). Нужно было каждую строку получать текущее положение курсора на экране, рендерить элементы относительно этого положения, а после смещать положение на новую строку, чтобы следующий элемент был ниже.

Это пожалуй единственные трудности на данный момент. Разве что интерфейс не адаптирован под разрешения и красиво смотрится только на 1980x1080 на данный момент.

Редактор, структура профиля.
Особо не думал, заранее знал что файл профиля будет сохраняться в JSON формате.
Для реализации клавиш хотел изначально подойти со стороны парсинга строк, то есть "[3000]Test test[enter:1]" должно было служить задержкой, текстом и методом ввода. Но после парочки тестов понял что это глупо, и проще работать с таблицами, получилось:
Lua:
tHotKeys = {
    {
        keys = {v = {vkeys.VK_1}},
        text = {
            {
                 str = "Текст",
                 delay = 3000,
                 enter = 1
            }
    }
}
При изменении данных это очень решает, ведь ненадо собирать и разбирать строку постоянно. Меньше нагрузки и понятней код. По поводу записи клавиш через .v сделано для модуля mImGui Addons (уже переведен и улучшен)

Теперь сам редактор долго не мог представить как будет выглядить. Всё оказалось просто.
photo_2019-01-01_13-05-10.jpg

Дальше немного улучшив дизайн я просто фиксил баги, так как накидал всё на скорую руку, да и всё продумать не мог некоторые особенности пришли позже. Редактор был готов и можно было приступать к самим биндам.

Бинды.
Использую опять же свой модуль RKeys, с ним всё просто и удобно. Сложность была только в привязке ID-бинда к ID-биндера. Но там таблица на таблицу и всё на мази.
Для реализации чтения создал единый колбек, onHotKey. Модуль RKeys возвращает в колбек ID-бинд который его вызвал. По ID-бинду получаем ID нужных нам строк и подрубаем читалку.
ОСТОРОЖНО СЛОЖНО!
Read Data:
Lua:
local readData = {
   state = false,
   line = 0,
   time = 0
}
Сюда разве что добавлю ID читалки, для реализации отмены текущего чтения.
Lua:
function onHotKey(id, keys)
   local hid = rBind[id]
   local func = {
      sampSendChat,
      sampSetChatInputText,
      sampProcessChatInput,
      sampAddChatMessage,
      print
   }
   readData.state = true
   if hid then
      readData.line = 1
      if tHotKeys[hid].text[1] then
         readData.time = os.clock() + tHotKeys[hid].text[1].delay / 1000
      else
         readData.state = false
      end
      lua_thread.create(function ()
         while readData.state and readData.line <= table.maxn(tHotKeys[hid].text) do
            wait(0)
            local line = tHotKeys[hid].text[readData.line]
            if line then
               if os.clock() >= readData.time then
                  func[line.enter](line.str, -1)
                  if line.enter == 2 then
                     sampSetChatInputEnabled(true)
                  end
                  readData.line = readData.line + 1
                  local newline = tHotKeys[hid].text[readData.line]
                  if newline and newline.str:len() > 0 then
                     readData.time = os.clock() + newline.delay / 1000
                  else
                     local found = false
                     for i = readData.line, table.maxn(tHotKeys[hid].text) do
                        local newline = tHotKeys[hid].text[readData.line]
                        if newline and newline.str:len() > 0 then
                           found = true
                           readData.time = os.clock() + newline.delay / 1000
                        else
                           readData.line = readData.line + 1
                        end
                     end
                     if not found then
                        readData.state = false
                     end
                  end
               end
            else
               readData.line = readData.line + 1
            end
         end
      end)
   end
end
Тут всё сложнее. Постараюсь объяснить на буржуйском.
При чтении получаем 1 строку (пока что 1, физика биндера допускает что минимальный индекс строки может быть не 1). Получаем текст и её задержку. Устанавливаем текущее время + задержка для отправки строки. Ждём это время. Отправляем сообщение. Получаем следующую строку, если текст строки пустой - ищем не пустую строку или максимальный индекс. Получаем задержку и повторяем так пока строки не кончатся.
Думаю стоит прочитать пару раз прежде чем что-то понять.

Что это дает? Мы исключаем пустые строки биндера, а это значит ненужно перехерачивать все строки для удаления одной в середине.

Система отправки не совершенна, нету переменных, сложных условий, но это пока и ненадо. Со своей задачей он справляется - строки отправляет, делает всё как нужно.

Сохранение.
Так как сохранение сразу было в JSON формате, то и запись / чтение нужно делать самому. Отсюда код:
Получение
Lua:
local tHotKeys = {}

if doesFileExist(profile) then
   local f = io.open(profile, "r")
   if f then
      local text = f:read("*a")
      f:close()
      tHotKeys = text:len() > 0 and decodeJson(text) or {}
   end
end
Сохранение
Lua:
function saveHotKeys()
   if type(tHotKeys) == "table" then
      local f = io.open(profile, "w")
      f:close()
      if f then
         f = io.open(profile, "r+")
         f:write(encodeJson(tHotKeys))
         f:close()
      end
   end
end

Изначально сохранение было только в событии onScriptTerminate(), но это плохое решение. В один из многих перезагрузок ГТА у меня не сохранились изменения. Обратившись в фипу он сказал что это событие может не вызваться при выходе из игры. Поэтому сохранение переделал в функцию и просто вызываю после изменения чего либо.

На сегодня всё.

Ах да, отчет о сегодняшней работе:
- Исправил сохранение
- При создании клавиши автоматически создается в ней пустая строка
- При создании первой строки в клавише она имеет по-умолчанию 0 задержку (т.к. задержки первой строки тоже работают). Все последующие 1000 ms.
 

uryukhai

Активный
196
104
интерфейс действительно фапабельный и побольше бы в наше время дев блохеров)
 

AnWu

Guardian of Order
Автор темы
Всефорумный модератор
4,687
5,164
Кстати хотел обсудить такой варик, в чате напомнили.
Должен появиться много строчный редактор, чтобы не играться по строкам. Трудность выбора: сделать свой синтакс строк, как например [wait:8000]Строка[enter:1] или сделать редактор только текста, но с глобальными настройками задержки, метода ввода. Склоняюсь что второй вариант зайдет лучше! Или вовсе разделить на обычный и профи редактор.
 

штейн

Известный
Проверенный
1,001
687
бля че за имгуи дайте мне эту хуйню я хочу сделать пиздатое меню типа этого
 
  • Нравится
Реакции: Cake_

AnWu

Guardian of Order
Автор темы
Всефорумный модератор
4,687
5,164

Вложения

  • ucp.lua
    20.3 KB · Просмотры: 163
  • Нравится
Реакции: kmsfax

trefa

Известный
Всефорумный модератор
2,097
1,230
Кстати хотел обсудить такой варик, в чате напомнили.
Должен появиться много строчный редактор, чтобы не играться по строкам. Трудность выбора: сделать свой синтакс строк, как например [wait:8000]Строка[enter:1] или сделать редактор только текста, но с глобальными настройками задержки, метода ввода. Склоняюсь что второй вариант зайдет лучше! Или вовсе разделить на обычный и профи редактор.
Лучше раздели
 
  • Нравится
Реакции: AnWu

ox1

Новичок
64
7
Держи пять, бро, мне тоже нравится интерфейс из GTA V, респект за такой биндер!
 

F11GAR0.

Потрачен
0
57
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
на луа, ёптвою мать ну ты и извращенец конечно
 

AnWu

Guardian of Order
Автор темы
Всефорумный модератор
4,687
5,164