# ModLoaderVersionService `modloaderversionservice.h`, `modloaderversionservice.cpp` Списки версий Forge, Fabric, NeoForge и Quilt. Устроен так же, как [VersionManifestService](VersionManifestService.md): качает, хранит копию в `/cache/loader_<ключ>.json` и отвечает из неё, пока она моложе 6 часов. Совместимость с версией игры отдельно не проверяется: данные с самого начала разложены по версиям игры. Под версию, для которой сборок нет, лежит пустой список, и выбрать несовместимый модлоадер нечем. Экземпляр держит [LauncherBackend](LauncherBackend.md). [ModLoaderInstaller](ModLoaderInstaller.md) берёт отсюда ссылку на `installer.jar` через `find()`. ## Откуда берутся данные **Fabric и Quilt** спрашиваются отдельно под каждую версию игры: `meta.fabricmc.net/v2/versions/loader/<игра>` и `meta.quiltmc.org/v3/versions/loader/<игра>`. Признак стабильности берётся из ответа, а если его нет, угадывается по имени. **Forge** — один `maven-metadata.xml` на все версии игры. Строка `1.20.1-47.4.0` делится по первому дефису. Параллельно запрашивается `promotions_slim.json`, оттуда берутся отметки recommended. Если он не ответил, список всё равно сохраняется, только без отметок. **NeoForge** тоже из `maven-metadata.xml`, но версия игры в номере не записана. Её приходится выводить: `21.1.248` → `1.21.1`, `20.4.80` → `1.20.4`, `21.0.x` → `1.21`. Для четырёхчастных номеров вроде `25.1.0.1` правило другое: `25.1.0.1` → `25.1`. Вторым запросом читается старый репозиторий `net/neoforged/forge` с первыми сборками NeoForge под 1.20.1, которые выходили под именем артефакта `forge` и номерами в стиле Forge. Ссылка на установщик собирается по схеме maven: `<репозиторий>/<версия>/<артефакт>-<версия>-installer.jar`. Версии внутри каждой версии игры отсортированы от новых к старым. Числа сравниваются как числа, поэтому `47.10` новее `47.9`. ## ensureLoaded(loader, gameVersion, callback, forceRefresh) Логика та же, что у манифеста версий. Отличие в том, что свежесть у Fabric и Quilt считается для каждой версии игры отдельно, а у Forge и NeoForge для модлоадера целиком. По этому же ключу объединяются одновременные запросы. - Пустая `gameVersion` — сразу `ok` и пустой список. - При первом обращении к модлоадеру читается кэш, и если он есть, испускается `versionsChanged(key, gameVersion)`. - Если сеть не ответила, но какие-то данные по модлоадеру есть, колбэк получит `ok = true` и `warning`. - Если ответ не разобрался, хороший кэш не затирается. `versionsChanged(loaderKey, gameVersion)` испускается после каждого успешного обновления. `refreshingChanged()` — в начале и в конце запроса. `isRefreshing(loader, gameVersion)` отвечает, идёт ли запрос по этому ключу. ## Формат кэша ```json { "fetchedAt": "...", "games": { "1.20.1": { "fetchedAt": "...", "entries": [ { "loaderVersion": "47.4.0", ... } ] } } } ``` Верхний `fetchedAt` используется для Forge и NeoForge, `fetchedAt` внутри версии игры — для Fabric и Quilt. --- При создании этого документа использовался ИИ.