Файл бандла
Бандл це спосіб зберігання маніфесту: zip із фіксованою структурою. Ця сторінка описує цю структуру для всіх, хто читає або пише бандл без opys.
Про те, для чого бандл, дивіться Бандл.
Записи
| Запис | Містить |
|---|---|
opys.json | Заголовок: що бандл каже про себе. |
manifest.json | Маніфест, цілий. |
blobs/<sha256> | Один запис на перенесений файл. |
unzip -l game.opys
unzip -p game.opys opys.json
unzip -p game.opys manifest.json | jq '.launch'Чому два файли JSON: вони описують різні речі. Маніфест описує встановлення, він важить мегабайти, по одному запису на встановлений файл. Заголовок описує бандл, він малий. Він тримає format, locale і options.
Шукайте записи за ім'ям. Не покладайтеся на їхній порядок.
format
{ "format": 1 }Версія формату, у заголовку. Вона дорівнює 1.
Читач має:
- Читати
formatспочатку. - Відхилити бандл, якщо це не ціле
1. Відсутнє,"1"і1.0усе відхиляється. - Зробити це до читання
manifest.json.
Чому спочатку: інший формат може інакше писати маніфест. Читач, що вгадує, міг би встановити не те.
Читач ігнорує будь-яке інше поле заголовка.
Будь-яке інше число відхиляється, менше так само, як більше. opys читає один формат. Немає ні перенесення, ні режиму сумісності. Коли формат змінюється, бандл перезбирається з конфігурації командою opys build.
Для лаунчера це означає: оновіть рантайм і перевидайте бандли разом.
options
Що той, хто запускає бандл, може вибрати. Необов'язкове, у заголовку.
{
"format": 1,
"options": [
{
"slider": "xmx",
"title": "RAM",
"min": 1024,
"max": 16384,
"step": 512,
"default": 4096,
"unit": "MB"
},
{
"feature": "custom_java",
"title": "Custom Java",
"options": [{ "directory": "java_home", "title": "Java folder" }]
}
]
}Маніфест читає змінні й перевіряє прапорці. options каже, які з них гравець може задати і як питати кожне. Це лише схема: встановлювач її не читає, а вибране гравцем доходить до встановлення як прості vars і features.
Параметр налаштувань буває одного з шести видів. Поле, що називає вид, тримає й ім'я:
| Поле | Ім'я це | Значення це |
|---|---|---|
slider | змінна | число в діапазоні |
select | змінна | одне зі списку |
text | змінна | рядок тексту |
file | змінна | шлях файла |
directory | змінна | шлях теки |
feature | прапорець | ввімкнено чи вимкнено |
Кожен параметр має title і може мати subtitle. Решта залежить від виду:
| Вид | Обов'язкове | Необов'язкове |
|---|---|---|
slider | min, max, step, default | unit |
select | choices, default | |
text | placeholder, default | |
feature | default, options |
defaultце число на повзунку, рядок на виборі чи в тексті, і логічне значення на прапорці. Прапорець безdefaultвимкнений.choicesце список{ "value", "label" }, у порядку показу.optionsпрапорця це параметри, що важливі, лише поки він увімкнений. Вони самі можуть бути прапорцями, на будь-яку глибину.title,subtitle,unit,placeholderіlabelваріанта це текст, який можна перекласти: див. locale.
Читач відхиляє заголовок, чиї налаштування:
- не називають жодного виду або називають більше одного;
- несуть поле іншого виду, наприклад
minна виборі; - називають одну змінну двічі або один прапорець двічі будь-де в дереві;
- мають повзунок із
minне меншеmax,stepне більше нуля абоdefaultпоза діапазоном; - мають вибір, чий
defaultне єvalueодного з його варіантів; - мають текст, що порушує правила locale.
Чому в заголовку: лаунчер показує налаштування ще до будь-якого встановлення, а заголовок читається без маніфесту.
locale
Мова, якою написані налаштування. Необов'язкове, у заголовку.
{
"format": 1,
"locale": "en",
"options": [
{
"slider": "xmx",
"title": { "en": "RAM", "uk": "Пам'ять" },
"min": 1024,
"max": 16384,
"step": 512,
"default": 4096,
"unit": "MB"
}
]
}locale це мовний тег: мова з двох чи трьох літер, далі підтеги з одного до восьми літер чи цифр, через -. en, uk, pt-BR.
Кожен текст, який читає гравець, це або:
- рядок, мовою
localeзаголовка; або - об'єкт із мовного тегу в текст цією мовою.
Тексти це title, subtitle, unit, placeholder і label варіанта. Ім'я, value варіанта і default ніколи не перекладаються: їх читає маніфест.
Читач відхиляє заголовок:
- чий
localeне є мовним тегом; - з перекладеним текстом і без
locale; - з перекладеним текстом, що не містить
locale; - з перекладеним текстом, що порожній або має ключ, який не є мовним тегом.
Яку мову показати, вирішує читач. Знайдіть мову гравця, інакше візьміть locale. Перекладений текст завжди її містить, тож показати є що.
Чому поруч із текстом: текст читається там, де його показують. Немає таблиці ключів поруч із налаштуваннями, тож жоден ключ не вкаже в нікуди.
Блоби
Блоб це файл, перенесений у бандлі. Артефакт називає його за sha256 його вмісту:
{
"path": "${game_directory}/config/pack.toml",
"source": { "blob": "f727f7b2…" }
}Його байти це запис blobs/f727f7b2…. Id це 64 малі шістнадцяткові цифри.
Читач має:
- Відхилити бандл, що називає блоб, якого він не містить, до будь-якого встановлення.
- Перевірити кожен блоб за його ім'ям під час його встановлення.
Письменник не має зберігати байти під ім'ям, до якого вони не хешуються. Той самий блоб, використаний двома артефактами, зберігається один раз.
Що записує opys
Так поводиться еталонний письменник. Читач не має на це покладатися.
opys.jsonпершим і без стиснення, щоб читався з початку файла. Решта стиснена.- Блоби за порядком їхніх id.
- Фіксовані мітки часу, тож той самий маніфест завжди дає ті самі записи.
- Жодних інших записів. Читач ігнорує ті, яких не знає.
Читання
open the zip
head = json(entry "opys.json")
if head.format != 1: refuse
manifest = json(entry "manifest.json")
for each artifact with source.blob:
if no entry "blobs/" + id: refuseДалі, під час встановлення артефакту з блобом: скопіюйте запис у його path і відхиліть його, якщо його sha256 не є id.
Читачеві бандла за URL не обов'язково його завантажувати. Каталог zip лежить у його кінці й каже, де кожен запис, тож каталог, потім заголовок і маніфест, потім кожен блоб, якого бракує встановленню, можна запитати діапазоном. Кожен діапазон після першого запитуйте з If-Range і версією, яку назвала перша відповідь: так бандл, замінений тим часом, буде помічено, а не прочитано наполовину з кожного.
Ім'я файла
За домовленістю <name>.opys. Від нього в форматі нічого не залежить.