не передаются данные в ини кфг

w99zzl1

Участник
Автор темы
114
12
Версия MoonLoader
.026-beta
Здравия, мужики. Для большего понимания, приложу полный код.

Я написал скрипт, который при появлении диалогового окна ид 487 (паспорт) будет записывать из него информацию в иникфг, и во время игры, можно открыть эти данные через /database. Я не знаю почему, но почему то уровень, законопослушность, телефон и розыск не передаются корректно, их значение nil. Перед отправкой этой темы мне удалось решить проблему, но почему то, код резко выдал ошибку, когда я попытался применить изменение под все "данные" которые не правильно сохранялись. Получилось это с помощью - `local name = text:match("Имя:%s*(.-)\n") or "Неизвестно"` (только подставить данные под параметр, к примеру - `local phone = text:match("Телефон:%s*(.-)\n") or "Неизвестно"` (но как я и говорил, почему то, когда я решил применить всё что не отображалось, в один момент появилась ошибка, исправить которую я не могу)

Постоянно выдает (и выдало когда я почти пришел к успеху...) -
еррор:
[ML] (error) database.lua: D:\SAMSA MEDIUM PC\moonloader\lib\encoding.lua:63: bad argument #1 to 'iconv' (string expected, got nil)

stack traceback:
    [C]: in function 'iconv'
    D:\SAMSA MEDIUM PC\moonloader\lib\encoding.lua:63: in function 'u8'
    D:\SAMSA MEDIUM PC\moonloader\database.lua:78: in function '_draw'
    D:\SAMSA MEDIUM PC\moonloader\lib\mimgui\init.lua:107: in function <D:\SAMSA MEDIUM PC\moonloader\lib\mimgui\init.lua:91>
[ML] (error) database.lua: Script died due to an error. (0F70CF04)

Lua:
require "lib.moonloader"

local imgui = require 'mimgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local inicfg = require "inicfg"
local sampev = require "lib.samp.events"

local config = getGameDirectory() .. "\\moonloader\\config\\passport_data.ini"
local window = imgui.new.bool()
local passportData = {}
local passports = {}

function main()
    while not isSampAvailable() do wait(0) end

    sampRegisterChatCommand('database', function()
        window[0] = not window[0]
    end)

    loadData()
    while true do wait(0) end
end

function loadData()
    local file = io.open(config, "r")
    if file then
        file:close()
        passportData = inicfg.load({ passports = {} }, config) or { passports = {} }
        passports = passportData.passports
    else
        print("[ERROR] Файл не найден, создаю ini")
        passportData = { passports = {} }
        passports = passportData.passports
        saveData()
    end
end

function saveData()
    passportData.passports = passports
    local success = inicfg.save(passportData, config)
    if not success then
        print("[ERROR] Не удалось сохранить INI-файл!")
    end
end

function sampev.onShowDialog(dialogId, style, title, btn1, btn2, text)
    if dialogId == 487 then
        local name = text:match("Имя:%s*(.-)\n") or "Неизвестно"
        
        passports[name] = {
            Name = name,
            lvl = text:match("Проживание в стране %(лет%): (%d+)") or "0",
            Gender = text:match("Пол:%s*(.-)\n") or "Неизвестно",
            Status = text:match("Семейное положение:%s*(.-)\n") or "Неизвестно",
            Residence = text:match("Проживание:%s*(.-)\n") or "Неизвестно",
            Job = text:match("Работа:%s*(.-)\n") or "Неизвестно",
            Organization = text:match("Организация:%s*(.-)\n") or "Нет",
            Department = text:match("Подразделение:%s*(.-)\n") or "Нет",
            Phone = text:match("Телефон:%s*(%d+)") or "Нет",
            Wanted = text:match("Уровень розыска:%s*(%d+)") or "0",
            Lawfulness = text:match("Законопослушность:%s*(%d+)") or "0"
        }

        saveData()
    end
end

imgui.OnFrame(function() return window[0] end, function()
    local X, Y = getScreenResolution()

    imgui.SetNextWindowSize(imgui.ImVec2(700, 500), imgui.Cond.FirstUseEver)
    imgui.SetNextWindowPos(imgui.ImVec2(X / 2 - 350, Y / 2 - 250), imgui.Cond.FirstUseEver)

    if imgui.Begin(u8'База паспортов', window) then
        for name, data in pairs(passports) do
            imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8(data.Name))
            imgui.Separator()
            imgui.Text(u8('Проживание в стране (лет): ') .. u8(data.lvl))
            imgui.Text(u8('Пол: ') .. u8(data.Gender))
            imgui.Text(u8('Семейное положение: ') .. u8(data.Status))
            imgui.Text(u8('Проживание: ') .. u8(data.Residence))
            imgui.Text(u8('Работа: ') .. u8(data.Job))
            imgui.Text(u8('Организация: ') .. u8(data.Organization))
            imgui.Text(u8('Подразделение: ') .. u8(data.Department))
            imgui.Text(u8('Телефон: ') .. u8(data.Phone))
            imgui.Text(u8('Уровень розыска: ') .. u8(data.Wanted))
            imgui.Text(u8('Законопослушность: ') .. u8(data.Lawfulness))
            imgui.Separator()
        end
        imgui.End()
    end
end)
(конечно, не самый лучший код этого скрипта, но я потерял лучшую версию. Надеюсь, так понятно, и мне смогут помочь)
 
  • Нравится
Реакции: Vespan
Решение
Вобщем, ребята, всем огромное спасибо! Без вас, я бы не справился. С горем пополам сделал адекватный код, которые передает все данные. Но были баги, вроде сами исчезли, если правильно пользоваться)) Поэтому, думаю правильным отправить сюда полный код и отметить решением именно его, (дабы другие пользователи могли видеть решение), из за чего такая дребедень, я так и не понял, если честно) постараюсь отметить каждую функцию с автором из этой темы. Ещё раз всем спасибо! Проблема - решена.
Код:
-- Структура кода Благодаря - https://www.blast.hk/members/474832/ (Поиск, удаление и время обновления)

require "lib.moonloader"

local imgui = require 'mimgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local...

kyrtion

