Заголовок: Расширенная библиотека для работы с JSON в Moonloader.
Установка: Переместить файл
jbp.lua
в moonlaoder/lib
Подключение:
local jbp = require 'jbp'
На данный момент реализовано:
decode(json_str)
- преобразует JSON строку в таблицу Luaencode(value, pretty, indent)
- преобразует Lua значение в JSON строкуcompress(json_str)
- минифицирует JSON строку, удаляя пробелыsanitize(value)
- очищает значение от недопустимых для JSON данныхvalidate(value, schema)
- проверяет JSON данные по заданной схемеpath_query(data, path)
- ищет значения по JSON Path выражениюpointer_set(data, path, value)
- устанавливает значение по указателюpointer_get(data, path)
- получает значение по JSON Pointerpatch(data, patch)
- применяет JSON Patch операции к даннымcreate(initial_data)
- создает новый построитель JSON объектов:set_pointer(path, ptr)
- сохраняет указатель в поле:get_pointer(path)
- получает указатель из поля:set(path, value)
- устанавливает значение по пути:get(path, default)
- получает значение по пути:merge(other)
- объединяет с другим JSON объектом:clone()
- создает копию объекта:keys()
- Возвращает массивы верхнего уровня:clear
- Очищает обьект:remove(path)
- Удаляет значение по указанному пути:to_json(pretty, indent)
- Конвертирует в JSON строку:validate(data, schema)
- Валидирует данные в обьекте по схеме:filter(keys)
- Фильтрует объект, оставляя только указанные ключи:flatten()
- Преобразует вложенный объект в плоский с точечной нотацией:diff(other)
- Сравнивает с другой таблицей или обьектом:watch(callback)
- Отслеживает изменения в объекте.from_json(json_string)
- Создает JsonBuilder из JSON строки:save_to_file(filename, pretty)
- сохраняет в файл.load_from_file(filename)
- загружает из файла- Работа с простыми указателями ffi
- Работа с cdata mimgui и userdata imgui
- Сохранение в Json происходит с форматированием. Ключи сортируются по степени важности.
1. API:
- Создание объекта
-
Lua:
-- Создание пустого объекта local jbp = require 'jbp' local empty = jbp.create() -- Создание с начальными данными local obj = jbp.create({ name = "John", age = 25, settings = { theme = "dark" } })
set(path, value)
- Установка значения-
Lua:
local user = jbp.create() -- Простая установка user:set("name", "John") -- {name = "John"} -- Вложенные объекты user:set("address.city", "Moscow") -- {name = "John", address = {city = "Moscow"}} -- Массивы user:set("scores[1]", 100) -- {name = "John", scores = {100}} user:set("items[2]", "Sword") -- {name = "John", items = {nil, "Sword"}} -- Цепочка вызовов user:set("level", 10) :set("health", 100) :set("mana", 50)
get(path, value)
- Получение значения-
Lua:
local user = jbp.create({ name = "John", stats = {health = 100}, inventory = {"Sword", "Shield"} }) print(user:get("name")) -- "John" print(user:get("stats.health")) -- 100 print(user:get("inventory[1]")) -- "Sword" print(user:get("missing", "N/A")) -- "N/A" (значение по умолчанию)
transform(fn)
- Преобразование значений-
Lua:
local stats = jbp.create({ health = 100, mana = 50, name = "Player", equipment = { weapon = {damage = 25}, armor = {defense = 15} } }) -- Умножаем все числа на 2 local doubled = stats:transform(function(v) return type(v) == "number" and v * 2 or v end) print(doubled:to_json(true)) -- Результат: { "health": 200, "mana": 100, "name": "Player", "equipment": { "weapon": { "damage": 50 }, "armor": { "defense": 30 } } }
flatten()
- Уплощение структуры-
Lua:
local nested = jbp.create({ user = { name = "John", address = { city = "Moscow", street = { name = "Lenin", number = 123 } } }, settings = { theme = { color = "dark", font = { size = 12, family = "Arial" } } } }) local flat = nested:flatten() print(flat:to_json(true)) -- Результат: { "user.name": "John", "user.address.city": "Moscow", "user.address.street.name": "Lenin", "user.address.street.number": 123, "settings.theme.color": "dark", "settings.theme.font.size": 12, "settings.theme.font.family": "Arial" }
filter(keys)
- Фильтрация данных-
Lua:
local user = jbp.create({ username = "john_doe", password = "secret123", email = "john@example.com", profile = { age = 25, avatar = "photo.jpg", private = { phone = "1234567890", notes = "personal info" } }, settings = { newsletter = true, theme = "dark" } }) -- Оставляем только публичные данные local public = user:filter({"username", "profile", "settings"}) print(public:to_json(true)) -- Результат: { "username": "john_doe", "profile": { "age": 25, "avatar": "photo.jpg" }, "settings": { "newsletter": true, "theme": "dark" } }
clear()
- Очистка всех данных-
Lua:
local data = jbp.create({ name = "John", age = 25, scores = {100, 200, 300} }) print(data:to_json()) -- Вывод: {"name":"John","age":25,"scores":[100,200,300]} data:clear() print(data:to_json()) -- Вывод: {}
clone()
- Создание глубокой копии-
Lua:
local original = jbp.create({ player = { stats = { health = 100, mana = 50 }, inventory = {"Sword", "Shield"} } }) local copy = original:clone() copy:set("player.stats.health", 80) copy:set("player.inventory[1]", "Axe") print("Original health:", original:get("player.stats.health")) -- 100 print("Copy health:", copy:get("player.stats.health")) -- 80 print("Original weapon:", original:get("player.inventory[1]")) -- "Sword" print("Copy weapon:", copy:get("player.inventory[1]")) -- "Axe"
merge(other)
- Объединение объектов-
Lua:
local base_config = jbp.create({ graphics = { quality = "medium", resolution = "1920x1080" }, audio = { volume = 80 } }) local user_config = { graphics = { quality = "high", vsync = true }, audio = { music = true } } base_config:merge(user_config) print(base_config:to_json(true)) -- Результат: { "graphics": { "quality": "high", "resolution": "1920x1080", "vsync": true }, "audio": { "volume": 80, "music": true } }
from_json(json_string)
- Создание из JSON строки-
Lua:
local json_str = [[ { "name": "John", "stats": { "level": 10, "experience": 1500 }, "achievements": ["Winner", "Explorer"] } ]] local obj, error = jbp.from_json(json_str) if obj then print("Name:", obj:get("name")) print("Level:", obj:get("stats.level")) print("First achievement:", obj:get("achievements[1]")) else print("Error:", error) end -- Вывод: -- Name: John -- Level: 10 -- First achievement: Winner
to_json(pretty, indent)
- Преобразование в JSON строку-
Lua:
local data = jbp.create({ player = { name = "Hero", stats = { level = 30, class = "Warrior" }, inventory = {"Sword", "Shield"} } }) -- Компактный вывод print(data:to_json()) -- Вывод: {"player":{"name":"Hero","stats":{"level":30,"class":"Warrior"},"inventory":["Sword","Shield"]}} -- Форматированный вывод print(data:to_json(true, 2)) -- Вывод: { "player": { "name": "Hero", "stats": { "level": 30, "class": "Warrior" }, "inventory": [ "Sword", "Shield" ] } }
remove(path)
- Удаление по пути-
Lua:
local data = jbp.create({ user = { name = "John", contacts = { email = "john@example.com", phone = "1234567890" }, settings = { theme = "dark", notifications = true } } }) -- Удаление отдельного поля data:remove("user.contacts.phone") -- Удаление вложенного объекта data:remove("user.settings") print(data:to_json(true)) -- Результат: { "user": { "name": "John", "contacts": { "email": "john@example.com" } } }
diff(other)
- Поиск различий-
Lua:
local config_v1 = jbp.create({ graphics = { quality = "high", resolution = "1920x1080", vsync = false }, audio = { volume = 80, music = true }, controls = { sensitivity = 1.0 } }) local config_v2 = jbp.create({ graphics = { quality = "ultra", resolution = "1920x1080", vsync = true }, audio = { volume = 90, music = false } }) local diff = config_v1:diff(config_v2) print(diff:to_json(true)) -- Результат: { "graphics.quality": { "old": "high", "new": "ultra", "status": "changed" }, "graphics.vsync": { "old": false, "new": true, "status": "changed" }, "audio.volume": { "old": 80, "new": 90, "status": "changed" }, "audio.music": { "old": true, "new": false, "status": "changed" }, "controls": { "old": { "sensitivity": 1.0 }, "new": null, "status": "removed" } }
watch(callback)
- Отслеживание изменений-
Lua:
local settings = jbp.create({ volume = 50, brightness = 0.8 }) settings:watch(function(change) print(string.format("Changed %s: %s -> %s at %s", change.key, tostring(change.old_value), tostring(change.new_value), os.date("%H:%M:%S", change.timestamp) )) end) settings.volume = 75 -- Вывод: Changed volume: 50 -> 75 at 14:30:45 settings.brightness = 1.0 -- Вывод: Changed brightness: 0.8 -> 1.0 at 14:30:46
validate(schema)
- Валидация по схеме-
Lua:
local player = jbp.create({ name = "John", level = 25, stats = { health = 100, mana = 50 }, inventory = ["Sword", "Shield"], settings = { difficulty = "hard" } }) local schema = { type = "object", properties = { name = {type = "string", required = true}, level = {type = "number", min = 1, max = 100}, stats = { type = "object", properties = { health = {type = "number", min = 0, max = 100}, mana = {type = "number", min = 0, max = 100} } }, inventory = {type = "array"}, settings = { type = "object", properties = { difficulty = {type = "string", enum = {"easy", "normal", "hard"}} } } } } local valid, error = player:validate(schema) print(valid and "Valid" or error) -- Вывод: Valid -- Пример с ошибкой player:set("level", 150) valid, error = player:validate(schema) print(error) -- Вывод: Value 150 greater than maximum 100
save_to_file(filepath, pretty, indent)
- Сохранение с форматированием и без.-
Lua:
local game_state = jbp.create({ player = { name = "Hero", level = 30, inventory = {"Sword", "Shield", "Potion"}, position = {x = 100, y = 200, z = 300} }, world = { time = "day", weather = "sunny", enemies = 10 } }) -- Сохранение с форматированием ---@param filepath string Путь к файлу ---@param pretty boolean|nil Форматировать ли вывод ---@param indent number|nil Размер отступа при форматиров ---@return boolean success Успешно ли сохранение ---@return string|nil error Текст ошибки в случае неудачи game_state:save_to_file("save.json", true, 2) -- Результат в файле save.json: { "player": { "name": "Hero", "level": 30, "inventory": [ "Sword", "Shield", "Potion" ], "position": { "x": 100, "y": 200, "z": 300 } }, "world": { "time": "day", "weather": "sunny", "enemies": 10 } }
load_from_file(filepath)
- Загрузка json из файла-
Lua:
local loaded = jbp.load_from_file("save.json") if loaded then print("Player name:", loaded:get("player.name")) print("World time:", loaded:get("world.time")) end
В этом спойлере описаны методы и примеры которые позволяют работать с любыми таблицами и строками json в луа. При этом, нет зависимости от создания новой таблицы через библиотеку, для использования вложенных методов, по типу table:method* table:get:set.
Новый подход с JBP:
1. Прямая работа с JSON
Традиционный подход:
Код:
local t = {}
local success = t:decode(json_string)
if not success then
print("Ошибка")
end
Lua:
local data, err = jbp.decode(json_string)
if data then
print("name:", data.name)
else
print("error:", err) -- Подробное описание ошибки
end
- Явное возвращение ошибки
- Нет необходимости создавать временную таблицу
- Более информативные сообщения об ошибках
2. JSON Path Query
JSONPath - это способ находить нужные данные в JSON файле, как будто вы ищете файл в папках на компьютере.
Lua:
-- Структура данных
local data = {
store = {
books = {
{
title = "Война и мир",
price = 1000,
categories = {"классика", "роман"}
},
{
title = "Мастер и Маргарита",
price = 800,
categories = {"фэнтези", "классика"}
}
}
}
}
-- Получение всех цен
local prices = jbp.path_query(data, "$.store.books[*].price")
-- Результат: [1000, 800]
-- Получение всех книг в категории "классика"
local classics = jbp.path_query(data, "$.store.books[*]")
- Декларативный синтаксис
- Меньше кода
- Меньше вложенных циклов
- Защита от nil
3. Валидация по схеме
Валидирует данные в массиве. К примеру если age больше 150, выдаст ошибку с указанием на позицию в таблице. Этот способ так-же есть для обьекта jbp
Lua:
local schema = {
type = "object",
properties = {
name = {type = "string", required = true},
age = {type = "number", min = 0, max = 150},
email = {type = "string", pattern = "^[%w.]+@[%w.]+$"}
}
}
local user = {
name = "Иван",
age = 25,
email = "ivan@mail.com"
}
local is_valid, err = jbp.validate(user, schema)
- Декларативное описание схемы
- Автоматическая проверка всех правил
- Подробные сообщения об ошибках
- Вложенная валидация объектов
4. JSON Pointer
JSON Pointer - это более простой способ указать путь к данным в JSON. Он похож на путь к файлу, только использует "/" для разделения.
Lua:
local data = {
users = {
{
name = "Иван",
contacts = {
email = "ivan@mail.com"
}
}
}
}
-- Получение email первого пользователя
local email = jbp.pointer_get(data, "/users/0/contacts/email")
Lua:
{
"магазин": {
"книги": [
{"название": "Гарри Поттер", "цена": 1000},
{"название": "Властелин колец", "цена": 800}
]
}
}
/магазин/книги/0/название - получить название первой книги
/магазин/книги/1/цена - получить цену второй книги
5. JSON Patch
JSON Patch - Это как список инструкций "что и где изменить".
Lua:
local user = {
name = "Иван",
age = 25
}
local patch = {
{op = "replace", path = "/age", value = 26},
{op = "add", path = "/city", value = "Москва"}
}
local updated = jbp.patch(user, patch)
- Каждое изменение описывается операцией (op):
- add - "добавить поле city со значением Москва"
- replace - "заменить age на 26"
- remove - "удалить поле old_field"
- copy - "скопировать значение из name в username"
- Путь (path) указывает, где делать изменение:
- /age - изменить поле age в корне
- /user/name - изменить name внутри объекта user
- /items/0 - изменить первый элемент массива items
6. Санитизация данных
Это процесс очистки данных JSON от вредоносных или нежелательных элементов
Lua:
local dirty_data = {
inf = math.huge,
nan = 0/0,
func = function() end,
valid = "это останется",
nested = {
bad = math.huge,
good = 42
}
}
local clean = jbp.sanitize(dirty_data)
- Автоматическая очистка недопустимых значений
- Рекурсивная обработка вложенных таблиц
- Сохранение структуры данных
Почему иногда : перед функцией, а иногда .
: Используется для вложенных методов для обьекта jbp.
. Используется для любых таблиц и строк.
Создание и загрузка
Трансформации
Валидация и сравнение
Сериализация
Кодирование и декодирование
Навигация по данным
Внимание, для сериализации cdata откройте спойлер "Работа с cdata".
: Используется для вложенных методов для обьекта jbp.
Lua:
local basic = jbp.create()
basic:set("name", "John")
basic:set("age", 25)
basic:set("items", {1, 2, 3})
basic:save_to_file("data.json")
Lua:
local pretty_json = [[
{
"name": "John",
"age": 30,
"city": "New York"
}
]]
local compressed = jbp.compress(pretty_json)
Создание и загрузка
:create(initial_data) | Создает новый JSON объект с опциональными начальными данными @param initial_data table|nil Начальные данные для JSON объекта @return table JsonBuilder объект с методами для работы с JSON |
.from_json(json_string) | Создает объект из JSON строки @param json_string string JSON строка @return table|nil builder JsonBuilder объект или nil при ошибке @return string|nil error Текст ошибки в случае неудачи |
.load_from_file(filepath) | Загружает JSON объект из файла @param filepath string Путь к файлу @return table|nil builder JsonBuilder объект или nil при ошибке @return string|nil error Текст ошибки в случае неудачи |
Получение и установка значений:set(path, value) | Устанавливает значение по указанному пути (поддерживает вложенные пути) @param path string Путь к значению (например "user.name" или "items[1]") @param value any Значение для установки @return table self Текущий объект для цепочки вызовов |
:get(path, default) | Получает значение по пути, возвращает default если путь не найден @param path string Путь к значению @param default any Значение по умолчанию, если путь не найден @return any value Найденное значение или default |
:exists(path) | Проверяет существование значения по указанному пути @param path string Путь для проверки @return boolean exists Существует ли значение |
:remove(path) | Удаляет значение по указанному пути @param path string Путь к удаляемому значению @return table self Текущий объект для цепочки вызовов |
:clear() | Очищает все данные объекта @return table self Текущий объект для цепочки вызовов |
:clone() | Создает глубокую копию объекта @return table copy Копия текущего объекта |
:merge(other) | Объединяет текущий объект с другим @param other table Таблица для объединения @return table self Текущий объект для цепочки вызовов |
:keys() | Возвращает массив ключей верхнего уровня @return table keys Массив ключей |
Трансформации
:transform(fn) | Применяет функцию преобразования ко всем значениям @param fn function Функция для преобразования значений @return table transformed Преобразованный объект |
:filter(keys) | Создает новый объект только с указанными ключами @param keys table Массив ключей для сохранения @return table filtered Отфильтрованный объект |
:flatten() | Преобразует вложенный объект в плоскую структуру с точечной нотацией @return table flattened Уплощенный объект |
.compress | Производит сжатие таблицы @param json_str string JSON строка для минификации @return string|nil minified Минифицированная строка или nil при ошибке @return string|nil error Текст ошибки в случае неудачи |
.sanitize(value) | Очищает значение от недопустимых для JSON значений @param value any Значение для очистки @return any sanitized Очищенное значение |
.path(data, path) | Применяет операции JSON Patch (RFC 6902) @param data table Данные для изменения @param patch table Массив операций patch @return table|nil result Измененные данные или nil при ошибке @return string|nil error Текст ошибки в случае неудачи |
Валидация и сравнение
:validate(schema) | Проверяет объект на соответствие схеме @param value any Данные для валидации @param schema table Схема для валидации @return boolean valid Валидны ли данные @return string|nil error Сообщение об ошибке если не валидны |
:diff(other) | Находит различия между текущим и другим объектом @param other table Объект для сравнения @return table diff Объект с различиями |
:watch(callback) | Отслеживает изменения в объекте через callback @param callback function Функция вызываемая при изменениях |
Сериализация
:to_json(pretty, indent) | Преобразует объект в JSON строку с опциональным форматированием @param pretty boolean|nil Форматировать ли вывод @param indent number|nil Размер отступа при форматировании @return string json_string JSON представление объекта |
:save_to_file(filepath, pretty, indent) | Сохраняет объект в файл в формате JSON @param filepath string Путь к файлу @param pretty boolean|nil Форматировать ли вывод @param indent number|nil Размер отступа при форматировании @return boolean success Успешно ли сохранение @return string|nil error Текст ошибки в случае неудачи |
Кодирование и декодирование
.encode(data, format: bool) | Кодирование, стандартная функция. True False для форматирования. |
.decode(data) | Декодирование, стандартная функция |
Навигация по данным
.path_query(data, path) | Поиск по выражению @param data table Данные для поиска @param path string JSON Path выражение (например: $.store.book[*].author) @return table|nil result Найденные значения или nil при ошибке @return string|nil error Текст ошибки в случае неудачи |
.pointer_get(data, pointer) | Получить конкретные данные @param data table Данные для поиска @param pointer string JSON Pointer (например: /store/book/0/author) @return any|nil value Найденное значение или nil если не найдено @return string|nil error Текст ошибки в случае неудачи |
1. Почему нужен специальный подход:
5. Как выглядит сохраненный файл:
- JSON не может хранить cdata типы
- Нужно сохранять и тип, и значение указателя
- При загрузке нужно восстанавливать оригинальный тип
-
Lua:
-- Сохранение basic:set_pointer("car", vehicle) -- vehicle это cdata -- Загрузка local car = loaded:get_pointer("car") -- получаем с оригинальным типом
- Указатели работают только в текущей сессии*
- После перезапуска игры нужно получать новые указатели
- Нельзя использовать сохраненные указатели между сессиями
Lua:
local jbp = require 'jbp'
local ffi = require 'ffi'
local samem = require "SAMemory"
samem.require "CAutomobile"
function main()
if not isSampLoaded() or not isSampfuncsLoaded() then return end
while not isSampAvailable() do wait(100) end
local basic = jbp.create()
-- Сохранение машины
if isCharInAnyCar(playerPed) then
local car = storeCarCharIsInNoSave(playerPed)
if car then
local CarPointer = getCarPointer(car)
if CarPointer ~= 0 then
local vehicle = ffi.cast("CAutomobile*", CarPointer)
basic:set_pointer("vehicle", vehicle)
basic:save_to_file("moonloader/config/save.json", true, 2)
print("Saved")
end
end
end
-- Загрузка и тест
wait(100)
local loaded = jbp.load_from_file("moonloader/config/save.json")
if loaded then
local vehicle = loaded:get_pointer("vehicle")
if vehicle then
vehicle.wheelOffsetZ[0] = 0.5
vehicle.wheelOffsetZ[1] = 0.5
vehicle.wheelOffsetZ[2] = 0.5
vehicle.wheelOffsetZ[3] = 0.5
print("Modified wheels")
end
end
while true do
wait(0)
end
end
-
JSON:
{ "vehicle":{ "type":"ctype<struct CAutomobile *>", "pointer":480169768 } }
-- Поддерживаемые типы Imgui
Пример работы с Imgui:
- ImBool - Булево значение
- ImInt - Целое число
- ImFloat - Число с плавающей точкой
- ImBuffer - Текстовый буфер
- ImVec2 - 2D вектор (x, y)
- ImVec4 - 4D вектор (x, y, z, w)
Lua:
local config = jbp.create()
-- Для стандартного ImGui
jbp.pointer_set(config, "Imgui/Window/visible", imgui_default.ImBool(false))
--Сохраняем в конфиг
config:save_to_file("moonloader/config/test.json", true, 2)
-- Загружаем конфиг
local loaded = jbp.load_from_file("moonloader/config/test.json")
--Через .pointer_get:
if jbp.pointer_get(loaded, "Imgui/Window/visible").v == false then
print("Visible Pointer = false")
end
--Через стандартный :get
if loaded:get('Imgui.Window.visible').v == false then
print("Visible get = false")
end
Lua:
local imgui = require 'imgui'
local jbp = require 'jbp'
local data = jbp.create()
-- Сохранение
--Можно использовать как :set, так и jbp.pointer_set(data, "/checkbox", imgui.ImBool(true))
data:set("checkbox", imgui.ImBool(true))
data:set("slider", imgui.ImInt(50))
data:set("input", imgui.ImBuffer(256, "Текст"))
data:set("position", imgui.ImVec2(100, 100))
data:set("color", imgui.ImVec4(1, 0, 0, 1))
data:save_to_file("moonloader/config/test.json", true, 2) -- True включить форматирование, 2 - размер отступа
-- Загрузка
local data = jbp.load_from_file("moonloader/config/test.json")
--Так-же можно использовать jbp.pointer_get(data, '/checkbox')
local checkbox = data:get("checkbox") -- imgui.ImBool
local slider = data:get("slider") -- imgui.ImInt
local input = data:get("input") -- imgui.ImBuffer
local pos = data:get("position") -- imgui.ImVec2
local color = data:get("color") -- imgui.ImVec4
Поддерживаемые типы Mimgui:
- bool[1] - Булево значение
- int[1] - Целое число
- float[1] - Число с плавающей точкой
- char[] - Текстовый буфер
- ImVec2 - 2D вектор
- ImVec4 - 4D вектор
Lua:
local jbp = require 'jbp'
local imgui = require 'mimgui'
local config = jbp.create()
local config = jbp.create()
-- pointer_set
jbp.pointer_set(config, "Mimgui/Window/visible", new.bool(true))
jbp.pointer_set(config, "Mimgui/Window/position", imgui.ImVec2(100, 100))
jbp.pointer_set(config, "Mimgui/Window/vectors/vector4D", imgui.ImVec4(100, 100, 100, 100))
jbp.pointer_set(config, "Mimgui/Window/input_text", new.char[256]('hello world'))
--Или стандартное set
config:set("Mimgui.Bools.Visible", new.bool(true))
config:set("Mimgui.Ints.SelectedTab", new.int(0))
config:set("Mimgui.Window.position", imgui.ImVec2(100, 100))
config:set("Mimgui.Window.vectors/vector4D", imgui.ImVec4(100, 100, 100, 100))
config:set("Mimgui.Window.Chars.input_text", new.char[256]('hello world'))
--Сохраняем в файл
config:save_to_file("moonloader/config/test.json", true, 2)
-- Загружаем конфиг
local loaded = jbp.load_from_file("moonloader/config/test.json")
--Дальнейшие манипуляции, как с обычными обьектами mimgui
if jbp.pointer_get(loaded, "Mimgui/Window/visible")[0] == true then
print("Visible Pointer = true")
end
-- Для получения значения из буфера MImGui
local buffer = jbp.pointer_get(loaded, "Mimgui/Window/input_text")
if buffer then
local text = ffi.string(buffer) -- Получаем строку из буфера
print("Buffer text:", text)
end
--Через стандартный :get
if loaded:get('Mimgui.Window.visible')[0] == true then
print("Visible get = true")
end
Через присваивание переменной, а затем её использование:
--Для мимгуи:
local VisibleMimgui = loaded:get("Mimgui.Window.visible")[0];
JSON:
{
"Imgui":{
"Bools":{
"ClosedMenu":{
"__type":"imgui_bool",
"value":false
}
},
"Buffers":{
"InputText":{
"__type":"imgui_buffer",
"value":"hello world"
}
},
"Ints":{
"SelectedTab":{
"__type":"imgui_int",
"value":0
}
},
"Window":{
"input_text":{
"__type":"imgui_buffer",
"value":"hello world"
},
"position":{
"__type":"imgui_vec2",
"x":0,
"y":0
},
"size":{
"__type":"imgui_vec2",
"x":800,
"y":600
},
"visible":{
"__type":"imgui_bool",
"value":false
}
}
},
"Mimgui":{
"Bools":{
"Visible":{
"__type":"bool",
"value":true
}
},
"Ints":{
"SelectedTab":{
"__type":"int",
"value":0
}
},
"Strs":{
"InputText":{
"__type":"mimgui_buffer",
"value":"hello world"
}
},
"Window":{
"input_text":{
"__type":"mimgui_buffer",
"value":"hello world"
},
"position":{
"__type":"vec2",
"x":100,
"y":100
},
"visible":{
"__type":"bool",
"value":true
},
"vectors":{
"vector4D":{
"__type":"vec4",
"x":100,
"y":100,
"z":100,
"w":100
}
}
}
}
}
Пример 1: Работа с API
Lua:
-- Получение данных из API
local response = [[{"users":[{"id":1,"name":"Иван"},{"id":2,"name":"Мария"}]}]]
-- Декодирование и валидация
local data = jbp.decode(response)
local users = jbp.path_query(data, "$.users[*].name")
print("users:", table.concat(users, ", "))
Пример 2: Сохранение конфигурации
Lua:
local config = {
window = {
width = 800,
height = 600,
position = {x = 100, y = 100}
},
settings = {
volume = 0.8,
fullscreen = true
}
}
-- Сохранение с форматированием
local success = jbp.encode(config, true, 2)
-- Загрузка отдельных настроек
local volume = jbp.pointer_get(config, "/settings/volume")
Пример 3: Обновление данных
Lua:
local user_data = {
name = "Иван",
settings = {
notifications = true,
theme = "dark"
}
}
-- Применение нескольких изменений
local patches = {
{op = "replace", path = "/settings/theme", value = "light"},
{op = "add", path = "/settings/language", value = "ru"}
}
local updated = jbp.patch(user_data, patches)
Пример 4: Поиск похожих значений
Lua:
local data = {
["Иван Петров"] = "программист",
["Петр Иванов"] = "дизайнер",
["Иван Сидоров"] = "менеджер",
["Сидор Иванов"] = "программист"
}
-- Функция поиска похожих значений
function find_similar(query, data, by_key)
local results = {}
query = query:lower() -- приводим к нижнему регистру для поиска
for k, v in pairs(data) do
local search_text = by_key and k or v
search_text = tostring(search_text):lower()
if search_text:find(query) then
table.insert(results, {key = k, value = v})
end
end
return results
end
-- Пример использования
local query = "иван"
local results = find_similar(query, data, true) -- поиск по ключам
-- Результат:
-- {
-- {key = "Иван Петров", value = "программист"},
-- {key = "Иван Сидоров", value = "менеджер"}
-- }
-- Поиск по значению
local prof_query = "прог"
local prof_results = find_similar(prof_query, data, false)
-- Результат:
-- {
-- {key = "Иван Петров", value = "программист"},
-- {key = "Сидор Иванов", value = "программист"}
-- }
Пример 5: Сжатие
Lua:
local pretty_json = [[
{
"name": "John",
"age": 30,
"city": "New York"
}
]]
local compressed = jbp.compress(pretty_json)
print("Original size:", #pretty_json)
print("Compressed size:", #compressed)
print("Compressed JSON:", compressed)
Продвинутый поиск с расстоянием Левенштейна
Lua:
-- Функция расчета расстояния Левенштейна
function levenshtein_distance(str1, str2)
str1, str2 = str1:lower(), str2:lower()
local len1, len2 = #str1, #str2
local matrix = {}
for i = 0, len1 do
matrix[i] = {[0] = i}
end
for j = 0, len2 do
matrix[0][j] = j
end
for i = 1, len1 do
for j = 1, len2 do
local cost = str1:sub(i,i) == str2:sub(j,j) and 0 or 1
matrix[i][j] = math.min(
matrix[i-1][j] + 1, -- удаление
matrix[i][j-1] + 1, -- вставка
matrix[i-1][j-1] + cost -- замена
)
end
end
return matrix[len1][len2]
end
-- Функция поиска похожих значений с учетом расстояния Левенштейна
function find_similar_advanced(query, data, max_distance)
local results = {}
query = query:lower()
max_distance = max_distance or 3 -- максимальное допустимое расстояние
for k, v in pairs(data) do
local key_distance = levenshtein_distance(query, k)
local value_distance = levenshtein_distance(query, tostring(v))
if key_distance <= max_distance or value_distance <= max_distance then
table.insert(results, {
key = k,
value = v,
key_relevance = 1 - (key_distance / #query),
value_relevance = 1 - (value_distance / #query)
})
end
end
-- Сортировка по релевантности
table.sort(results, function(a, b)
return math.max(a.key_relevance, a.value_relevance) >
math.max(b.key_relevance, b.value_relevance)
end)
return results
end
-- Пример использования продвинутого поиска
local database = {
["Иван Петров"] = "программист",
["Петр Иванов"] = "дизайнер",
["Иван Сидоров"] = "менеджер",
["Сидор Иванов"] = "программист",
["Иван Иванов"] = "аналитик"
}
-- Поиск с опечаткой
local query = "Иван Петроф" -- опечатка в фамилии
local results = find_similar_advanced(query, database)
-- Вывод результатов с релевантностью
for i, result in ipairs(results) do
print(string.format(
"%s (%s) - релевантность: %.2f",
result.key,
result.value,
math.max(result.key_relevance, result.value_relevance)
))
end
Поиск с учетом категорий
Lua:
local categorized_data = {
programmers = {
["Иван Петров"] = {
position = "Senior Developer",
skills = {"Lua", "Python", "C++"}
},
["Петр Иванов"] = {
position = "Junior Developer",
skills = {"Lua", "JavaScript"}
}
},
designers = {
["Анна Сидорова"] = {
position = "UI Designer",
skills = {"Figma", "Photoshop"}
}
}
}
-- Функция поиска по категориям
function search_in_categories(query, data, category)
local results = {}
query = query:lower()
local function search_category(cat_data, cat_name)
for name, info in pairs(cat_data) do
if name:lower():find(query) then
table.insert(results, {
name = name,
category = cat_name,
info = info
})
else
-- Поиск по навыкам
for _, skill in ipairs(info.skills) do
if skill:lower():find(query) then
table.insert(results, {
name = name,
category = cat_name,
info = info,
matched_skill = skill
})
break
end
end
end
end
end
if category then
if data[category] then
search_category(data[category], category)
end
else
for cat_name, cat_data in pairs(data) do
search_category(cat_data, cat_name)
end
end
return results
end
-- Примеры использования
-- Поиск по всем категориям
local results1 = search_in_categories("lua", categorized_data)
-- Найдет всех, кто знает Lua
-- Поиск только среди программистов
local results2 = search_in_categories("junior", categorized_data, "programmers")
-- Найдет только Junior Developer
-- Вывод результатов
for _, result in ipairs(results1) do
print(string.format(
"%s (%s) - %s",
result.name,
result.category,
result.info.position
))
if result.matched_skill then
print("Найдено по навыку:", result.matched_skill)
end
end
Рекомендации по использованию:
- Выбор метода доступа к данным:
- Используйте path_query для сложных запросов и массивов
- Используйте pointer_get для прямого доступа к известным путям
- Используйте стандартный доступ для простых операций
- Используйте сжатие для больших JSON
- Избегайте излишней валидации для доверенных данных
- Используйте схемы для критичных данных
- Применяйте санитизацию для пользовательского ввода
1. Подключение библиотеки
Lua:
local jbp = require 'jbp'
2. Создание и сохранение данных
Lua:
-- Создаем новый объект
local config = jbp.create()
-- Сохраняем простые значения
config:set("name", "John")
config:set("health", 100)
config:set("weapons", {"Desert Eagle", "M4"})
-- Сохраняем вложенные данные
config:set("stats.strength", 80)
config:set("stats.agility", 75)
-- Сохраняем в файл
config:save_to_file("moonloader/config/my_config.json", true, 2)
3. Загрузка и использование данных
Lua:
-- Загружаем файл
local data = jbp.load_from_file("moonloader/config/my_config.json")
if data then
-- Получаем значения
local name = data:get("name") -- "John"
local strength = data:get("stats.strength") -- 80
local weapons = data:get("weapons") -- {"Desert Eagle", "M4"}
end
Разное:
Lua:
-- Создание с начальными данными
local profile = jbp.create({
name = "John",
level = 1,
inventory = {"Pistol"}
})
Lua:
-- Значение по умолчанию
local money = profile:get("money", 0) -- Вернёт 0 если money не найден
Lua:
-- Проверка существования
if profile:get("weapon.ammo") then
-- Значение существует
end
1. Установка библиотеки
Lua:
-- Скачайте файл jbp.lua и поместите его в папку moonloader/lib
-- В начале скрипта подключите библиотеку:
local jbp = require 'jbp'
2. Создание простого конфига
Lua:
-- Создаем новый конфиг
local config = jbp.create()
-- Добавляем настройки
config:set("name", "Мой скрипт")
config:set("version", 1.0)
config:set("settings.enabled", true)
config:set("settings.hotkey", 0x42) -- клавиша B
-- Сохраняем в файл
config:save_to_file("moonloader/config/myscript.json")
3. Загрузка конфига
Lua:
-- Создаем конфиг и загружаем из файла
local loaded = jbp.load_from_file("moonloader/config/myscript.json")
if not loaded then
-- Если файл не существует, создаем стандартные настройки
config:set("name", "Мой скрипт")
config:set("version", 1.0)
config:set("settings.enabled", true)
config:set("settings.hotkey", 0x42)
-- Сохраняем стандартные настройки
config:save_to_file("moonloader/config/myscript.json")
end
4. Различные функции
Lua:
-- Создание вложенных настроек
config:set("players.max", 50)
config:set("players.list[1].name", "Player1")
config:set("players.list[1].score", 100)
config:set("players.list[2].name", "Player2")
config:set("players.list[2].score", 200)
-- Получение значений
local maxPlayers = config:get("players.max") -- 50
local player1Name = config:get("players.list[1].name") -- "Player1"
-- Работа с массивами
local weapons = {0x1, 0x2, 0x3, 0x4}
config:set("weapons", weapons)
-- Слияние конфигов
local otherConfig = jbp.create({
newSetting = true,
extraValue = 123
})
config:merge(otherConfig)
-- Клонирование конфига
local configBackup = config:clone()
Внутри библиотеки используется стандартная
cjson
для базовых функций.Прикрепил файл
test_lua.lua
с примерами работы с библиотекой.Прикрепил файл
gui_examples.lua
с примерами Imgui и Mimgui используя данную библиотеку.Обновлено: 09.01.2025 18:36
09.01.2025. 01:06: .sanitize, .decode, .encode, .compress, .validate, .path_query, .pointer_get, .path
09.01.2025. 18:36: Работа с cdata mimgui, userdata imgui
Вложения
Последнее редактирование: