# Лаунчер Minecraft: Java edition
Є така гра, називається Minecraft.
Ця гра запускається через "лаунчер".
:::info
**launcher**: з англійської "to launch" --- запустити, наприклад, "to launch a rocket" --- запустити ракету.
**Запускатор**, **запускальщик** по нашому.
:::
Навіть якщо ви запускаєте гру даблкліком на робочому столі, це запускає лаунчер, з якого запускається сама гра.
Для скачування Майнкрафту (особливо якщо ми говоримо про Java edition) достатньо скачати лаунчер, а лаунчер зможе скачати саму гру і запустити її.
Окрім стандартного лаунчера, існує повно інших лаунчерів:
- MultiMC
- TLauncher
- GDLauncher
- ...
- кожен піратський сервер випускає свої лаунчери, які загружають свою "особливу" версію майкрафту, з фіксами, плагінами, патчами, модами, текстурпаками і тп.
Я якось написав свій лаунчер. І я хотів би щоб ви також зрозуміли як це робиться.
:::info
Якщо комусь цікаво подивитись мій код --- ось він:
- https://gist.github.com/danbst/a335b93f515606975bc1e6425ce9fecb
:::
## Технічні терміни
- **операційна система** (ОС), **платформа** --- Windows, Linux або MacOS.
- кросплатформернність --- підтримка кількох операційних систем. Як правило один і той же лаунчер файл не буде працювати на різних системах, тому потрібні платформо-специфічні версії
- **файл** --- дані на диску. Найважливішим є те, що ці дані мають ім'я ("шлях до файлу") і залишаються після того як комп'ютер вимикається. Ці дані можна дістати програмно, якщо знати шлях до файлу
- **папка**, **директорія** --- частина шляху до файлу до останнього слешу. Тобто, в шляху `C:\Users\test\somefile.exe` папкою буде `C:\Users\test\`
- **ресурси** --- файли для закачки. Файли можуть бути будь-які --- картинки, екзешники, аудіо, текстові, ...
- **ассети** --- список ресурсів, тобто, пакет файлів на закачку.
- **артефакт** (artifact) --- фактично те саме, що і ресурс, але з точки зору розробника. Також може бути архівом і містити додаткову інформацію --- час створення, хеш, і тп.
- **сервер ресурсів** --- сервер, з якого викачуються ресурси. Може співпадати з ігровим сервером, а може бути і стороннім. Якщо ресурс має хеш, то це дозволяє робити дзеркала серверів ресурсів
- дзеркало --- альтернативний сервер, копія в іншому місці
- **launcher** --- система, яка дозволяє запускати гру. Часто включає в себе докачку додаткових файлів (DLC), автентифікацію (логін-пароль) і верифікацію файлів гри (античіт)
- **клієнт** --- та частина гри, яка знаходиться на комп'ютерів гравця. Іноді є просто папкою з файлами десь на диску, тому її можна переносити по диску. Але часто деякі файли роблять зашивки на шляхи, і переносити з місця на місце стає неможливим.
- **версія** --- клієнт гри з іншим набором файлів та фіч. Якщо розробник додає нові фічі, то він називає їх новою версією, яку юзер може наново скачати
- альфа версія --- версія з новими фічами і не дуже відтестована
- бета версія --- версія з новими фічами і відтестована альфа-тестерами
- реліз кандидат --- версія, відтестована бета-тестерами
- реліз --- офіційний пакет гри, як правило це останній реліз-кандидат
- патч версія --- версія після релізної, де виправляють баги та хаки, які не відловили тестери, альфа-тестери, бета-тестери та реліз-кандидат тестери
- **параметри**, **аргументи** --- при запуску програми з командного рядка вказуються після назви програми. Дозволяють передавати в програму додаткові параметри (як це робить в функціях в Python).
- **сервер** --- код, який отримує запити з клієнтів і реалізує механіку мультиплеєра. Як правило знаходиться НЕ НА комп'ютері гравця, але для деяких ігор можна запускати сервер на своєму комп'ютері.
- **Java** --- мова програмування та крос-платформенна віртуальна машина.
- **ліби**, **бібліотеки** --- куски коду (скопмпільованого або некомпільованого), які розширують або спрощують роботу з мовою програмування. Можуть використовуватися як і при компіляції, так і при фінальному запуску програми.
- LWJGL --- бібліотека для Java для роботи з OpenGL (3D-графіка)
- **.jar** --- файловий формат для біблотеки в Java. Є ZIP-архівом, тобто, його можна розпакувати архіватором. Містить скомпільовані класи Java
- **Java аргументи** --- параметри запуску `java.exe`. Контролюють технічні нюанси, наприклад, кількість оперативної пам'яті та список біблотек для використання
- **classpath** --- список шляхів бібліотек Java. Розділювач крапка з комою (на відновсі) або двокрапка (на лінуксі і MacOS). https://en.wikipedia.org/wiki/Classpath
- **хеш** --- коротка послідовність символів, яка є "унікальною" для різних послдовностей даних. "Унікальною" в лапках, бо насправді існують два набори різних даних, які мають одинаковий хеш, але знайти такі пари майже нереально.
- **JSON** --- текстовий формат даних. Складається з словників, списків, рядків та чисел. Його можуть читати та створювати всі мови програмування, тому він використовується для обміну даними між різними середовищами, і особливо його любить інтернет
- **словник** --- структура даних, яка є набором пар "ключ-значення". Ключі в словнику завжди унікальні, значення можуть повторюватись.
- **індекс** --- (тут) документ, який вказує лінки на файли які треба скачувати. Тобто, містить не файли для закачки, а список лінків для закачки
- **парсинг** --- отримування структурної інформації з рядка. Наприклад, з рядків `"01.10.2021"` та `"2021-04-21"` (які є датами у різних форматах) дістати інформацію про "рік" можна тільки після парсингу
- **запит**, **реквест** (request) --- взаємодія з інтернет сервером. Може бути запит на закачку документу, може бути запит на викачку файлу.
## Маніфест версій
:::info
https://launchermeta.mojang.com/mc/game/version_manifest.json
:::
В цьому файлі знаходиться інформація про всі версії, які підтримуються для запуску стандартним лаунчером.
![](https://i.imgur.com/I1Hgeon.png)
Це файл у форматі JSON. Ключ `"latest"` вказує на останню версію клієнта, а ключ `"versions"` є списком всіх можливих версій Майкрафта.
Окрім снепшот версій є ще `release` версії:
![](https://i.imgur.com/uUE9iAV.png)
І є різні альфа і бета версії:
![](https://i.imgur.com/543rHDW.png)
:::info
**Завдання:** Написати код, який пише на екран дату релізу найпершої версії майнкрафту, використовуючи маніфест версій.
:::
:::info
**Завдання:** Написати код, який виводить на екран всі релізні версії майнкрафту.
:::
:::info
**Завдання:** Написати код, який порахує, скільки різних версій майнкрафту (релізних і нерелізних) було випущено в кожен з років 2009--2021.
:::
## Пакетний індекс
:::info
Адреса, яка знаходиться в `url` ключі версії з маніфесту версій. Наприклад,
https://launchermeta.mojang.com/v1/packages/dc5f9e134da9e18a2db42ddc246aba5cdfe28d3c/1.2.1.json
:::
Пакетний індекс містить багато інформації про файли (з яких складається клієнт) і додаткову інформацію про те, як робити запуск.
![](https://i.imgur.com/hZKeVQx.png)
- **assetIndex** вказує на список ассетів. Список ассетів знаходиться в іншому документі
- **downloads** вказує на основні файли для завантаження. Наприклад, основний файл для запуску клієнту. Файл є ресурсом, тому скачується з серверу ресурсів (про це пізніше)
- **libraries** вказує на додаткові бібліотеки для завантаження. Бібліотеки відповідають за 3Д графіку і інші системні задачі
- **mainClass** вказує який клас з `.jar` клієнту треба запускати (нюанси Java)
- **minecraftArguments** параметри запуску
- і всякі інші параметри, непотрібні для запуску гри
### Сторонні ліби
Окремо про бібліотеки в цьому документів. Інформація про лібу може бути "простою" (коли треба просто скачати і покласти в папку):
![](https://i.imgur.com/5vB5ju5.png)
А може бути складною.
:::info
В яку папку класти бібліотеку? В принципі, це неважливо, головне потім вказати правильний шлях до бібліотеки у class path аргументі лаунчера.
:::
#### Ліба для версії
Деякі ліби доступні тільки для певних версій. Наприклад, ця ліба потрібна для всіх версій MacOS **окрім** 10.5.x
![](https://i.imgur.com/a8ZsB3t.png)
А ось ця ліба потрібна **тільки** для MacOS версій 10.5.x
![](https://i.imgur.com/rvEJ47m.png)
Тобто, механізм "правил" ("rules") дозволяє для різних версій викачувати різні версії різних біблотек. Наприклад, в цьому випадку у MacOS 10.5.x був якийсь баг, через який бібліотека LWJGL не працювала як треба, тому довелось скачувати пропатчену версію.
#### Ліба для системи
Деякі бібліотеки потрібна тільки для однієї з ОС. У цьому випадку структура виглядає трошки складнішою, але все що воно робить, це вибирає яку бібліотеку на якій операційній системі скачувати.
![](https://i.imgur.com/gW9yrQ4.png)
:::info
**Завдання:** дістати список назв бібліотек (ключ `name`) з пакетного індексу.
:::
:::info
**Завдання:** скачати програмно будь-яку бібліотеку з цього списку. Лінк на закачку вказаний в ключі `url`.
Як скачувати файли через Python: https://www.tutorialspoint.com/downloading-files-from-web-using-python
:::
:::info
**Завдання:** для складних варіантів (де є ключ `downloads.natives`) потрібно скачати бібліотеку для правильної операційної системи (windows якщо у вас вінда, osx якщо MacOS).
:::
## Індекс ассетів
:::info
Він вказаний як лінк на ассети в пакетному індексі, наприклад:
https://launchermeta.mojang.com/v1/packages/4759bad2824e419da9db32861fcdc3a274336532/pre-1.6.json
:::
![](https://i.imgur.com/1Yu46AQ.png)
Формат цього файлу доволі простий: ключ `objects` є словник об'єктів, де ключем є шлях до файлу на клієнті (куди треба скачати), а значенням є пара (hash, size):
- **hash** вказує на хеш об'єкту, і по цьому хешу можна отримати лінк на закачку. Лінк будується так: `https://resources.download.minecraft.net/XX/YYYYYYYYYYYYYYYYYYYY`, де `XX` --- це перші два символи хешу, а `YYYYYYYYYYYYYYYYYYY` --- сам хеш.
- **size** --- розмір файлу для закачки. Це потрібно для плавного відображення прогрес-бару при закачці.
:::info
**Завдання**: Написати функцію, яка по хешу отримує лінк на закачку ресурса по правилу вище.
:::
:::info
**Завдання**: Написати функцію, яка отримує шлях до файлу, і створює всі папки які потрібно для того, щоб цей файл можна було скачати.
:::
:::info
**Завдання**: (якщо зробили попередні два) Написати функцію, яка по індексу ассетів викачає всі файли по черзі і збереже їх в правильну папку.
:::
:::info
**Завдання**: Написати функцію, яка по індексу ассетів порахує розмір всіх файлів для закачки і виведе на екран (в мегабайтах).
:::
:::info
**Завдання**: Написати функцію, яка отримує на вхід два лінки на два різних індекси ассетів і виводить
- скільки файлів ассетів є спільні для обох індексів
- розмір файлів даних для кожного індексу
- розмір даних для спільних асетів
- скільки байт можна зекономити на інтернет закачці другого індексу, якщо не скачувати файли які вже були скачані по першому індексу
:::