Известный
1,096
395
Во-первых, воспользуйся json (https://www.blast.hk/threads/214849/) раз и навсегда
Во-вторых, для парса в диалог желательно зациклить, дабы чтобы парсить по каждой строке, а не в целом контент диалога:
 
  • Влюблен
Реакции: w99zzl1

w99zzl1

Участник
Автор темы
114
12
Получилось так:


Lua:
require "lib.moonloader"
local imgui = require 'mimgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local json = require "dkjson"
local sampev = require "lib.samp.events"
local configPath = getGameDirectory() .. "\\moonloader\\config\\passport_data.json"
local window = imgui.new.bool()
local passports = {}
function main()
    while not isSampAvailable() do wait(0) end
    sampRegisterChatCommand('database', function()
        window[0] = not window[0]
    end)
    loadData()
    while true do wait(0) end
end
function loadData()
    local file = io.open(configPath, "r")
    if file then
        local content = file:read("*a")
        file:close()
        local success, parsedData = pcall(json.decode, content)
        if success and type(parsedData) == "table" then
            passports = parsedData
        else
            print("[ERROR] Ошибка загрузки JSON, создаю новый файл")
            passports = {}
            saveData()
        end
    else
        print("[ERROR] Файл не найден, создаю новый JSON")
        passports = {}
        saveData()
    end
end
function saveData()
    local file = io.open(configPath, "w")
    if file then
        file:write(json.encode(passports, { indent = true }))
        file:close()
    else
        print("[ERROR] Не удалось сохранить JSON-файл!")
    end
end
function sampev.onShowDialog(dialogId, style, title, btn1, btn2, text)
    if dialogId == 487 then
        print("=== TEXT ===")
        print(text)
        print("=== END TEXT ===")
        local name = tostring(text:match("Имя:%s*(.-)\n") or "Неизвестно")
        passports[name] = {
            Name = name,
            lvl = tostring(text:match("Проживание в стране (лет):%s*(.-)\n") or "0"),
            Gender = tostring(text:match("Пол:%s*(.-)\n") or "Неизвестно"),
            Status = tostring(text:match("Семейное положение:%s*(.-)\n") or "Неизвестно"),
            Residence = tostring(text:match("Проживание:%s*(.-)\n") or "Неизвестно"),
            Job = tostring(text:match("Работа:%s*(.-)\n") or "Неизвестно"),
            Organization = tostring(text:match("Организация:%s*(.-)\n") or "Нет"),
            Department = tostring(text:match("Подразделение:%s*(.-)\n") or "Нет"),
            Phone = tostring(text:match("Телефон:%s*(.-)\n") or "Нет"),
            Wanted = tostring(text:match("Уровень розыска:%s*(.-)\n") or "0"),
            Lawfulness = tostring(text:match("Законопослушность:%s*(.-)") or "0")
        }
        saveData()
    end
end
imgui.OnFrame(function() return window[0] end, function()
    local X, Y = getScreenResolution()
    imgui.SetNextWindowSize(imgui.ImVec2(700, 500), imgui.Cond.FirstUseEver)
    imgui.SetNextWindowPos(imgui.ImVec2(X / 2 - 350, Y / 2 - 250), imgui.Cond.FirstUseEver)
    if imgui.Begin(u8'База паспортов', window) then
        for name, data in pairs(passports) do
            if data.Name and data.lvl and data.Gender and data.Phone then
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8(data.Name))
                imgui.Separator()
                imgui.Text(u8('Проживание в стране (лет): ') .. u8(data.lvl))
                imgui.Text(u8('Пол: ') .. u8(data.Gender))
                imgui.Text(u8('Семейное положение: ') .. u8(data.Status))
                imgui.Text(u8('Проживание: ') .. u8(data.Residence))
                imgui.Text(u8('Работа: ') .. u8(data.Job))
                imgui.Text(u8('Организация: ') .. u8(data.Organization))
                imgui.Text(u8('Подразделение: ') .. u8(data.Department))
                imgui.Text(u8('Телефон: ') .. u8(data.Phone))
                imgui.Text(u8('Уровень розыска: ') .. u8(data.Wanted))
                imgui.Text(u8('Законопослушность: ') .. u8(data.Lawfulness))
                imgui.Separator()
            else
                print("[ERROR] В паспорте " .. tostring(name) .. " есть nil-значения!")
            end
        end
        imgui.End()
    end
end)

Но основная проблема по прежнему остается - не передают данные Законки, розыска и лет в федерации( Телефон вроде пофиксил

Во-первых, воспользуйся json (https://www.blast.hk/threads/214849/) раз и навсегда
Во-вторых, для парса в диалог желательно зациклить, дабы чтобы парсить по каждой строке, а не в целом контент диалога:
 

zuxobu

Участник
8
4
хз что я сделал, но попробуй, может поможет (я не тестил)

lua:
require "lib.moonloader"

local imgui = require 'mimgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local json = require "dkjson"
local sampev = require "lib.samp.events"
local ffi = require 'ffi'

-- Путь к JSON файлу
local config = getGameDirectory() .. "\\moonloader\\config\\passport_data.json"
local window = imgui.new.bool()
local passports = {}

-- Вспомогательная функция для безопасной конвертации в UTF-8
function safeU8(text)
    if text then
        return u8(tostring(text))
    end
    return u8("Неизвестно")
end

function main()
    while not isSampAvailable() do wait(0) end

    sampRegisterChatCommand('database', function()
        window[0] = not window[0]
    end)

    loadData()
    while true do
        wait(0)

    end
end

function loadData()
    local file = io.open(config, "r")


    if file then
        local content = file:read("*all")
        file:close()
        -- Декодируем JSON
        passports = decodeJson(content) or {}
    else
        print("[ERROR] Файл не найден, создаю JSON")
        passports = {}
        saveData()
    end
end

function saveData()
    -- Кодируем в JSON и сохраняем
    local file = io.open(config, "w")
    if file then
        local content = encodeJson(passports)
        file:write(content)
        file:close()
    else
        print("[ERROR] Не удалось сохранить JSON-файл!")
    end
end

function sampev.onShowDialog(dialogId, style, title, btn1, btn2, text)
    if dialogId == 487 then
        local name = text:match("Имя:%s*(.-)\n") or "Неизвестно"
        local phone = text:match("Телефон:%s*(%d+)") or "Нет"
        local wanted = text:match("Уровень розыска:%s*(%d+)") or "0"
        local lawfulness = text:match("Законопослушность:%s*(%d+)") or "0"
        local level = text:match("Проживание в стране %(лет%): (%d+)") or "0"
        
        -- Создаем запись в базе
        passports[name] = {
            Name = name,
            lvl = level,
            Gender = text:match("Пол:%s*(.-)\n") or "Неизвестно",
            Status = text:match("Семейное положение:%s*(.-)\n") or "Неизвестно",
            Residence = text:match("Проживание:%s*(.-)\n") or "Неизвестно",
            Job = text:match("Работа:%s*(.-)\n") or "Неизвестно",
            Organization = text:match("Организация:%s*(.-)\n") or "Нет",
            Department = text:match("Подразделение:%s*(.-)\n") or "Нет",
            Phone = phone,
            Wanted = wanted,
            Lawfulness = lawfulness,
            LastUpdate = os.date("%d.%m.%Y %H:%M:%S") -- Добавляем дату последнего обновления
        }

        saveData()
        sampAddChatMessage("[DATABASE] Паспортные данные сохранены", -1)
    end
end

-- Функция поиска по базе
function searchInPassports(query)
    local results = {}
    query = query:lower()
    for name, data in pairs(passports) do
        if name:lower():find(query) or
           data.Phone:find(query) or
           data.Organization:lower():find(query) then
            results[name] = data
        end
    end
    return results
end

-- Буфер для поиска
local searchBuffer = imgui.new.char[256]()

imgui.OnFrame(function() return window[0] end, function()
    local X, Y = getScreenResolution()

    imgui.SetNextWindowSize(imgui.ImVec2(700, 500), imgui.Cond.FirstUseEver)
    imgui.SetNextWindowPos(imgui.ImVec2(X / 2 - 350, Y / 2 - 250), imgui.Cond.FirstUseEver)

    if imgui.Begin(u8'База паспортов', window) then
        -- Добавляем поиск
        if imgui.InputText(u8"Поиск", searchBuffer, ffi.sizeof(searchBuffer)) then
            -- Можно добавить мгновенный поиск при вводе
        end
        
        -- Кнопка поиска
        if imgui.Button(u8"Найти") then
            local query = ffi.string(searchBuffer)
            if query ~= "" then
                local results = searchInPassports(query)
                passports = results -- Временно показываем только результаты
                -- Можно добавить кнопку "Показать все"
            end
        end
        
        imgui.SameLine()
        if imgui.Button(u8"Показать все") then
            loadData() -- Перезагружаем все данные
        end
        
        imgui.Separator()

        -- Отображение данных
        for name, data in pairs(passports) do
            if imgui.CollapsingHeader(safeU8(data.Name)) then
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Основная информация:")
                imgui.Text(u8('Проживание в стране (лет): ') .. safeU8(data.lvl))
                imgui.Text(u8('Пол: ') .. safeU8(data.Gender))
                imgui.Text(u8('Семейное положение: ') .. safeU8(data.Status))
                imgui.Text(u8('Проживание: ') .. safeU8(data.Residence))
                
                imgui.Spacing()
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Работа:")
                imgui.Text(u8('Работа: ') .. safeU8(data.Job))
                imgui.Text(u8('Организация: ') .. safeU8(data.Organization))
                imgui.Text(u8('Подразделение: ') .. safeU8(data.Department))
                
                imgui.Spacing()
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Дополнительно:")
                imgui.Text(u8('Телефон: ') .. safeU8(data.Phone))
                imgui.Text(u8('Уровень розыска: ') .. safeU8(data.Wanted))
                imgui.Text(u8('Законопослушность: ') .. safeU8(data.Lawfulness))
                
                if data.LastUpdate then
                    imgui.TextColored(imgui.ImVec4(0.7, 0.7, 0.7, 1), u8"Последнее обновление: " .. safeU8(data.LastUpdate))
                end
                
                -- Добавляем кнопку удаления записи
                if imgui.Button(u8"Удалить запись##" .. name) then
                    passports[name] = nil
                    saveData()
                    sampAddChatMessage("[DATABASE] Запись удалена", -1)
                end
                
                imgui.Separator()
            end
        end
        imgui.End()
    end
end)
 
  • Влюблен
Реакции: w99zzl1

w99zzl1

Участник
Автор темы
114
12
хз что я сделал, но попробуй, может поможет (я не тестил)

lua:
require "lib.moonloader"

local imgui = require 'mimgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local json = require "dkjson"
local sampev = require "lib.samp.events"
local ffi = require 'ffi'

-- Путь к JSON файлу
local config = getGameDirectory() .. "\\moonloader\\config\\passport_data.json"
local window = imgui.new.bool()
local passports = {}

-- Вспомогательная функция для безопасной конвертации в UTF-8
function safeU8(text)
    if text then
        return u8(tostring(text))
    end
    return u8("Неизвестно")
end

function main()
    while not isSampAvailable() do wait(0) end

    sampRegisterChatCommand('database', function()
        window[0] = not window[0]
    end)

    loadData()
    while true do
        wait(0)

    end
end

function loadData()
    local file = io.open(config, "r")


    if file then
        local content = file:read("*all")
        file:close()
        -- Декодируем JSON
        passports = decodeJson(content) or {}
    else
        print("[ERROR] Файл не найден, создаю JSON")
        passports = {}
        saveData()
    end
end

function saveData()
    -- Кодируем в JSON и сохраняем
    local file = io.open(config, "w")
    if file then
        local content = encodeJson(passports)
        file:write(content)
        file:close()
    else
        print("[ERROR] Не удалось сохранить JSON-файл!")
    end
end

function sampev.onShowDialog(dialogId, style, title, btn1, btn2, text)
    if dialogId == 487 then
        local name = text:match("Имя:%s*(.-)\n") or "Неизвестно"
        local phone = text:match("Телефон:%s*(%d+)") or "Нет"
        local wanted = text:match("Уровень розыска:%s*(%d+)") or "0"
        local lawfulness = text:match("Законопослушность:%s*(%d+)") or "0"
        local level = text:match("Проживание в стране %(лет%): (%d+)") or "0"
       
        -- Создаем запись в базе
        passports[name] = {
            Name = name,
            lvl = level,
            Gender = text:match("Пол:%s*(.-)\n") or "Неизвестно",
            Status = text:match("Семейное положение:%s*(.-)\n") or "Неизвестно",
            Residence = text:match("Проживание:%s*(.-)\n") or "Неизвестно",
            Job = text:match("Работа:%s*(.-)\n") or "Неизвестно",
            Organization = text:match("Организация:%s*(.-)\n") or "Нет",
            Department = text:match("Подразделение:%s*(.-)\n") or "Нет",
            Phone = phone,
            Wanted = wanted,
            Lawfulness = lawfulness,
            LastUpdate = os.date("%d.%m.%Y %H:%M:%S") -- Добавляем дату последнего обновления
        }

        saveData()
        sampAddChatMessage("[DATABASE] Паспортные данные сохранены", -1)
    end
end

-- Функция поиска по базе
function searchInPassports(query)
    local results = {}
    query = query:lower()
    for name, data in pairs(passports) do
        if name:lower():find(query) or
           data.Phone:find(query) or
           data.Organization:lower():find(query) then
            results[name] = data
        end
    end
    return results
end

-- Буфер для поиска
local searchBuffer = imgui.new.char[256]()

imgui.OnFrame(function() return window[0] end, function()
    local X, Y = getScreenResolution()

    imgui.SetNextWindowSize(imgui.ImVec2(700, 500), imgui.Cond.FirstUseEver)
    imgui.SetNextWindowPos(imgui.ImVec2(X / 2 - 350, Y / 2 - 250), imgui.Cond.FirstUseEver)

    if imgui.Begin(u8'База паспортов', window) then
        -- Добавляем поиск
        if imgui.InputText(u8"Поиск", searchBuffer, ffi.sizeof(searchBuffer)) then
            -- Можно добавить мгновенный поиск при вводе
        end
       
        -- Кнопка поиска
        if imgui.Button(u8"Найти") then
            local query = ffi.string(searchBuffer)
            if query ~= "" then
                local results = searchInPassports(query)
                passports = results -- Временно показываем только результаты
                -- Можно добавить кнопку "Показать все"
            end
        end
       
        imgui.SameLine()
        if imgui.Button(u8"Показать все") then
            loadData() -- Перезагружаем все данные
        end
       
        imgui.Separator()

        -- Отображение данных
        for name, data in pairs(passports) do
            if imgui.CollapsingHeader(safeU8(data.Name)) then
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Основная информация:")
                imgui.Text(u8('Проживание в стране (лет): ') .. safeU8(data.lvl))
                imgui.Text(u8('Пол: ') .. safeU8(data.Gender))
                imgui.Text(u8('Семейное положение: ') .. safeU8(data.Status))
                imgui.Text(u8('Проживание: ') .. safeU8(data.Residence))
               
                imgui.Spacing()
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Работа:")
                imgui.Text(u8('Работа: ') .. safeU8(data.Job))
                imgui.Text(u8('Организация: ') .. safeU8(data.Organization))
                imgui.Text(u8('Подразделение: ') .. safeU8(data.Department))
               
                imgui.Spacing()
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Дополнительно:")
                imgui.Text(u8('Телефон: ') .. safeU8(data.Phone))
                imgui.Text(u8('Уровень розыска: ') .. safeU8(data.Wanted))
                imgui.Text(u8('Законопослушность: ') .. safeU8(data.Lawfulness))
               
                if data.LastUpdate then
                    imgui.TextColored(imgui.ImVec4(0.7, 0.7, 0.7, 1), u8"Последнее обновление: " .. safeU8(data.LastUpdate))
                end
               
                -- Добавляем кнопку удаления записи
                if imgui.Button(u8"Удалить запись##" .. name) then
                    passports[name] = nil
                    saveData()
                    sampAddChatMessage("[DATABASE] Запись удалена", -1)
                end
               
                imgui.Separator()
            end
        end
        imgui.End()
    end
end)
Воу! Ну, это круто! Это прям то, что мне нужно! Но етить, проблема с сохранением лвл, законки и розыска присутствует(
 

zuxobu

Участник
8
4
2 часа пытался понять в чём проблема, 2 часа пытался найти кто поможет протестить код, но не нашёл, поэтому пробуй сам

lua:
require "lib.moonloader"

local imgui = require 'mimgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local json = require "dkjson"
local sampev = require "samp.events"
local ffi = require 'ffi'

-- Путь к JSON файлу
local config = getGameDirectory() .. "\\moonloader\\config\\passport_data.json"
local window = imgui.new.bool()
local passports = {}

function main()
    while not isSampAvailable() do wait(100) end
    sampRegisterChatCommand('database', function()
        window[0] = not window[0]
    end)

    loadData()
    while true do
        wait(0)
        if os.clock() % 300 < 1 then
            saveData()
            wait(1000)
        end
    end
end

function log(label, text)
    local file = io.open(getGameDirectory() .. "\\moonloader\\database_log.txt", "a")
    if file then
        file:write(os.date("[%d.%m.%Y %H:%M:%S] ") .. label .. ": " .. tostring(text) .. "\n")
        file:close()
    end
end

function sampev.onShowDialog(dialogId, style, title, btn1, btn2, text)
    if title == "Паспорт" then
        log("Dialog Text", text) -- логируем текст диалога
        
        local name = text:match("Имя:%s*(.-)\n") or "Неизвестно"
        log("Found Name", name) -- логируем найденное имя
        
        -- Извлекаем данные с проверкой
        local level = text:match("Проживание в стране %(лет%):%s*(%d+)") or
                     text:match("Уровень:%s*(%d+)") or "0"
        
        local lawfulness = text:match("Законопослушность:%s*(%d+)") or
                          text:match("Законопослушность:%s*([%d%.]+)") or "0"
        
        local wanted = text:match("Уровень розыска:%s*(%d+)") or
                      text:match("Розыск:%s*(%d+)") or "0"
        
        -- Создаем новую запись
        local newEntry = {
            Name = name,
            lvl = tostring(level),
            Gender = text:match("Пол:%s*(.-)\n") or "Неизвестно",
            Status = text:match("Семейное положение:%s*(.-)\n") or "Неизвестно",
            Residence = text:match("Проживание:%s*(.-)\n") or "Неизвестно",
            Job = text:match("Работа:%s*(.-)\n") or "Неизвестно",
            Organization = text:match("Организация:%s*(.-)\n") or "Нет",
            Department = text:match("Подразделение:%s*(.-)\n") or "Нет",
            Phone = text:match("Телефон:%s*(%d+)") or "Нет",
            Wanted = tostring(wanted),
            Lawfulness = tostring(lawfulness),
            LastUpdate = os.date("%d.%m.%Y %H:%M:%S")
        }
        
        log("New Entry", encodeJson(newEntry)) -- логируем новую запись
        
        -- Добавляем запись в базу
        passports[name] = newEntry
        
        -- Сохраняем данные
        local success = saveData()
        if success then
            sampAddChatMessage("[DATABASE] Паспортные данные сохранены", -1)
            log("Save Status", "Success")
        else
            sampAddChatMessage("[DATABASE] Ошибка при сохранении данных", -1)
            log("Save Status", "Failed")
        end
        
        return false -- не блокируем диалог
    end
end

-- Обновленная функция сохранения
function saveData()
    local success = pcall(function()
        local file = io.open(config, "w")
        if file then
            local content = encodeJson(passports)
            log("Saving Content", content) -- логируем содержимое
            file:write(content)
            file:close()
        else
            error("Cannot open file for writing")
        end
    end)
    
    return success
end

-- Обновленная функция загрузки
function loadData()
    local success = pcall(function()
        local file = io.open(config, "r")
        if file then
            local content = file:read("*all")
            file:close()
            log("Loading Content", content) -- логируем загруженное содержимое
            
            if content and content ~= "" then
                passports = decodeJson(content) or {}
            else
                passports = {}
            end
        else
            log("File Status", "Not found, creating new")
            passports = {}
            saveData()
        end
    end)
    
    if not success then
        log("Load Error", "Failed to load data")
        passports = {}
    end
end

-- Функция поиска по базе
function searchInPassports(query)
    local results = {}
    query = query:lower()
    for name, data in pairs(passports) do
        if name:lower():find(query) or
           data.Phone:find(query) or
           data.Organization:lower():find(query) then
            results[name] = data
        end
    end
    return results
end

-- Буфер для поиска
local searchBuffer = imgui.new.char[256]()

imgui.OnFrame(function() return window[0] end, function()
    local X, Y = getScreenResolution()

    imgui.SetNextWindowSize(imgui.ImVec2(700, 500), imgui.Cond.FirstUseEver)
    imgui.SetNextWindowPos(imgui.ImVec2(X / 2 - 350, Y / 2 - 250), imgui.Cond.FirstUseEver)

    if imgui.Begin(u8'База паспортов##database', window) then
        -- Поиск
        if imgui.InputText(u8"Поиск", searchBuffer, ffi.sizeof(searchBuffer)) then end
        
        if imgui.Button(u8"Найти") then
            local query = ffi.string(searchBuffer)
            if query ~= "" then
                local results = searchInPassports(query)
                passports = results
            end
        end
        
        imgui.SameLine()
        if imgui.Button(u8"Показать все") then
            loadData()
        end
        
        imgui.Separator()

        -- Проверяем наличие данных
        local hasData = false
        for _ in pairs(passports) do
            hasData = true
            break
        end

        if not hasData then
            imgui.TextColored(imgui.ImVec4(1, 0.5, 0.5, 1), u8"База данных пуста")
        else
            -- Отображение данных
            for name, data in pairs(passports) do
                if imgui.CollapsingHeader(safeU8(name) .. "##" .. name) then
                    -- Основная информация
                    imgui.BeginChild("info_" .. name, imgui.ImVec2(0, 200), true)
                    
                    imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Основная информация:")
                    imgui.Text(u8"Имя: " .. safeU8(data.Name))
                    imgui.Text(u8"Уровень: " .. safeU8(data.lvl))
                    imgui.Text(u8"Пол: " .. safeU8(data.Gender))
                    imgui.Text(u8"Статус: " .. safeU8(data.Status))
                    imgui.Text(u8"Проживание: " .. safeU8(data.Residence))
                    
                    imgui.Spacing()
                    imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Работа:")
                    imgui.Text(u8"Работа: " .. safeU8(data.Job))
                    imgui.Text(u8"Организация: " .. safeU8(data.Organization))
                    imgui.Text(u8"Подразделение: " .. safeU8(data.Department))
                    
                    imgui.Spacing()
                    imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Дополнительная информация:")
                    imgui.Text(u8"Телефон: " .. safeU8(data.Phone))
                    imgui.Text(u8"Розыск: " .. safeU8(data.Wanted))
                    imgui.Text(u8"Законопослушность: " .. safeU8(data.Lawfulness))
                    
                    if data.LastUpdate then
                        imgui.TextColored(imgui.ImVec4(0.7, 0.7, 0.7, 1), u8"Обновлено: " .. safeU8(data.LastUpdate))
                    end
                    
                    -- Кнопка удаления
                    if imgui.Button(u8"Удалить##" .. name) then
                        passports[name] = nil
                        saveData()
                        sampAddChatMessage("[DATABASE] Запись удалена", -1)
                    end
                    
                    imgui.EndChild()
                end
            end
        end
        
        imgui.End()
    end
end)

-- Обновляем функцию safeU8
function safeU8(text)
    if text == nil then return u8("Неизвестно") end
    if type(text) ~= "string" then text = tostring(text) end
    return u8(text)
end
 
  • Влюблен
Реакции: w99zzl1

kyrtion

Известный
1,096
395
Автору бы желательно скинуть хотя бы скриншот диалога/полный его текст
дабы смогли помочь
и желательно полный исходник диалога, включая ид, стиль, титль и тд
 
  • Нравится
  • Влюблен
Реакции: w99zzl1 и outdated

w99zzl1

Участник
Автор темы
114
12
Автору бы желательно скинуть хотя бы скриншот диалога/полный его текст
дабы смогли помочь
Оой... Что то я вообще. Конечно, вот:

1739051173701.png

По началу я думал, что ошибка из за цвета. Но ведь номер сохраняется, и имя

Да и дом тоже сохраняется

2 часа пытался понять в чём проблема, 2 часа пытался найти кто поможет протестить код, но не нашёл, поэтому пробуй сам

lua:
require "lib.moonloader"

local imgui = require 'mimgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local json = require "dkjson"
local sampev = require "samp.events"
local ffi = require 'ffi'

-- Путь к JSON файлу
local config = getGameDirectory() .. "\\moonloader\\config\\passport_data.json"
local window = imgui.new.bool()
local passports = {}

function main()
    while not isSampAvailable() do wait(100) end
    sampRegisterChatCommand('database', function()
        window[0] = not window[0]
    end)

    loadData()
    while true do
        wait(0)
        if os.clock() % 300 < 1 then
            saveData()
            wait(1000)
        end
    end
end

function log(label, text)
    local file = io.open(getGameDirectory() .. "\\moonloader\\database_log.txt", "a")
    if file then
        file:write(os.date("[%d.%m.%Y %H:%M:%S] ") .. label .. ": " .. tostring(text) .. "\n")
        file:close()
    end
end

function sampev.onShowDialog(dialogId, style, title, btn1, btn2, text)
    if title == "Паспорт" then
        log("Dialog Text", text) -- логируем текст диалога
      
        local name = text:match("Имя:%s*(.-)\n") or "Неизвестно"
        log("Found Name", name) -- логируем найденное имя
      
        -- Извлекаем данные с проверкой
        local level = text:match("Проживание в стране %(лет%):%s*(%d+)") or
                     text:match("Уровень:%s*(%d+)") or "0"
      
        local lawfulness = text:match("Законопослушность:%s*(%d+)") or
                          text:match("Законопослушность:%s*([%d%.]+)") or "0"
      
        local wanted = text:match("Уровень розыска:%s*(%d+)") or
                      text:match("Розыск:%s*(%d+)") or "0"
      
        -- Создаем новую запись
        local newEntry = {
            Name = name,
            lvl = tostring(level),
            Gender = text:match("Пол:%s*(.-)\n") or "Неизвестно",
            Status = text:match("Семейное положение:%s*(.-)\n") or "Неизвестно",
            Residence = text:match("Проживание:%s*(.-)\n") or "Неизвестно",
            Job = text:match("Работа:%s*(.-)\n") or "Неизвестно",
            Organization = text:match("Организация:%s*(.-)\n") or "Нет",
            Department = text:match("Подразделение:%s*(.-)\n") or "Нет",
            Phone = text:match("Телефон:%s*(%d+)") or "Нет",
            Wanted = tostring(wanted),
            Lawfulness = tostring(lawfulness),
            LastUpdate = os.date("%d.%m.%Y %H:%M:%S")
        }
      
        log("New Entry", encodeJson(newEntry)) -- логируем новую запись
      
        -- Добавляем запись в базу
        passports[name] = newEntry
      
        -- Сохраняем данные
        local success = saveData()
        if success then
            sampAddChatMessage("[DATABASE] Паспортные данные сохранены", -1)
            log("Save Status", "Success")
        else
            sampAddChatMessage("[DATABASE] Ошибка при сохранении данных", -1)
            log("Save Status", "Failed")
        end
      
        return false -- не блокируем диалог
    end
end

-- Обновленная функция сохранения
function saveData()
    local success = pcall(function()
        local file = io.open(config, "w")
        if file then
            local content = encodeJson(passports)
            log("Saving Content", content) -- логируем содержимое
            file:write(content)
            file:close()
        else
            error("Cannot open file for writing")
        end
    end)
  
    return success
end

-- Обновленная функция загрузки
function loadData()
    local success = pcall(function()
        local file = io.open(config, "r")
        if file then
            local content = file:read("*all")
            file:close()
            log("Loading Content", content) -- логируем загруженное содержимое
          
            if content and content ~= "" then
                passports = decodeJson(content) or {}
            else
                passports = {}
            end
        else
            log("File Status", "Not found, creating new")
            passports = {}
            saveData()
        end
    end)
  
    if not success then
        log("Load Error", "Failed to load data")
        passports = {}
    end
end

-- Функция поиска по базе
function searchInPassports(query)
    local results = {}
    query = query:lower()
    for name, data in pairs(passports) do
        if name:lower():find(query) or
           data.Phone:find(query) or
           data.Organization:lower():find(query) then
            results[name] = data
        end
    end
    return results
end

-- Буфер для поиска
local searchBuffer = imgui.new.char[256]()

imgui.OnFrame(function() return window[0] end, function()
    local X, Y = getScreenResolution()

    imgui.SetNextWindowSize(imgui.ImVec2(700, 500), imgui.Cond.FirstUseEver)
    imgui.SetNextWindowPos(imgui.ImVec2(X / 2 - 350, Y / 2 - 250), imgui.Cond.FirstUseEver)

    if imgui.Begin(u8'База паспортов##database', window) then
        -- Поиск
        if imgui.InputText(u8"Поиск", searchBuffer, ffi.sizeof(searchBuffer)) then end
      
        if imgui.Button(u8"Найти") then
            local query = ffi.string(searchBuffer)
            if query ~= "" then
                local results = searchInPassports(query)
                passports = results
            end
        end
      
        imgui.SameLine()
        if imgui.Button(u8"Показать все") then
            loadData()
        end
      
        imgui.Separator()

        -- Проверяем наличие данных
        local hasData = false
        for _ in pairs(passports) do
            hasData = true
            break
        end

        if not hasData then
            imgui.TextColored(imgui.ImVec4(1, 0.5, 0.5, 1), u8"База данных пуста")
        else
            -- Отображение данных
            for name, data in pairs(passports) do
                if imgui.CollapsingHeader(safeU8(name) .. "##" .. name) then
                    -- Основная информация
                    imgui.BeginChild("info_" .. name, imgui.ImVec2(0, 200), true)
                  
                    imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Основная информация:")
                    imgui.Text(u8"Имя: " .. safeU8(data.Name))
                    imgui.Text(u8"Уровень: " .. safeU8(data.lvl))
                    imgui.Text(u8"Пол: " .. safeU8(data.Gender))
                    imgui.Text(u8"Статус: " .. safeU8(data.Status))
                    imgui.Text(u8"Проживание: " .. safeU8(data.Residence))
                  
                    imgui.Spacing()
                    imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Работа:")
                    imgui.Text(u8"Работа: " .. safeU8(data.Job))
                    imgui.Text(u8"Организация: " .. safeU8(data.Organization))
                    imgui.Text(u8"Подразделение: " .. safeU8(data.Department))
                  
                    imgui.Spacing()
                    imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Дополнительная информация:")
                    imgui.Text(u8"Телефон: " .. safeU8(data.Phone))
                    imgui.Text(u8"Розыск: " .. safeU8(data.Wanted))
                    imgui.Text(u8"Законопослушность: " .. safeU8(data.Lawfulness))
                  
                    if data.LastUpdate then
                        imgui.TextColored(imgui.ImVec4(0.7, 0.7, 0.7, 1), u8"Обновлено: " .. safeU8(data.LastUpdate))
                    end
                  
                    -- Кнопка удаления
                    if imgui.Button(u8"Удалить##" .. name) then
                        passports[name] = nil
                        saveData()
                        sampAddChatMessage("[DATABASE] Запись удалена", -1)
                    end
                  
                    imgui.EndChild()
                end
            end
        end
      
        imgui.End()
    end
end)

-- Обновляем функцию safeU8
function safeU8(text)
    if text == nil then return u8("Неизвестно") end
    if type(text) ~= "string" then text = tostring(text) end
    return u8(text)
end
(не решено, но...) Спасибо большое! Ценю, если что, сразу кидай сюда, ничего страшного. Но ошибку это всё равно не решило. Не сохраняется уровень и все данные из "доп. инф." (Телефон, розыск, законка)

1739051490722.png

Вот что показывает (код:

Lua:
require "lib.moonloader"

local imgui = require 'mimgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local json = require "dkjson"
local sampev = require "lib.samp.events"
local ffi = require 'ffi'

-- Путь к JSON файлу
local config = getGameDirectory() .. "\\moonloader\\config\\passport_data.json"
local window = imgui.new.bool()
local passports = {}

-- Вспомогательная функция для безопасной конвертации в UTF-8
function safeU8(text)
    if text then
        return u8(tostring(text))
    end
    return u8("Неизвестно")
end

function main()
    while not isSampAvailable() do wait(0) end

    sampRegisterChatCommand('database', function()
        window[0] = not window[0]
    end)

    loadData()
    while true do
        wait(0)

    end
end

function loadData()
    local file = io.open(config, "r")


    if file then
        local content = file:read("*all")
        file:close()
        -- Декодируем JSON
        passports = decodeJson(content) or {}
    else
        print("[ERROR] Файл не найден, создаю JSON")
        passports = {}
        saveData()
    end
end

function saveData()
    -- Кодируем в JSON и сохраняем
    local file = io.open(config, "w")
    if file then
        local content = encodeJson(passports)
        file:write(content)
        file:close()
    else
        print("[ERROR] Не удалось сохранить JSON-файл!")
    end
end

function sampev.onShowDialog(dialogId, style, title, btn1, btn2, text)
    if dialogId == 487 then
        local name = text:match("Имя:%s*(.-)\n") or "Неизвестно"
        local phone = text:match("Телефон:%s*(%d+)") or "Нет"
        local wanted = text:match("Уровень розыска:%s*(%d+)") or "0"
        local lawfulness = text:match("Законопослушность:%s*(%d+)") or "0"
        local level = text:match("Проживание в стране %(лет%): (%d+)") or "0"
       
        -- Создаем запись в базе
        passports[name] = {
            Name = name,
            lvl = level,
            Gender = text:match("Пол:%s*(.-)\n") or "Неизвестно",
            Status = text:match("Семейное положение:%s*(.-)\n") or "Неизвестно",
            Residence = text:match("Проживание:%s*(.-)\n") or "Неизвестно",
            Job = text:match("Работа:%s*(.-)\n") or "Неизвестно",
            Organization = text:match("Организация:%s*(.-)\n") or "Нет",
            Department = text:match("Подразделение:%s*(.-)\n") or "Нет",
            Phone = phone,
            Wanted = wanted,
            Lawfulness = lawfulness,
            LastUpdate = os.date("%d.%m.%Y %H:%M:%S") -- Добавляем дату последнего обновления
        }

        saveData()
        sampAddChatMessage("[DATABASE] Паспортные данные сохранены", -1)
    end
end

-- Функция поиска по базе
function searchInPassports(query)
    local results = {}
    query = query:lower()
    for name, data in pairs(passports) do
        if name:lower():find(query) or
           data.Phone:find(query) or
           data.Organization:lower():find(query) then
            results[name] = data
        end
    end
    return results
end

-- Буфер для поиска
local searchBuffer = imgui.new.char[256]()

imgui.OnFrame(function() return window[0] end, function()
    local X, Y = getScreenResolution()

    imgui.SetNextWindowSize(imgui.ImVec2(700, 500), imgui.Cond.FirstUseEver)
    imgui.SetNextWindowPos(imgui.ImVec2(X / 2 - 350, Y / 2 - 250), imgui.Cond.FirstUseEver)

    if imgui.Begin(u8'База паспортов', window) then
        -- Добавляем поиск
        if imgui.InputText(u8"Поиск", searchBuffer, ffi.sizeof(searchBuffer)) then
            -- Можно добавить мгновенный поиск при вводе
        end
       
        -- Кнопка поиска
        if imgui.Button(u8"Найти") then
            local query = ffi.string(searchBuffer)
            if query ~= "" then
                local results = searchInPassports(query)
                passports = results -- Временно показываем только результаты
                -- Можно добавить кнопку "Показать все"
            end
        end
       
        imgui.SameLine()
        if imgui.Button(u8"Показать все") then
            loadData() -- Перезагружаем все данные
        end
       
        imgui.Separator()

        -- Отображение данных
        for name, data in pairs(passports) do
            if imgui.CollapsingHeader(safeU8(data.Name)) then
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Основная информация:")
                imgui.Text(u8('Проживание в стране (лет): ') .. safeU8(data.lvl))
                imgui.Text(u8('Пол: ') .. safeU8(data.Gender))
                imgui.Text(u8('Семейное положение: ') .. safeU8(data.Status))
                imgui.Text(u8('Проживание: ') .. safeU8(data.Residence))
               
                imgui.Spacing()
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Работа:")
                imgui.Text(u8('Работа: ') .. safeU8(data.Job))
                imgui.Text(u8('Организация: ') .. safeU8(data.Organization))
                imgui.Text(u8('Подразделение: ') .. safeU8(data.Department))
               
                imgui.Spacing()
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Дополнительно:")
                imgui.Text(u8('Телефон: ') .. safeU8(data.Phone))
                imgui.Text(u8('Уровень розыска: ') .. safeU8(data.Wanted))
                imgui.Text(u8('Законопослушность: ') .. safeU8(data.Lawfulness))
               
                if data.LastUpdate then
                    imgui.TextColored(imgui.ImVec4(0.7, 0.7, 0.7, 1), u8"Последнее обновление: " .. safeU8(data.LastUpdate))
                end
               
                -- Добавляем кнопку удаления записи
                if imgui.Button(u8"Удалить запись##" .. name) then
                    passports[name] = nil
                    saveData()
                    sampAddChatMessage("[DATABASE] Запись удалена", -1)
                end
               
                imgui.Separator()
            end
        end
        imgui.End()
    end
end)
)

Автору бы желательно скинуть хотя бы скриншот диалога/полный его текст
дабы смогли помочь
Мгм:

Код:
[DialogInfo]: Dialog ID: 487
[DialogInfo]: Dialog Title: Паспорт Arseniy_Samsonov - 487
[DialogInfo]: Dialog text: Имя:                Arseniy_Samsonov
Проживание в стране (лет):    47
Пол:                Мужской
Семейное положение:        Женат на Maria_Samsonova
Проживание:            Средний класс (№331)
Работа:             Старший агент
Организация:            Министерство внутренних дел
Подразделение:        Федеральное бюро расследований
Телефон:            166
Уровень розыска:        0
Законопослушность:        100
[DialogInfo]: Dialog Style: 0
[DialogInfo]: Dialog Button1: Закрыть
[DialogInfo]: Dialog Button2:

Чтобы пофиксить "телефон" нужно заменить строку:

local phone = text:match("Телефон:%s*(%d+)") or "Нет" на: local phone = removeColorCodes(text:match("Телефон:%s*(.-)\n") or "Нет")
 
Последнее редактирование:

kyrtion

Известный
1,096
395
Оой... Что то я вообще. Конечно, вот:

Посмотреть вложение 263354

Чтобы пофиксить "телефон" нужно заменить строку:

local phone = text:match("Телефон:%s*(%d+)") or "Нет" на: local phone = removeColorCodes(text:match("Телефон:%s*(.-)\n") or "Нет")
В контент диалога всегда имеет значение {FFFFFF}, его убрать можно с помощью заменой на пустое значение:
text = text:gsub('{%x%x%x%x%x%x}', '')
 

kyrtion

Известный
1,096
395
можно просто text = text:gsub('{......}', '')
если в диалог окажет например, {хорошо}, заменит на пустой
"%x: соответствует любой шестнадцатеричной цифре."

1739091570248.png



Lua:
local dataPassport = {}

local regexPassport = {
    title = '^(Паспорт %S+ %- %d+)$',
    name = '^Имя:%s+(%S+)$',
    year = '^Проживание в стране %(лет%):%s+(%d+)$',
    gender = '^Пол:%s+(%S+)$',
    family = '^Семейное положение:%s+(.*)$',
    home = '^Проживание:%s+(.*)$',
    work = '^Работа:%s+(.*)$',
    org = '^Организация:%s+(.*)$',
    dep = '^Подразделение:%s+(.*)$',
    phone = '^Телефон:%s+(.*)$',
    suspect = '^Уровень розыска:%s+(%d+)$',
    respect = '^Законопослушность:%s+(-?%d+)$',
}

function sampev.onShowDialog(dialogId, style, title, b1, b2, text)
    title = title:gsub('{%x%x%x%x%x%x}', '')
    b1 = b1:gsub('{%x%x%x%x%x%x}', '')
    b2 = b2:gsub('{%x%x%x%x%x%x}', '')
    text = text:gsub('{%x%x%x%x%x%x}', '')

    if style == 0 and title:find(regexPassport.title) then
        for line in text:gmatch('[^\n]+') do
            for typ, regex in pairs(regexPassport) do
                if line:find(regex) then
                    dataPassport[typ] = line:match(regex)
                    break
                end
            end
        end
    end
end
 
Последнее редактирование:
  • Влюблен
Реакции: w99zzl1

w99zzl1

Участник
Автор темы
114
12
Вобщем, ребята, всем огромное спасибо! Без вас, я бы не справился. С горем пополам сделал адекватный код, которые передает все данные. Но были баги, вроде сами исчезли, если правильно пользоваться)) Поэтому, думаю правильным отправить сюда полный код и отметить решением именно его, (дабы другие пользователи могли видеть решение), из за чего такая дребедень, я так и не понял, если честно) постараюсь отметить каждую функцию с автором из этой темы. Ещё раз всем спасибо! Проблема - решена.
Код:
-- Структура кода Благодаря - https://www.blast.hk/members/474832/ (Поиск, удаление и время обновления)

require "lib.moonloader"

local imgui = require 'mimgui'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local json = require "dkjson"
local sampev = require "lib.samp.events"
local ffi = require 'ffi'

-- Путь к JSON файлу. Перешел на json исходя из совета - https://www.blast.hk/members/125042/
local config = getGameDirectory() .. "\\moonloader\\config\\passport_data.json"
local window = imgui.new.bool()
local passports = {}
local searchBuffer = imgui.new.char[256]()

-- Вспомогательная функция для безопасной конвертации в UTF-8
function safeU8(text)
    if text and text ~= "" then
        return u8(tostring(text))
    end
    return u8("Неизвестно")
end

function main()
    while not isSampAvailable() do wait(0) end

    sampRegisterChatCommand('database', function()
        window[0] = not window[0]
    end)

    loadData()
    while true do
        wait(0)
    end
end

function loadData()
    local file = io.open(config, "r")
    if file then
        local content = file:read("*all")
        file:close()
        passports = json.decode(content) or {}
    else
        print("[ERROR] Файл не найден, создаю JSON")
        passports = {}
        saveData()
    end
end

function saveData()
    local file = io.open(config, "w")
    if file then
        local content = json.encode(passports, { indent = true })
        file:write(content)
        file:close()
    else
        print("[ERROR] Не удалось сохранить JSON-файл!")
    end
end

local regexPassport = { -- Благодаря - https://www.blast.hk/members/125042/
    name = "Имя:%s*(.-)\n",
    phone = "Телефон:%s*(.-)\n",
    wanted = "Уровень розыска:%s*(%d+)",
    lawfulness = "Законопослушность:%s*(-?%d+)",
    level = "Проживание в стране %(лет%):%s*(%d+)",
    gender = "Пол:%s*(.-)\n",
    status = "Семейное положение:%s*(.-)\n",
    residence = "Проживание:%s*(.-)\n",
    job = "Работа:%s*(.-)\n",
    organization = "Организация:%s*(.-)\n",
    department = "Подразделение:%s*(.-)\n"
}

function sampev.onShowDialog(dialogId, style, title, btn1, btn2, text)
    if dialogId == 487 then
        text = text:gsub('{......}', '')
        local data = {}
        for key, pattern in pairs(regexPassport) do
            data[key] = text:match(pattern) or "Неизвестно"
        end
        passports[data.name] = data
        passports[data.name].LastUpdate = os.date("%d.%m.%Y %H:%M:%S")
        saveData()
        sampAddChatMessage("[DATABASE] Паспортные данные сохранены", -1)
    end
end

function searchInPassports(query)
    local results = {}
    query = query:lower()
    for name, data in pairs(passports) do
        if name:lower():find(query) or data.phone:find(query) or data.organization:lower():find(query) then
            results[name] = data
        end
    end
    return results
end

imgui.OnFrame(function() return window[0] end, function()
    local X, Y = getScreenResolution()

    imgui.SetNextWindowSize(imgui.ImVec2(700, 500), imgui.Cond.FirstUseEver)
    imgui.SetNextWindowPos(imgui.ImVec2(X / 2 - 350, Y / 2 - 250), imgui.Cond.FirstUseEver)

    if imgui.Begin(u8'База паспортов', window) then
        if imgui.InputText(u8"Поиск", searchBuffer, ffi.sizeof(searchBuffer)) then
        end

        if imgui.Button(u8"Найти") then
            local query = ffi.string(searchBuffer)
            if query ~= "" then
                passports = searchInPassports(query)
            end
        end
        imgui.SameLine()
        if imgui.Button(u8"Показать все") then
            loadData()
        end

        imgui.Separator()

        for name, data in pairs(passports) do
            if imgui.CollapsingHeader(safeU8(name)) then
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Основная информация:")
                imgui.Text(u8('Проживание в стране (лет): ') .. safeU8(data.level))
                imgui.Text(u8('Пол: ') .. safeU8(data.gender))
                imgui.Text(u8('Семейное положение: ') .. safeU8(data.status))
                imgui.Text(u8('Проживание: ') .. safeU8(data.residence))

                imgui.Spacing()
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Работа:")
                imgui.Text(u8('Работа: ') .. safeU8(data.job))
                imgui.Text(u8('Организация: ') .. safeU8(data.organization))
                imgui.Text(u8('Подразделение: ') .. safeU8(data.department))

                imgui.Spacing()
                imgui.TextColored(imgui.ImVec4(1, 1, 0, 1), u8"Дополнительно:")
                imgui.Text(u8('Телефон: ') .. safeU8(data.phone))
                imgui.Text(u8('Уровень розыска: ') .. safeU8(data.wanted))
                imgui.Text(u8('Законопослушность: ') .. safeU8(data.lawfulness))

                if data.LastUpdate then
                    imgui.TextColored(imgui.ImVec4(0.7, 0.7, 0.7, 1), u8"Последнее обновление: " .. safeU8(data.LastUpdate))
                end

                if imgui.Button(u8"Удалить запись##" .. name) then
                    passports[name] = nil
                    saveData()
                    sampAddChatMessage("[DATABASE] Запись удалена", -1)
                end

                imgui.Separator()
            end
        end
        imgui.End()
    end
end)
 
  • Нравится
Реакции: kyrtion

kyrtion

Известный
1,096
395
Вобщем, ребята, всем огромное спасибо! Без вас, я бы не справился. С горем пополам сделал адекватный код, которые передает все данные. Но были баги, вроде сами исчезли, если правильно пользоваться)) Поэтому, думаю правильным отправить сюда полный код и отметить решением именно его, (дабы другие пользователи могли видеть решение), из за чего такая дребедень, я так и не понял, если честно) постараюсь отметить каждую функцию с автором из этой темы. Ещё раз всем спасибо! Проблема - решена.
Ну и странный код у тебя получилось 😄
Вообще изначально показал как разбить по строкам (\n) и чекать, а затем уже внести в дата паспорт
 
  • Нравится
Реакции: w99zzl1