diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..1b9f3199 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: ['luuxis'] \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..8c9d5677 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,71 @@ +name: Signaler un bug +description: Vous avez rencontré un bug? Signalez-le ici +title: "[Bug] " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Un grand merci d'avance pour votre aide. Néanmoins, nous avons besoin d'un certain nombre d'informations, pour nous aider. + - type: checkboxes + attributes: + label: "Liste des vérifications à faire avant de valider l'ouverture du signalement de bug" + description: Assurez que vous avez complété ce qui suit, dans le cas contraire, votre rapport peut être refusé + options: + - label: J'ai réussi à reproduire le bug sur le Selvania Launcher (sans mes modifications) + required: true + - label: Mon code respecte la licence Creative Commons Zero v1.0 Universal + required: true + - label: Mon code respecte les conditions d'utilisation du Selvania Launcher + required: true + - label: J'arrive à reproduire le bug sur la dernière version du Selvania Launcher + required: true + - type: dropdown + attributes: + label: Système d'exploitation + options: + - Windows + - macOS + - Linux (Basé sur Debian/Ubuntu) + - Linux (Autres) + validations: + required: true + - type: input + attributes: + label: Version du système d'exploitation + placeholder: "Exemple: Windows 11 Professionnel 21H2 Build 22000.739" + validations: + required: true + - type: input + attributes: + label: Hash du commit sur lequel le bug est rencontré + placeholder: 84d7881b67ecf6088205eca6723bfb19bf2a5f0d + - type: textarea + attributes: + label: Comportement attendu + description: Une description de ce qui devrait se passer + placeholder: Le launcher devrait... + validations: + required: true + - type: textarea + attributes: + label: Comportement actuel + description: Une description de ce qui se passe avec le bug + validations: + required: true + - type: textarea + attributes: + label: Instructions pour reproduire le but + placeholder: | + 1. Ouvrir le launcher + 2. Aller dans le menu xyz + 3. Cliquer sur abc + 4. Observer + validations: + required: true + - type: textarea + attributes: + label: Notes additionnelles + placeholder: Détails supplémentaires concernant le bug, tout ce qui pourrait être utile + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..574a5e0f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Nous rejoindre sur Discord, pour toutes questions ou demandes + url: http://discord.luuxis.fr + about: Veuillez ne pas ouvrir d'issue autre que pour signaler des bugs diff --git a/.gitignore b/.gitignore index 08dc1a24..82791e76 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ node_modules build -files -.Minecraft -test/*.json +test/Minecraft +test/*.json* webfiles/instances/* +.DS_Store diff --git a/LICENSE.md b/LICENSE.md index c94c4001..82901b88 100755 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,160 +1,77 @@ -# Creative Commons Attribution-NonCommercial 4.0 International +LUUXIS LICENSE v1.0 – LICENCE PERSONNALISÉE / CUSTOM LICENSE -Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. +Copyright © 2025 Luuxis -### Using Creative Commons Public Licenses +FRANÇAIS 🇫🇷 +──────────────────────────────────────────────────────────── -Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. +Ce logiciel et son code source sont la propriété exclusive de l’auteur (ci-après « le Titulaire »). +L’utilisation, la modification et la redistribution sont autorisées sous réserve du respect strict des conditions suivantes : -* __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors). +1. 🛑 Interdiction d’usage commercial par des tiers + - Il est strictement interdit de vendre, louer ou redistribuer ce code (ou ses dérivés) à des fins commerciales. + - Toute utilisation commerciale directe du code est interdite, sauf autorisation écrite explicite du Titulaire. -* __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees). +2. 💰 Microtransactions autorisées + - La monétisation par microtransactions en jeu est autorisée, tant que : + - le code n’est pas vendu ni monétisé directement, + - le code source reste public et accessible. -## Creative Commons Attribution-NonCommercial 4.0 International Public License +3. 📂 Code source obligatoire et public + - Toute version redistribuée ou modifiée doit publier son code source complet, librement et gratuitement accessible, sans restriction. -By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. +4. 🧾 Attribution + - Le nom de l’auteur original (« Luuxis ») doit être clairement mentionné dans toute redistribution ou version modifiée. -### Section 1 – Definitions. +5. 🔐 Droit exclusif de revente par le créateur + - Seul le Titulaire (Luuxis) est autorisé à vendre ou concéder une licence commerciale du code source. -a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. +6. 🚫 Interdiction de modifier cette licence + - Il est interdit de modifier, supprimer ou remplacer cette licence. Toute redistribution doit inclure cette licence sans altération. -b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. +7. ⚠️ Absence de garantie + - Le logiciel est fourni "tel quel", sans garantie. L’auteur décline toute responsabilité pour tout dommage lié à son usage. -c. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. +8. ⚖️ Violation et poursuites + - Tout non-respect entraîne la résiliation immédiate de cette licence. L’usage non autorisé peut entraîner des poursuites conformément aux articles L.122-1 et L.335-3 du Code de la propriété intellectuelle (France). -d. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. +Par l’utilisation de ce logiciel, vous acceptez toutes les conditions de cette licence. -e. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. +──────────────────────────────────────────────────────────── -f. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License. +ENGLISH 🇬🇧 +──────────────────────────────────────────────────────────── -g. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. +This software and its source code are the exclusive property of the author (hereinafter “the Licensor”). +Use, modification, and redistribution are permitted under the following strict conditions: -h. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License. +1. 🛑 Prohibition of commercial use by third parties + - It is strictly forbidden to sell, rent or redistribute this code (or any derivative) for commercial purposes. + - Any direct commercial use of the code is forbidden unless explicitly authorized in writing by the Licensor. -i. __NonCommercial__ means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. +2. 💰 Microtransactions allowed + - In-game microtransaction monetization is allowed, as long as: + - the code itself is not sold or directly monetized, + - the source code remains public and freely accessible. -j. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. +3. 📂 Mandatory public source code + - Any redistributed or modified version must make its complete source code freely and publicly accessible, without restrictions. -k. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. +4. 🧾 Attribution + - The original author’s name (“Luuxis”) must be clearly credited in any redistribution or modified version. -l. __You__ means the individual or entity exercising the Licensed Rights under this Public License. __Your__ has a corresponding meaning. +5. 🔐 Exclusive resale rights reserved by the creator + - Only the Licensor (Luuxis) is allowed to sell or license this software or its source code for commercial purposes. -### Section 2 – Scope. +6. 🚫 License modification is forbidden + - This license must not be altered, replaced, or removed. Any redistribution must include this license as-is. -a. ___License grant.___ +7. ⚠️ No warranty + - This software is provided “as is”, without any warranties. The author accepts no liability for any damage resulting from its use. - 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: +8. ⚖️ Violation and legal consequences + - Any violation results in immediate termination of this license. Unauthorized use may lead to legal action under applicable copyright law. - A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and - - B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only. - - 2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. - - 3. __Term.__ The term of this Public License is specified in Section 6(a). - - 4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. - - 5. __Downstream recipients.__ - - A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. - - B. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. - - 6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). - -b. ___Other rights.___ - - 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this Public License. - - 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. - -### Section 3 – License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the following conditions. - -a. ___Attribution.___ - - 1. If You Share the Licensed Material (including in modified form), You must: - - A. retain the following if it is supplied by the Licensor with the Licensed Material: - - i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of warranties; - - v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; - - B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and - - C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. - - 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. - - 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. - -### Section 4 – Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: - -a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; - -b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and - -c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. - -### Section 5 – Disclaimer of Warranties and Limitation of Liability. - -a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__ - -b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__ - -c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. - -### Section 6 – Term and Termination. - -a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. - -b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. - -c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. - -d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. - -### Section 7 – Other Terms and Conditions. - -a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. - -b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. - -### Section 8 – Interpretation. - -a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. - -b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. - -c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. - -d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. - -> Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. -> -> Creative Commons may be contacted at creativecommons.org +By using this software, you fully and irrevocably agree to the terms of this license. +──────────────────────────────────────────────────────────── diff --git a/README.md b/README.md index dec625ec..f10f0f13 100755 --- a/README.md +++ b/README.md @@ -1,127 +1,248 @@ -# minecraft-java-core -NodeJS Module for Minecraft launcher -
-[![Number](https://img.shields.io/npm/v/minecraft-java-core?style=social&logo=appveyor)](https://npmjs.com/minecraft-java-core) -
-[![Install](https://img.shields.io/npm/dm/minecraft-java-core.svg?style=social&logo=appveyor)](https://npmjs.com/minecraft-java-core) -
-[![size](https://img.shields.io/github/languages/code-size/luuxis/minecraft-java-core?style=social&logo=appveyor)](https://npmjs.com/minecraft-java-core) -
-[![sizeinstall](https://badgen.net/packagephobia/install/minecraft-java-core)](https://npmjs.com/minecraft-java-core) +##### v4 • **minecraft‑java‑core** +[![License: CC‑BY‑NC 4.0](https://img.shields.io/badge/License-CC--BY--NC%204.0-yellow.svg)](https://creativecommons.org/licenses/by-nc/4.0/) +![stable version](https://img.shields.io/npm/v/minecraft-java-core?logo=nodedotjs) + +**minecraft‑java‑core** is a **NodeJS/TypeScript** solution for launching both vanilla *and* modded Minecraft Java Edition without juggling JSON manifests, assets, libraries or Java runtimes yourself. Think of it as the *core* of an Electron/NW.js/CLI launcher. --- -## Avantages :dizzy: -- Auto check & downloading compatible java version -- Support 100% custom minecraft version -- Work with ftp without any zip file, juste drop folder in your ftp -- Auto check & delete file with bad hash & size - -# Install Client - -## Quick Start :zap: -```npm -git clone https://github.com/luuxis/Selvania-Launcher.git -cd Selvania-Launcher -npm install -npm start -``` -## Installation :package: -```npm +### Getting support +Need help or just want to chat? Join the community Discord! + +

+ + + +

+ +--- + +### Installing + +```bash npm i minecraft-java-core +# or +yarn add minecraft-java-core ``` -## Usage :triangular_flag_on_post: -Require library -```javascript -const { Launch, Mojang } = require('minecraft-java-core'); -``` +*Requirements:* Node ≥ 18, TypeScript (only if you import *.ts*), 7‑Zip embedded binary. -## Launch :rocket: -### Options -```javascript -const { Mojang, Launch } = require('minecraft-java-core'); -const launch = new Launch(); - -async function main() { - let opt = { - authenticator: await Mojang.login('Luuxis'), - timeout: 10000, - path: './.Minecraft test', - version: '1.19.3', - detached: false, - downloadFileMultiple: 100, +--- + +### Standard Example (ESM) +```ts +const { Launch, Microsoft } = require('minecraft-java-core'); +const launcher = new Launch(); + +const fs = require('fs'); +let mc + +(async () => { + if (!fs.existsSync('./account.json')) { + mc = await new Microsoft().getAuth(); + fs.writeFileSync('./account.json', JSON.stringify(mc, null, 4)); + } else { + mc = JSON.parse(fs.readFileSync('./account.json')); + if (!mc.refresh_token) { + mc = await new Microsoft().getAuth(); + fs.writeFileSync('./account.json', JSON.stringify(mc, null, 4)); + } else { + mc = await new Microsoft().refresh(mc); + fs.writeFileSync('./account.json', JSON.stringify(mc, null, 4)); + if (mc.error) process.exit(1); + } + } + + const opt = { + url: "https://luuxcraft.fr/api/user/48c74227-13d1-48d6-931b-0f12b73da340/instance", + path: './minecraft', + authenticator: mc, + version: '1.8.9', + intelEnabledMac: true, + instance: "Hypixel", + + ignored: [ + "config", + "logs", + "resourcepacks", + "options.txt", + "optionsof.txt" + ], loader: { type: 'forge', build: 'latest', enable: true }, + memory: { + min: '14G', + max: '16G' + }, + }; + + launcher.Launch(opt); + launcher.on('progress', (progress, size) => console.log(`[DL] ${((progress / size) * 100).toFixed(2)}%`)); + launcher.on('patch', pacth => process.stdout.write(pacth)); + launcher.on('data', line => process.stdout.write(line)); + launcher.on('error', err => console.error(err)); +})(); +``` - verify: false, - ignored: ['loader', 'options.txt'], - args: [], +--- - javaPath: null, - java: true, +## Documentation + +### Launch class + +| Function | Type | Description | +|----------|---------|------------------------------------------------------------------------| +| `launch` | Promise | Launches Minecraft with the given **`LaunchOptions`** (see below). | + +#### LaunchOptions + +| Parameter | Type | Description | Required | +|-----------|------|-------------|----------| +| `path` | String | Working directory where game files are stored (usually `.minecraft`). | ✔︎ | +| `url` | String \| null | Custom version manifest base URL (only for mirror setups). | — | +| `authenticator` | Object | Microsoft / Mojang / AZauth profile returned by the authenticator. | ✔︎ | +| `timeout` | Integer | Network timeout in **milliseconds** for downloads. | — | +| `version` | String | `'latest_release'`, `'latest_snapshot'`, `'1.21.1'`. | — | +| `instance` | String \| null | Name of the instance if you manage multiple profiles. | — | +| `detached` | Boolean | Detach the Java process from the launcher. | — | +| `intelEnabledMac` | Boolean | Force Rosetta when running on Apple Silicon. | — | +| `downloadFileMultiple` | Integer | Max parallel downloads. | — | +| `loader.enable` | Boolean | Whether to install a mod‑loader (Forge/Fabric/…). | — | +| `loader.type` | String \| null | `forge`, `neoforge`, `fabric`, `legacyfabric`, `quilt`. | — | +| `loader.build` | String | Loader build tag (e.g. `latest`, `0.15.9`). | — | +| `loader.path` | String | Destination folder for loader files. Defaults to `./loader`. | — | +| `mcp` | String \| null | Path to MCP configuration for legacy mods. | — | +| `verify` | Boolean | Verify SHA‑1 of downloaded files. | — | +| `ignored` | Array | List of files to skip during verification. | — | +| `JVM_ARGS` | Array | Extra JVM arguments. | — | +| `GAME_ARGS` | Array | Extra Minecraft arguments. | — | +| `java.path` | String \| null | Absolute path to Java runtime. | — | +| `java.version` | String \| null | Force a specific Java version (e.g. `17`). | — | +| `java.type` | String | `jre` or `jdk`. | — | +| `screen.width` | Number \| null | Width of game window. | — | +| `screen.height` | Number \| null | Height of game window. | — | +| `screen.fullscreen` | Boolean | Start the game in fullscreen mode. | — | +| `memory.min` | String | Minimum RAM (e.g. `1G`). | ✔︎ | +| `memory.max` | String | Maximum RAM (e.g. `2G`). | ✔︎ | + +> **Recommendation:** Start with the minimal set (`authenticator`, `path`, `version`, `memory`) and gradually add overrides only when you need them. + +#### Default configuration + +Below is the complete **default** `LaunchOptions` object returned by +`minecraft‑java‑core` when you don’t override any field. Use it as a quick +reference for every available parameter and its default value. +(Parameters marked *nullable* can be left `null`/`undefined` and the library +will figure out sane values.) + +```ts +const defaultOptions = { + url: null, // Optional custom manifest URL + authenticator: null, // Microsoft/Mojang/AZauth profile + timeout: 10000, // Network timeout in ms + path: '.Minecraft', // Root directory (alias: root) + version: 'latest_release', // Minecraft version (string or 'latest_…') + instance: null, // Multi‑instance name (optional) + detached: false, // Detach Java process from parent + intelEnabledMac: false, // Rosetta toggle for Apple Silicon + downloadFileMultiple: 5, // Parallel downloads + + loader: { + path: './loader', // Where to install loaders + type: null, // forge | neoforge | fabric | … + build: 'latest', // Build number / tag + enable: false, // Whether to install the loader + }, + + mcp: null, // Path to MCP config (legacy mods) + + verify: false, // SHA‑1 check after download + ignored: [], // Files to skip verification + JVM_ARGS: [], // Extra JVM arguments + GAME_ARGS: [], // Extra game arguments + + java: { + path: null, // Custom JVM path + version: null, // Explicit Java version + type: 'jre', // jre | jdk + }, + + screen: { + width: null, + height: null, + fullscreen: false, + }, + + memory: { + min: '1G', + max: '2G', + }, +} as const; +``` - screen: { - width: null, - height: null, - fullscreen: null, - }, +> **Note** : Any field you provide when calling `Launch.launch()` will be +> merged on top of these defaults; you rarely need to specify more than +> `authenticator`, `path`, `version` and `memory`. - memory: { - min: '2G', - max: '4G' - } - } +--- - await launch.Launch(opt); +#### Events - launch.on('extract', extract => { - console.log(extract); - }); +| Event Name | Payload | Description | +|-------------|---------|--------------------------------------------------------------| +| `data` | String | Raw output from the Java process. | +| `progress` | Number | Global download progress percentage. | +| `speed` | Number | Current download speed (kB/s). | +| `estimated` | Number | Estimated time remaining (s). | +| `extract` | String | Name of the file currently being extracted. | +| `patch` | String | Loader patch currently applied. | +| `close` | void | Emitted when the Java process exits. | +| `error` | Error | Something went wrong. | - launch.on('progress', (progress, size, element) => { - console.log(`Downloading ${element} ${Math.round((progress / size) * 100)}%`); - }); +--- - launch.on('check', (progress, size, element) => { - console.log(`Checking ${element} ${Math.round((progress / size) * 100)}%`); - }); +### Authentication *(built‑in)* - launch.on('estimated', (time) => { - let hours = Math.floor(time / 3600); - let minutes = Math.floor((time - hours * 3600) / 60); - let seconds = Math.floor(time - hours * 3600 - minutes * 60); - console.log(`${hours}h ${minutes}m ${seconds}s`); - }) +* **Microsoft** — OAuth 2 Device Code flow via Xbox Live → XSTS → Minecraft. +* **Mojang** *(legacy)* — classic Yggdrasil endpoint. +* **AZauth** — community Yggdrasil‑compatible server. - launch.on('speed', (speed) => { - console.log(`${(speed / 1067008).toFixed(2)} Mb/s`) - }) +> The authenticator returns a profile object that you pass directly to `Launch.launch()`. - launch.on('patch', patch => { - console.log(patch); - }); +--- - launch.on('data', (e) => { - console.log(e); - }) +### Utilities - launch.on('close', code => { - console.log(code); - }); +* **Downloader** — resilient downloader with resume, integrity check & `progress`/`speed` events. +* **Status** — simple TCP ping that returns MOTD, player count & latency. - launch.on('error', err => { - console.log(err); - }); -} +--- -main() +### File structure (simplified) ``` +src/ + Authenticator/ Microsoft, Mojang, AZauth flows + Minecraft/ Version JSON, assets, libraries, args builder + Minecraft-Loader/ Forge, NeoForge, Fabric, Quilt, … installers + StatusServer/ Server ping implementation + utils/ Downloader & helpers + Launch.ts Main entry point +assets/ LWJGL native indexes +``` + +--- + +### Contributors +See the commit history for a full list. Special thanks to: + +* **Luuxis** — original author. +* Community testers & issue reporters. + --- -
-[

discord](https://discord.gg/e9q7Yr2cuQ) +### License +Released under **Creative Commons Attribution‑NonCommercial 4.0 International**. \ No newline at end of file diff --git a/assets/LWJGL/aarch/2.9.4.json b/assets/LWJGL/aarch/2.9.4.json new file mode 100644 index 00000000..9a6bd338 --- /dev/null +++ b/assets/LWJGL/aarch/2.9.4.json @@ -0,0 +1,96 @@ +{ + "libraries": [ + { + "downloads": { + "classifiers": { + "natives-linux": { + "path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-linux.jar", + "sha1": "f3c455b71c5146acb5f8a9513247fc06db182fd5", + "size": 4521, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-2.9.4/jinput-platform-2.0.5-natives-linux.jar" + } + } + }, + "extract": { + "exclude": [ + "META-INF/" + ] + }, + "name": "net.java.jinput:jinput-platform:2.0.5", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "path": "net/java/jinput/jinput/2.0.5/jinput-2.0.5.jar", + "sha1": "c2e322bbec2345f1b93b96000f93e3a4c3b2bf96", + "size": 216945, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-2.9.4/jinput-2.0.5.jar" + } + }, + "name": "net.java.jinput:jinput:2.0.5" + }, + { + "downloads": { + "artifact": { + "path": "net/java/jutils/jutils/1.0.0/jutils-1.0.0.jar", + "sha1": "e12fe1fda814bd348c1579329c86943d2cd3c6a6", + "size": 7508, + "url": "https://libraries.minecraft.net/net/java/jutils/jutils/1.0.0/jutils-1.0.0.jar" + } + }, + "name": "net.java.jutils:jutils:1.0.0" + }, + { + "downloads": { + "artifact": { + "path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar", + "sha1": "b04f3ee8f5e43fa3b162981b50bb72fe1acabb33", + "size": 22, + "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar" + }, + "classifiers": { + "natives-linux": { + "path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar", + "sha1": "fa483e540a9a753a5ffbb23dcf7879a5bf752611", + "size": 475177, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-2.9.4/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar" + } + } + }, + "extract": { + "exclude": [ + "META-INF/" + ] + }, + "name": "org.lwjgl.lwjgl:lwjgl-platform:2.9.4-nightly-20150209", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "path": "org/lwjgl/lwjgl/lwjgl/2.9.4-nightly-20150209/lwjgl-2.9.4-nightly-20150209.jar", + "sha1": "697517568c68e78ae0b4544145af031c81082dfe", + "size": 1047168, + "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl/2.9.4-nightly-20150209/lwjgl-2.9.4-nightly-20150209.jar" + } + }, + "name": "org.lwjgl.lwjgl:lwjgl:2.9.4-nightly-20150209" + }, + { + "downloads": { + "artifact": { + "path": "org/lwjgl/lwjgl/lwjgl_util/2.9.4-nightly-20150209/lwjgl_util-2.9.4-nightly-20150209.jar", + "sha1": "d51a7c040a721d13efdfbd34f8b257b2df882ad0", + "size": 173887, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-2.9.4/lwjgl_util-2.9.4-nightly-20150209.jar" + } + }, + "name": "org.lwjgl.lwjgl:lwjgl_util:2.9.4-nightly-20150209" + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch/3.1.2.json b/assets/LWJGL/aarch/3.1.2.json new file mode 100644 index 00000000..a9577cde --- /dev/null +++ b/assets/LWJGL/aarch/3.1.2.json @@ -0,0 +1,202 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "d2df40234fd576e708feee78bccadaf02c5712a3", + "size": 300107, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "d2df40234fd576e708feee78bccadaf02c5712a3", + "size": 300107, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "1d4e6397a4ba0df30f7477ee5ba308d4dad3387e", + "size": 59165, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "9b0884b8fc763ebf9abe2fd747feaf6bc6968d8c", + "size": 39899, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "9b0884b8fc763ebf9abe2fd747feaf6bc6968d8c", + "size": 39899, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "e3c8c26f433efc2e135b9f02a275742825560bfc", + "size": 134237, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-jemalloc-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "71cbf1f0f60dc7a9c522c5b76e7e62453ca7c77c", + "size": 78718, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "71cbf1f0f60dc7a9c522c5b76e7e62453ca7c77c", + "size": 78718, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "fafb2af9deeb64b52a1642ae853493e1f13f98a2", + "size": 398418, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-openal-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "9a6b6e74b41c15b70964a79a32d4a9b04f614d9f", + "size": 830047, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "9a6b6e74b41c15b70964a79a32d4a9b04f614d9f", + "size": 830047, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "a7922f4e7be6aae0483432cac5ee7da7b0748346", + "size": 65526, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-opengl-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "f978d3bf16a4ba09dafeb3d5563786cb7002129c", + "size": 114229, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "f978d3bf16a4ba09dafeb3d5563786cb7002129c", + "size": 114229, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "0c1dc55fed2fe336c256206a2b49fc54107115f5", + "size": 80186, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-glfw-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "bc9e649120027fc78cfebabc17b00ba50e16a86a", + "size": 104372, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "bc9e649120027fc78cfebabc17b00ba50e16a86a", + "size": 104372, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "bdf6e31bf49d466cc497444f1be31dbd522e108a", + "size": 143311, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-stb-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.1.6", + "natives": { + "linux": "natives-linux" + } + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch/3.1.6.json b/assets/LWJGL/aarch/3.1.6.json new file mode 100644 index 00000000..a9577cde --- /dev/null +++ b/assets/LWJGL/aarch/3.1.6.json @@ -0,0 +1,202 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "d2df40234fd576e708feee78bccadaf02c5712a3", + "size": 300107, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "d2df40234fd576e708feee78bccadaf02c5712a3", + "size": 300107, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "1d4e6397a4ba0df30f7477ee5ba308d4dad3387e", + "size": 59165, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "9b0884b8fc763ebf9abe2fd747feaf6bc6968d8c", + "size": 39899, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "9b0884b8fc763ebf9abe2fd747feaf6bc6968d8c", + "size": 39899, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "e3c8c26f433efc2e135b9f02a275742825560bfc", + "size": 134237, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-jemalloc-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "71cbf1f0f60dc7a9c522c5b76e7e62453ca7c77c", + "size": 78718, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "71cbf1f0f60dc7a9c522c5b76e7e62453ca7c77c", + "size": 78718, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "fafb2af9deeb64b52a1642ae853493e1f13f98a2", + "size": 398418, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-openal-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "9a6b6e74b41c15b70964a79a32d4a9b04f614d9f", + "size": 830047, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "9a6b6e74b41c15b70964a79a32d4a9b04f614d9f", + "size": 830047, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "a7922f4e7be6aae0483432cac5ee7da7b0748346", + "size": 65526, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-opengl-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "f978d3bf16a4ba09dafeb3d5563786cb7002129c", + "size": 114229, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "f978d3bf16a4ba09dafeb3d5563786cb7002129c", + "size": 114229, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "0c1dc55fed2fe336c256206a2b49fc54107115f5", + "size": 80186, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-glfw-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "bc9e649120027fc78cfebabc17b00ba50e16a86a", + "size": 104372, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "bc9e649120027fc78cfebabc17b00ba50e16a86a", + "size": 104372, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "bdf6e31bf49d466cc497444f1be31dbd522e108a", + "size": 143311, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.1.6/lwjgl-stb-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.1.6", + "natives": { + "linux": "natives-linux" + } + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch/3.2.1.json b/assets/LWJGL/aarch/3.2.1.json new file mode 100644 index 00000000..7cfebef2 --- /dev/null +++ b/assets/LWJGL/aarch/3.2.1.json @@ -0,0 +1,202 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "c1f8d244dda855a936e136844a5c80611a5f36fe", + "size": 314536, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "c1f8d244dda855a936e136844a5c80611a5f36fe", + "size": 314536, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "a50f6e12091dccd4901e783b168b428f7653d254", + "size": 65481, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.2.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "f8f7801d8b82af7705f06c40bbea16b066479531", + "size": 37712, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.1/lwjgl-jemalloc-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "f8f7801d8b82af7705f06c40bbea16b066479531", + "size": 37712, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.1/lwjgl-jemalloc-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "e19e402887625f15a982426156976badcdffaadc", + "size": 134237, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-jemalloc-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.1/lwjgl-jemalloc-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.2.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "3dcb4c151a8ccf65f50f4aee9f6ff30a79bb7439", + "size": 79683, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.1/lwjgl-openal-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "3dcb4c151a8ccf65f50f4aee9f6ff30a79bb7439", + "size": 79683, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.1/lwjgl-openal-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "0dce4b9a444fcb0a4e5b75ea758b0094049daea3", + "size": 398418, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-openal-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.1/lwjgl-openal-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.2.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "2350cc2bd1fe80e14ff2c39a81477b57dccfe09a", + "size": 939248, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.1/lwjgl-opengl-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "2350cc2bd1fe80e14ff2c39a81477b57dccfe09a", + "size": 939248, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.1/lwjgl-opengl-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "a6d3ff86fe3e07bd055032e93ce3b8952574a427", + "size": 56387, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-opengl-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.1/lwjgl-opengl-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.2.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "f245bcd89c484e05b524c25ea9935b6aa1e6d7ac", + "size": 116839, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.1/lwjgl-glfw-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "f245bcd89c484e05b524c25ea9935b6aa1e6d7ac", + "size": 116839, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.1/lwjgl-glfw-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "14533fb79a7077b2eb1d156067956d2da9f3403f", + "size": 80186, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-glfw-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.1/lwjgl-glfw-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.2.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "acd384013d30ea9ddddd805e9a5996b2b6058c5c", + "size": 105432, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.1/lwjgl-stb-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "acd384013d30ea9ddddd805e9a5996b2b6058c5c", + "size": 105432, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.1/lwjgl-stb-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "bc5bb97dbb328df0c82375637030f692a161d082", + "size": 144685, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.1/lwjgl-stb-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.1/lwjgl-stb-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.2.1", + "natives": { + "linux": "natives-linux" + } + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch/3.2.2.json b/assets/LWJGL/aarch/3.2.2.json new file mode 100644 index 00000000..e19ae72a --- /dev/null +++ b/assets/LWJGL/aarch/3.2.2.json @@ -0,0 +1,235 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "16ea3934fca417368250d1ddac01a30c1809d317", + "size": 318413, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.2.2/lwjgl-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "16ea3934fca417368250d1ddac01a30c1809d317", + "size": 318413, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.2.2/lwjgl-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "6bd0b37fef777a309936a72dc7f63126e8c79ea5", + "size": 90296, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl/3.2.2/lwjgl-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "8224ae2e8fc6d8e1a0fc7d84dc917aa3c440620c", + "size": 33790, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.2/lwjgl-jemalloc-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "8224ae2e8fc6d8e1a0fc7d84dc917aa3c440620c", + "size": 33790, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.2/lwjgl-jemalloc-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "9163a2a5559ef87bc13ead8fea84417ea3928748", + "size": 134237, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-jemalloc-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.2/lwjgl-jemalloc-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "304f0571fd5971621ee6da86a4c1e90f6f52e2ee", + "size": 79582, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.2/lwjgl-openal-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "304f0571fd5971621ee6da86a4c1e90f6f52e2ee", + "size": 79582, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.2/lwjgl-openal-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "ecbc981fdd996492a1f6334f003ed62e5a8c0cd5", + "size": 398418, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-openal-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.2/lwjgl-openal-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "9762ae928d02147e716cd82e929b74a97ea9600a", + "size": 937609, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.2/lwjgl-opengl-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "9762ae928d02147e716cd82e929b74a97ea9600a", + "size": 937609, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.2/lwjgl-opengl-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "3af5599c74dd76dd8dbb567b3f9b4963a6abeed5", + "size": 56388, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-opengl-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.2/lwjgl-opengl-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "99e9a39fa8ed4167e3ff9e04d47eb32c9e69804d", + "size": 108691, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.2/lwjgl-glfw-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "99e9a39fa8ed4167e3ff9e04d47eb32c9e69804d", + "size": 108691, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.2/lwjgl-glfw-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "4265f2fbe3b9d642591165165a17cf406cf7b98e", + "size": 80186, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-glfw-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.2/lwjgl-glfw-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "ea979b0af45b8e689f5f47c989aa8550c148d8a2", + "size": 104075, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.2/lwjgl-stb-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "ea979b0af45b8e689f5f47c989aa8550c148d8a2", + "size": 104075, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.2/lwjgl-stb-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "ec9d70aaebd0ff76dfeecf8f00b56118bf3706b1", + "size": 149387, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-stb-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.2/lwjgl-stb-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "a8c09f5b7fa24bd53ec329c231b566497a163d5b", + "size": 5571, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-tinyfd.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.2.2/lwjgl-tinyfd-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "a8c09f5b7fa24bd53ec329c231b566497a163d5b", + "size": 5571, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-tinyfd.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.2.2/lwjgl-tinyfd-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "82d16054ada6633297a3108fb6d8bae98800c76f", + "size": 41663, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm32/raw/lwjgl-3.2.2/lwjgl-tinyfd-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.2.2/lwjgl-tinyfd-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.2.2", + "natives": { + "linux": "natives-linux" + } + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch/3.3.1.json b/assets/LWJGL/aarch/3.3.1.json new file mode 100644 index 00000000..a76adcaa --- /dev/null +++ b/assets/LWJGL/aarch/3.3.1.json @@ -0,0 +1,270 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "cbac1b8d30cb4795149c1ef540f912671a8616d0", + "size": 128801, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "cbac1b8d30cb4795149c1ef540f912671a8616d0", + "size": 128801, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "816d935933f2dd743074c4e717cc25b55720f294", + "size": 104027, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "e502700e6a1a0d02bddb8b4ef85afcdc15c88358", + "size": 125778, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "a817bcf213db49f710603677457567c37d53e103", + "size": 36601, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "a817bcf213db49f710603677457567c37d53e103", + "size": 36601, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "a96a6d6cb3876d7813fcee53c3c24f246aeba3b3", + "size": 136157, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "f5858d34e06053b1866858fed7a685cf0c6b5926", + "size": 32306, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "2623a6b8ae1dfcd880738656a9f0243d2e6840bd", + "size": 88237, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "2623a6b8ae1dfcd880738656a9f0243d2e6840bd", + "size": 88237, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "ffbe35d7fa5ec9b7eca136a7c71f24d4025a510b", + "size": 400129, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "9c563bf7c10b71c6609b9f96a7c7859bdf05d21f", + "size": 85417, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "831a5533a21a5f4f81bbc51bb13e9899319b5411", + "size": 921563, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "831a5533a21a5f4f81bbc51bb13e9899319b5411", + "size": 921563, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "e3550fa91097fd56e361b4370fa822220fef3595", + "size": 58474, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "1a827bc02651fa44d32f424c380edc6d53f94a62", + "size": 1274449, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "b119297cf8ed01f247abe8685857f8e7fcf5980f", + "size": 112380, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "b119297cf8ed01f247abe8685857f8e7fcf5980f", + "size": 112380, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "b08226bab162c06ae69337d8a1b0ee0a3fdf0b90", + "size": 153889, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "22cb295464f44068add8443204ec8c85fd379cbe", + "size": 103489, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "0ff1914111ef2e3e0110ef2dabc8d8cdaad82347", + "size": 6767, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "0ff1914111ef2e3e0110ef2dabc8d8cdaad82347", + "size": 6767, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "d53d331e859217a61298fcbcf8d79137f3df345c", + "size": 48061, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar" + }, + "sources": { + "sha1": "4784c20508b51386ce9d572632524a5bf47ccb40", + "size": 5530, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "ae58664f88e18a9bb2c77b063833ca7aaec484cb", + "size": 724243, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar", + "path": "org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "ae58664f88e18a9bb2c77b063833ca7aaec484cb", + "size": 724243, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar", + "path": "org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "41a3c1dd15d6b964eb8196dde69720a3e3e5e969", + "size": 82374, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "e918fb595d1ca293a68807a9da8b519ea348a67a", + "size": 572854, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.3.1", + "natives": { + "linux": "natives-linux" + } + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch/3.3.2.json b/assets/LWJGL/aarch/3.3.2.json new file mode 100644 index 00000000..360f5c24 --- /dev/null +++ b/assets/LWJGL/aarch/3.3.2.json @@ -0,0 +1,270 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "757920418805fb90bfebb3d46b1d9e7669fca2eb", + "size": 135828, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "757920418805fb90bfebb3d46b1d9e7669fca2eb", + "size": 135828, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "5907d9a6b7c44fb0612a63bb1cff5992588f65be", + "size": 110067, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "0bdd2ae91adb35fd7809b7ecf2d677546b26fe4f", + "size": 126160, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "877e17e39ebcd58a9c956dc3b5b777813de0873a", + "size": 43233, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "877e17e39ebcd58a9c956dc3b5b777813de0873a", + "size": 43233, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "9367437ce192e4d6f5725d53d85520644c0b0d6f", + "size": 177571, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "1d953086a319cfb09d0703e50011849a95ab2277", + "size": 32303, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "ae5357ed6d934546d3533993ea84c0cfb75eed95", + "size": 108230, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "ae5357ed6d934546d3533993ea84c0cfb75eed95", + "size": 108230, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "7c82bbc33ef49ee4094b216c940db564b2998224", + "size": 503352, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "534195bc70b8ff83c270c1d618cdafe76e9be2c4", + "size": 100606, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "ee8e95be0b438602038bc1f02dc5e3d011b1b216", + "size": 928871, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "ee8e95be0b438602038bc1f02dc5e3d011b1b216", + "size": 928871, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "821f9a2d1d583c44893f42b96f6977682b48a99b", + "size": 59265, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "1301ff0d9814ac96d7020f5912d5f0f72c039fca", + "size": 1275908, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "a2550795014d622b686e9caac50b14baa87d2c70", + "size": 118874, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "a2550795014d622b686e9caac50b14baa87d2c70", + "size": 118874, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "ca9333da184aade20757151f4615f1e27ca521ae", + "size": 154928, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "dda437f20ae0c920c1c744984b4093889982b994", + "size": 103496, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "9f65c248dd77934105274fcf8351abb75b34327c", + "size": 13404, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "9f65c248dd77934105274fcf8351abb75b34327c", + "size": 13404, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "807e220913aa0740449ff90d3b3d825cf5f359ed", + "size": 48788, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2.jar" + }, + "sources": { + "sha1": "bd33407b8cdbac1161c759656034d283f4708051", + "size": 5527, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "4421d94af68e35dcaa31737a6fc59136a1e61b94", + "size": 786196, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2.jar", + "path": "org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "4421d94af68e35dcaa31737a6fc59136a1e61b94", + "size": 786196, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2.jar", + "path": "org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "afcbfaaa46f217e98a6da4208550f71de1f2a225", + "size": 89347, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2-natives-linux-arm32.jar", + "path": "org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "aff949f8180d6d1e26a47c7a2bca8163f5b987fe", + "size": 624340, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.3.2", + "natives": { + "linux": "natives-linux" + } + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch64/2.9.4.json b/assets/LWJGL/aarch64/2.9.4.json new file mode 100644 index 00000000..aa3324da --- /dev/null +++ b/assets/LWJGL/aarch64/2.9.4.json @@ -0,0 +1,96 @@ +{ + "libraries": [ + { + "downloads": { + "classifiers": { + "natives-linux": { + "path": "net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-linux.jar", + "sha1": "42b388ccb7c63cec4e9f24f4dddef33325f8b212", + "size": 10932, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-2.9.4/jinput-platform-2.0.5-natives-linux.jar" + } + } + }, + "extract": { + "exclude": [ + "META-INF/" + ] + }, + "name": "net.java.jinput:jinput-platform:2.0.5", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "path": "net/java/jinput/jinput/2.0.5/jinput-2.0.5.jar", + "sha1": "47f50f20c60495069c5a3cab65f5f87b44c1069e", + "size": 216970, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-2.9.4/jinput-2.0.5.jar" + } + }, + "name": "net.java.jinput:jinput:2.0.5" + }, + { + "downloads": { + "artifact": { + "path": "net/java/jutils/jutils/1.0.0/jutils-1.0.0.jar", + "sha1": "e12fe1fda814bd348c1579329c86943d2cd3c6a6", + "size": 7508, + "url": "https://libraries.minecraft.net/net/java/jutils/jutils/1.0.0/jutils-1.0.0.jar" + } + }, + "name": "net.java.jutils:jutils:1.0.0" + }, + { + "downloads": { + "artifact": { + "path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar", + "sha1": "b04f3ee8f5e43fa3b162981b50bb72fe1acabb33", + "size": 22, + "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar" + }, + "classifiers": { + "natives-linux": { + "path": "org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar", + "sha1": "63ac7da0f4a4785c7eadc0f8edc1e9dcc4dd08cb", + "size": 579979, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-2.9.4/lwjgl-platform-2.9.4-nightly-20150209-natives-linux.jar" + } + } + }, + "extract": { + "exclude": [ + "META-INF/" + ] + }, + "name": "org.lwjgl.lwjgl:lwjgl-platform:2.9.4-nightly-20150209", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "path": "org/lwjgl/lwjgl/lwjgl/2.9.4-nightly-20150209/lwjgl-2.9.4-nightly-20150209.jar", + "sha1": "697517568c68e78ae0b4544145af031c81082dfe", + "size": 1047168, + "url": "https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl/2.9.4-nightly-20150209/lwjgl-2.9.4-nightly-20150209.jar" + } + }, + "name": "org.lwjgl.lwjgl:lwjgl:2.9.4-nightly-20150209" + }, + { + "downloads": { + "artifact": { + "path": "org/lwjgl/lwjgl/lwjgl_util/2.9.4-nightly-20150209/lwjgl_util-2.9.4-nightly-20150209.jar", + "sha1": "d51a7c040a721d13efdfbd34f8b257b2df882ad0", + "size": 173887, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-2.9.4/lwjgl_util-2.9.4-nightly-20150209.jar" + } + }, + "name": "org.lwjgl.lwjgl:lwjgl_util:2.9.4-nightly-20150209" + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch64/3.1.2.json b/assets/LWJGL/aarch64/3.1.2.json new file mode 100644 index 00000000..fab1028f --- /dev/null +++ b/assets/LWJGL/aarch64/3.1.2.json @@ -0,0 +1,202 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "55b9dbe63745835ddde8b4c22be8da6520e8274f", + "size": 300107, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "55b9dbe63745835ddde8b4c22be8da6520e8274f", + "size": 300107, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "68c8151938f33c702528208d32084e1c18b2dc9e", + "size": 54802, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "6e9ee82494343aee0737c391e151d0147c992584", + "size": 39899, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "6e9ee82494343aee0737c391e151d0147c992584", + "size": 39899, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "762d7d80c9cdf3a3f3fc80c8a5f86612255edfe0", + "size": 156343, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-jemalloc-patched-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "fa243387070b806da104e3746828968b07ca737f", + "size": 78718, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "fa243387070b806da104e3746828968b07ca737f", + "size": 78718, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "5d1f9e7c633044a5700f2a80454d2a717251f675", + "size": 469432, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-openal-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "862a9e64741dfab2f3a48638ebd58c35ba5e43cd", + "size": 830047, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "862a9e64741dfab2f3a48638ebd58c35ba5e43cd", + "size": 830047, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "f9dec4cedbe2d98a92dd933d030c7e3efa99411b", + "size": 67010, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-opengl-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "b3ae7bad5b7e7d771ba9423521fc10f4ed67bbab", + "size": 114229, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "b3ae7bad5b7e7d771ba9423521fc10f4ed67bbab", + "size": 114229, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "645aeac6de1deb1b77c7cf3abe84674f77ef1aea", + "size": 85072, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-glfw-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "688e32efb1ad7a09b60f0f4b7131e3dc33b286ca", + "size": 104372, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "688e32efb1ad7a09b60f0f4b7131e3dc33b286ca", + "size": 104372, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "7852b75b40a470face01cbb9f37ebc5e715944bd", + "size": 192935, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-stb-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.1.6", + "natives": { + "linux": "natives-linux" + } + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch64/3.1.6.json b/assets/LWJGL/aarch64/3.1.6.json new file mode 100644 index 00000000..fab1028f --- /dev/null +++ b/assets/LWJGL/aarch64/3.1.6.json @@ -0,0 +1,202 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "55b9dbe63745835ddde8b4c22be8da6520e8274f", + "size": 300107, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "55b9dbe63745835ddde8b4c22be8da6520e8274f", + "size": 300107, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "68c8151938f33c702528208d32084e1c18b2dc9e", + "size": 54802, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl/3.1.6/lwjgl-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "6e9ee82494343aee0737c391e151d0147c992584", + "size": 39899, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "6e9ee82494343aee0737c391e151d0147c992584", + "size": 39899, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "762d7d80c9cdf3a3f3fc80c8a5f86612255edfe0", + "size": 156343, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-jemalloc-patched-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.1.6/lwjgl-jemalloc-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "fa243387070b806da104e3746828968b07ca737f", + "size": 78718, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "fa243387070b806da104e3746828968b07ca737f", + "size": 78718, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "5d1f9e7c633044a5700f2a80454d2a717251f675", + "size": 469432, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-openal-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-openal/3.1.6/lwjgl-openal-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "862a9e64741dfab2f3a48638ebd58c35ba5e43cd", + "size": 830047, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "862a9e64741dfab2f3a48638ebd58c35ba5e43cd", + "size": 830047, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "f9dec4cedbe2d98a92dd933d030c7e3efa99411b", + "size": 67010, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-opengl-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-opengl/3.1.6/lwjgl-opengl-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "b3ae7bad5b7e7d771ba9423521fc10f4ed67bbab", + "size": 114229, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "b3ae7bad5b7e7d771ba9423521fc10f4ed67bbab", + "size": 114229, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "645aeac6de1deb1b77c7cf3abe84674f77ef1aea", + "size": 85072, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-glfw-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-glfw/3.1.6/lwjgl-glfw-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.1.6", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "688e32efb1ad7a09b60f0f4b7131e3dc33b286ca", + "size": 104372, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.1.6" + }, + { + "downloads": { + "artifact": { + "sha1": "688e32efb1ad7a09b60f0f4b7131e3dc33b286ca", + "size": 104372, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "7852b75b40a470face01cbb9f37ebc5e715944bd", + "size": 192935, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.1.6/lwjgl-stb-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-stb/3.1.6/lwjgl-stb-3.1.6-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.1.6", + "natives": { + "linux": "natives-linux" + } + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch64/3.2.1.json b/assets/LWJGL/aarch64/3.2.1.json new file mode 100644 index 00000000..c395b0bd --- /dev/null +++ b/assets/LWJGL/aarch64/3.2.1.json @@ -0,0 +1,202 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "4add49f642c6f6d0bf51e1b6fea388d5101267b9", + "size": 314115, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "4add49f642c6f6d0bf51e1b6fea388d5101267b9", + "size": 314115, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "03c691efeac999530f4b350312a5a9d85e52cf89", + "size": 60186, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl/3.2.1/lwjgl-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.2.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "5621e055b542f6caab937b8346de5fd02105f9b2", + "size": 37712, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.1/lwjgl-jemalloc-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "5621e055b542f6caab937b8346de5fd02105f9b2", + "size": 37712, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.1/lwjgl-jemalloc-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "762d7d80c9cdf3a3f3fc80c8a5f86612255edfe0", + "size": 156343, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-jemalloc-patched-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.1/lwjgl-jemalloc-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.2.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "b6ef8efb60c888a14feebcd09addc265f1eca1a2", + "size": 79683, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.1/lwjgl-openal-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "b6ef8efb60c888a14feebcd09addc265f1eca1a2", + "size": 79683, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.1/lwjgl-openal-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "222a583cbfdcc3a81d5d9ad807c3d68196c8ec52", + "size": 469432, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-openal-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.1/lwjgl-openal-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.2.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "282139e3a8d1402fc25e18eb6a05eb090a1e81b4", + "size": 939248, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.1/lwjgl-opengl-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "282139e3a8d1402fc25e18eb6a05eb090a1e81b4", + "size": 939248, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.1/lwjgl-opengl-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "1d5e0092e54efd3f100f2c307261155573fa78f6", + "size": 56110, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-opengl-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.1/lwjgl-opengl-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.2.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "ccc4ba7e8521b5981343bcdbc3cf6492f35a5aa5", + "size": 116839, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.1/lwjgl-glfw-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "ccc4ba7e8521b5981343bcdbc3cf6492f35a5aa5", + "size": 116839, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.1/lwjgl-glfw-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "d52b2a26fafb6d4eebeef74ee4f6c3ebd65004b2", + "size": 85072, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-glfw-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.1/lwjgl-glfw-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.2.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "e6898a15a8067c89771ae2949bea8f5ff7874fcc", + "size": 105432, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.1/lwjgl-stb-3.2.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.2.1" + }, + { + "downloads": { + "artifact": { + "sha1": "e6898a15a8067c89771ae2949bea8f5ff7874fcc", + "size": 105432, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.1/lwjgl-stb-3.2.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "b8f7ace2cb31887254bbcde88e0dc705f5de2c3f", + "size": 193998, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.1/lwjgl-stb-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.1/lwjgl-stb-3.2.1-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.2.1", + "natives": { + "linux": "natives-linux" + } + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch64/3.2.2.json b/assets/LWJGL/aarch64/3.2.2.json new file mode 100644 index 00000000..d15ca007 --- /dev/null +++ b/assets/LWJGL/aarch64/3.2.2.json @@ -0,0 +1,235 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "360899386df83d6a8407844a94478607af937f97", + "size": 318833, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.2.2/lwjgl-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "360899386df83d6a8407844a94478607af937f97", + "size": 318833, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-core.jar", + "path": "org/lwjgl/lwjgl/3.2.2/lwjgl-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "612efd57d12b2e48e554858eb35e7e2eb46ebb4c", + "size": 87121, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl/3.2.2/lwjgl-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "cc04eec29b2fa8c298791af9800a3766d9617954", + "size": 33790, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.2/lwjgl-jemalloc-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "cc04eec29b2fa8c298791af9800a3766d9617954", + "size": 33790, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-jemalloc.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.2/lwjgl-jemalloc-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "762d7d80c9cdf3a3f3fc80c8a5f86612255edfe0", + "size": 156343, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-jemalloc-patched-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.2.2/lwjgl-jemalloc-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "6dfce9dc6a9629c75b2ae01a8df7e7be80ba0261", + "size": 79582, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.2/lwjgl-openal-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "6dfce9dc6a9629c75b2ae01a8df7e7be80ba0261", + "size": 79582, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-openal.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.2/lwjgl-openal-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "948e415b5b2a2c650c25b377a4a9f443b21ce92e", + "size": 469432, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-openal-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-openal/3.2.2/lwjgl-openal-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "198bc2f72e0b2eb401eb6f5999aea52909b31ac4", + "size": 937609, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.2/lwjgl-opengl-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "198bc2f72e0b2eb401eb6f5999aea52909b31ac4", + "size": 937609, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-opengl.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.2/lwjgl-opengl-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "bd40897077bf7d12f562da898b18ac2c68e1f9d7", + "size": 56109, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-opengl-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-opengl/3.2.2/lwjgl-opengl-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "155d175037efc76630940c197ca6dea2b17d7e18", + "size": 108691, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.2/lwjgl-glfw-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "155d175037efc76630940c197ca6dea2b17d7e18", + "size": 108691, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-glfw.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.2/lwjgl-glfw-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "074ad243761147df0d060fbefc814614d2ff75cc", + "size": 85072, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-glfw-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-glfw/3.2.2/lwjgl-glfw-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "46a5735f3eb9d17eb5dcbdd5afa194066d2a6555", + "size": 104075, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.2/lwjgl-stb-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "46a5735f3eb9d17eb5dcbdd5afa194066d2a6555", + "size": 104075, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-stb.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.2/lwjgl-stb-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "077efa7d7ea41b32df5c6078e912e724cccd06db", + "size": 202038, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-stb-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-stb/3.2.2/lwjgl-stb-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.2.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "3a75b9811607633bf33c978f53964df1534a4bc1", + "size": 5571, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-tinyfd.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.2.2/lwjgl-tinyfd-3.2.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.2.2" + }, + { + "downloads": { + "artifact": { + "sha1": "3a75b9811607633bf33c978f53964df1534a4bc1", + "size": 5571, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-tinyfd.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.2.2/lwjgl-tinyfd-3.2.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "37c744ca289b5d7ae155d79e39029488b3254e5b", + "size": 37893, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.2.2/lwjgl-tinyfd-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.2.2/lwjgl-tinyfd-3.2.2-natives-linux.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.2.2", + "natives": { + "linux": "natives-linux" + } + } + ] +} \ No newline at end of file diff --git a/assets/LWJGL/aarch64/3.3.1.json b/assets/LWJGL/aarch64/3.3.1.json new file mode 100644 index 00000000..f9bbf8e0 --- /dev/null +++ b/assets/LWJGL/aarch64/3.3.1.json @@ -0,0 +1,270 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "cbac1b8d30cb4795149c1ef540f912671a8616d0", + "size": 128801, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "cbac1b8d30cb4795149c1ef540f912671a8616d0", + "size": 128801, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "513eb39b866d0fe131a18d5c517087805433b029", + "size": 112350, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "e502700e6a1a0d02bddb8b4ef85afcdc15c88358", + "size": 125778, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.1/lwjgl-glfw-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "a817bcf213db49f710603677457567c37d53e103", + "size": 36601, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "a817bcf213db49f710603677457567c37d53e103", + "size": 36601, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "749be48a9b86ee2c3a2da5fd77511208adcfb33b", + "size": 159993, + "url": "https://github.com/theofficialgman/lwjgl3-binaries-arm64/raw/lwjgl-3.3.1/lwjgl-jemalloc-patched-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "f5858d34e06053b1866858fed7a685cf0c6b5926", + "size": 32306, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.1/lwjgl-jemalloc-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "2623a6b8ae1dfcd880738656a9f0243d2e6840bd", + "size": 88237, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "2623a6b8ae1dfcd880738656a9f0243d2e6840bd", + "size": 88237, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "cf4e303257e82981b8b2e31bba3d7f8f7b8f42b2", + "size": 470743, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "9c563bf7c10b71c6609b9f96a7c7859bdf05d21f", + "size": 85417, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.1/lwjgl-openal-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "831a5533a21a5f4f81bbc51bb13e9899319b5411", + "size": 921563, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "831a5533a21a5f4f81bbc51bb13e9899319b5411", + "size": 921563, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "1c528fb258a6e63e8fceb4482d8db0f3af10a634", + "size": 57908, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "1a827bc02651fa44d32f424c380edc6d53f94a62", + "size": 1274449, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.1/lwjgl-opengl-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "b119297cf8ed01f247abe8685857f8e7fcf5980f", + "size": 112380, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "b119297cf8ed01f247abe8685857f8e7fcf5980f", + "size": 112380, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "8e8348a1813aad7f30aaf75ea197151ebb7beba9", + "size": 205491, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "22cb295464f44068add8443204ec8c85fd379cbe", + "size": 103489, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.1/lwjgl-stb-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "0ff1914111ef2e3e0110ef2dabc8d8cdaad82347", + "size": 6767, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "0ff1914111ef2e3e0110ef2dabc8d8cdaad82347", + "size": 6767, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "964f628b7a82fd909def086c0dd9a4b84bb259ae", + "size": 42654, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1.jar" + }, + "sources": { + "sha1": "4784c20508b51386ce9d572632524a5bf47ccb40", + "size": 5530, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.1/lwjgl-tinyfd-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.3.1", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "ae58664f88e18a9bb2c77b063833ca7aaec484cb", + "size": 724243, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar", + "path": "org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.3.1" + }, + { + "downloads": { + "artifact": { + "sha1": "ae58664f88e18a9bb2c77b063833ca7aaec484cb", + "size": 724243, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar", + "path": "org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "b597401014acb7196c76d97e15a6288f54f1f692", + "size": 86308, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-natives-linux.jar" + }, + "sources": { + "sha1": "e918fb595d1ca293a68807a9da8b519ea348a67a", + "size": 572854, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.3.1", + "natives": { + "linux": "natives-linux" + } + } + ] +} diff --git a/assets/LWJGL/aarch64/3.3.2.json b/assets/LWJGL/aarch64/3.3.2.json new file mode 100644 index 00000000..37cb2ba3 --- /dev/null +++ b/assets/LWJGL/aarch64/3.3.2.json @@ -0,0 +1,270 @@ +{ + "libraries": [ + { + "downloads": { + "artifact": { + "sha1": "757920418805fb90bfebb3d46b1d9e7669fca2eb", + "size": 135828, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "757920418805fb90bfebb3d46b1d9e7669fca2eb", + "size": 135828, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "bc49e64bae0f7ff103a312ee8074a34c4eb034c7", + "size": 120168, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "0bdd2ae91adb35fd7809b7ecf2d677546b26fe4f", + "size": 126160, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-glfw/3.3.2/lwjgl-glfw-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-glfw:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "877e17e39ebcd58a9c956dc3b5b777813de0873a", + "size": 43233, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "877e17e39ebcd58a9c956dc3b5b777813de0873a", + "size": 43233, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "5249f18a9ae20ea86c5816bc3107a888ce7a17d2", + "size": 206402, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "1d953086a319cfb09d0703e50011849a95ab2277", + "size": 32303, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-jemalloc/3.3.2/lwjgl-jemalloc-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-jemalloc:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "ae5357ed6d934546d3533993ea84c0cfb75eed95", + "size": 108230, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-openal:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "ae5357ed6d934546d3533993ea84c0cfb75eed95", + "size": 108230, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "22408980cc579709feaf9acb807992d3ebcf693f", + "size": 590865, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "534195bc70b8ff83c270c1d618cdafe76e9be2c4", + "size": 100606, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-openal/3.3.2/lwjgl-openal-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-openal:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "ee8e95be0b438602038bc1f02dc5e3d011b1b216", + "size": 928871, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "ee8e95be0b438602038bc1f02dc5e3d011b1b216", + "size": 928871, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "bb9eb56da6d1d549d6a767218e675e36bc568eb9", + "size": 58627, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "1301ff0d9814ac96d7020f5912d5f0f72c039fca", + "size": 1275908, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-opengl/3.3.2/lwjgl-opengl-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-opengl:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "a2550795014d622b686e9caac50b14baa87d2c70", + "size": 118874, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-stb:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "a2550795014d622b686e9caac50b14baa87d2c70", + "size": 118874, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "11a380c37b0f03cb46db235e064528f84d736ff7", + "size": 207419, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "dda437f20ae0c920c1c744984b4093889982b994", + "size": 103496, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-stb/3.3.2/lwjgl-stb-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-stb:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "9f65c248dd77934105274fcf8351abb75b34327c", + "size": 13404, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "9f65c248dd77934105274fcf8351abb75b34327c", + "size": 13404, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "93f8c5bc1984963cd79109891fb5a9d1e580373e", + "size": 43381, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2.jar" + }, + "sources": { + "sha1": "bd33407b8cdbac1161c759656034d283f4708051", + "size": 5527, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl-tinyfd/3.3.2/lwjgl-tinyfd-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl-tinyfd:3.3.2", + "natives": { + "linux": "natives-linux" + } + }, + { + "downloads": { + "artifact": { + "sha1": "4421d94af68e35dcaa31737a6fc59136a1e61b94", + "size": 786196, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2.jar", + "path": "org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2.jar" + } + }, + "name": "org.lwjgl:lwjgl:3.3.2" + }, + { + "downloads": { + "artifact": { + "sha1": "4421d94af68e35dcaa31737a6fc59136a1e61b94", + "size": 786196, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2.jar", + "path": "org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2.jar" + }, + "classifiers": { + "natives-linux": { + "sha1": "8bd89332c90a90e6bc4aa997a25c05b7db02c90a", + "size": 90795, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2-natives-linux-arm64.jar", + "path": "org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2-natives-linux.jar" + }, + "sources": { + "sha1": "aff949f8180d6d1e26a47c7a2bca8163f5b987fe", + "size": 624340, + "url": "https://repo1.maven.org/maven2/org/lwjgl/lwjgl/3.3.2/lwjgl-3.3.2-sources.jar" + } + } + }, + "name": "org.lwjgl:lwjgl:3.3.2", + "natives": { + "linux": "natives-linux" + } + } + ] +} \ No newline at end of file diff --git a/assets/forge/maven-metadata.json b/assets/forge/maven-metadata.json new file mode 100644 index 00000000..a8182810 --- /dev/null +++ b/assets/forge/maven-metadata.json @@ -0,0 +1,4969 @@ +{ + "1.1": [ + "1.1-1.3.2.1", + "1.1-1.3.2.2", + "1.1-1.3.2.3", + "1.1-1.3.2.4", + "1.1-1.3.2.5", + "1.1-1.3.2.6", + "1.1-1.3.2.7", + "1.1-1.3.2.8", + "1.1-1.3.2.9", + "1.1-1.3.2.10", + "1.1-1.3.3.12", + "1.1-1.3.3.13", + "1.1-1.3.3.14", + "1.1-1.3.3.15", + "1.1-1.3.3.16", + "1.1-1.3.3.18", + "1.1-1.3.3.19", + "1.1-1.3.3.20", + "1.1-1.3.3.21", + "1.1-1.3.3.22", + "1.1-1.3.3.23", + "1.1-1.3.3.24", + "1.1-1.3.3.26", + "1.1-1.3.3.27", + "1.1-1.3.3.28", + "1.1-1.3.4.29" + ], + "1.2.3": [ + "1.2.3-1.3.4.30", + "1.2.3-1.3.4.31", + "1.2.3-1.3.4.32", + "1.2.3-1.3.4.33", + "1.2.3-1.3.4.34", + "1.2.3-1.3.4.35", + "1.2.3-1.3.4.36", + "1.2.3-1.3.4.37", + "1.2.3-1.3.4.38", + "1.2.3-1.3.4.39", + "1.2.3-1.3.4.41", + "1.2.3-1.4.0.44", + "1.2.3-1.4.0.45", + "1.2.3-1.4.0.46", + "1.2.3-1.4.0.47", + "1.2.3-1.4.0.48", + "1.2.3-1.4.0.50", + "1.2.3-1.4.0.51", + "1.2.3-1.4.0.52", + "1.2.3-1.4.0.55", + "1.2.3-1.4.0.56", + "1.2.3-1.4.0.57", + "1.2.3-1.4.1.58", + "1.2.3-1.4.1.59", + "1.2.3-1.4.1.60", + "1.2.3-1.4.1.61", + "1.2.3-1.4.1.62", + "1.2.3-1.4.1.63", + "1.2.3-1.4.1.64" + ], + "1.2.4": [ + "1.2.4-2.0.0.65", + "1.2.4-2.0.0.66", + "1.2.4-2.0.0.67", + "1.2.4-2.0.0.68" + ], + "1.2.5": [ + "1.2.5-3.0.0.69", + "1.2.5-3.0.0.70", + "1.2.5-3.0.0.71", + "1.2.5-3.0.0.72", + "1.2.5-3.0.1.73", + "1.2.5-3.0.1.74", + "1.2.5-3.0.1.75", + "1.2.5-3.0.1.77", + "1.2.5-3.0.1.78", + "1.2.5-3.0.1.79", + "1.2.5-3.0.1.80", + "1.2.5-3.0.1.81", + "1.2.5-3.0.1.82", + "1.2.5-3.0.1.83", + "1.2.5-3.0.1.84", + "1.2.5-3.0.1.85", + "1.2.5-3.0.1.86", + "1.2.5-3.0.1.87", + "1.2.5-3.0.1.88", + "1.2.5-3.0.1.89", + "1.2.5-3.1.2.90", + "1.2.5-3.1.2.91", + "1.2.5-3.1.2.92", + "1.2.5-3.1.2.93", + "1.2.5-3.1.2.94", + "1.2.5-3.1.2.95", + "1.2.5-3.1.2.96", + "1.2.5-3.1.2.97", + "1.2.5-3.1.2.98", + "1.2.5-3.1.3.99", + "1.2.5-3.1.3.100", + "1.2.5-3.1.3.101", + "1.2.5-3.1.3.102", + "1.2.5-3.1.3.103", + "1.2.5-3.1.3.104", + "1.2.5-3.1.3.105", + "1.2.5-3.1.3.106", + "1.2.5-3.1.3.107", + "1.2.5-3.2.3.108", + "1.2.5-3.2.4.110", + "1.2.5-3.2.4.111", + "1.2.5-3.2.4.114", + "1.2.5-3.2.4.115", + "1.2.5-3.2.4.116", + "1.2.5-3.2.5.117", + "1.2.5-3.2.5.118", + "1.2.5-3.2.5.119", + "1.2.5-3.2.5.120", + "1.2.5-3.2.5.121", + "1.2.5-3.2.5.122", + "1.2.5-3.2.5.123", + "1.2.5-3.2.5.124", + "1.2.5-3.2.5.125", + "1.2.5-3.2.5.126", + "1.2.5-3.2.5.127", + "1.2.5-3.2.5.128", + "1.2.5-3.2.6.129", + "1.2.5-3.2.6.130", + "1.2.5-3.2.6.131", + "1.2.5-3.2.6.132", + "1.2.5-3.3.7.133", + "1.2.5-3.3.7.134", + "1.2.5-3.3.7.135", + "1.2.5-3.3.7.136", + "1.2.5-3.3.7.137", + "1.2.5-3.3.7.138", + "1.2.5-3.3.7.139", + "1.2.5-3.3.7.140", + "1.2.5-3.3.8.141", + "1.2.5-3.3.8.142", + "1.2.5-3.3.8.143", + "1.2.5-3.3.8.144", + "1.2.5-3.3.8.145", + "1.2.5-3.3.8.146", + "1.2.5-3.3.8.147", + "1.2.5-3.3.8.148", + "1.2.5-3.3.8.150", + "1.2.5-3.3.8.151", + "1.2.5-3.3.8.152", + "1.2.5-3.3.8.153", + "1.2.5-3.3.8.154", + "1.2.5-3.3.8.155", + "1.2.5-3.3.8.156", + "1.2.5-3.3.8.157", + "1.2.5-3.3.8.158", + "1.2.5-3.3.8.159", + "1.2.5-3.3.8.160", + "1.2.5-3.3.8.161", + "1.2.5-3.3.8.162", + "1.2.5-3.3.8.163", + "1.2.5-3.3.8.164", + "1.2.5-3.3.8.168", + "1.2.5-3.3.8.170", + "1.2.5-3.4.9.171" + ], + "1.3.2": [ + "1.3.2-4.0.0.172", + "1.3.2-4.0.0.173", + "1.3.2-4.0.0.176", + "1.3.2-4.0.0.177", + "1.3.2-4.0.0.178", + "1.3.2-4.0.0.179", + "1.3.2-4.0.0.180", + "1.3.2-4.0.0.181", + "1.3.2-4.0.0.182", + "1.3.2-4.0.0.183", + "1.3.2-4.0.0.184", + "1.3.2-4.0.0.185", + "1.3.2-4.0.0.186", + "1.3.2-4.0.0.187", + "1.3.2-4.0.0.188", + "1.3.2-4.0.0.189", + "1.3.2-4.0.0.190", + "1.3.2-4.0.0.191", + "1.3.2-4.0.0.192", + "1.3.2-4.0.0.193", + "1.3.2-4.0.0.194", + "1.3.2-4.0.0.195", + "1.3.2-4.0.0.196", + "1.3.2-4.0.0.197", + "1.3.2-4.0.0.198", + "1.3.2-4.0.0.199", + "1.3.2-4.0.0.200", + "1.3.2-4.0.0.204", + "1.3.2-4.0.0.205", + "1.3.2-4.0.0.206", + "1.3.2-4.0.0.207", + "1.3.2-4.0.0.208", + "1.3.2-4.0.0.209", + "1.3.2-4.0.0.210", + "1.3.2-4.0.0.211", + "1.3.2-4.0.0.212", + "1.3.2-4.0.0.213", + "1.3.2-4.0.0.214", + "1.3.2-4.0.0.215", + "1.3.2-4.0.0.216", + "1.3.2-4.0.0.217", + "1.3.2-4.0.0.220", + "1.3.2-4.0.0.221", + "1.3.2-4.0.0.222", + "1.3.2-4.0.0.223", + "1.3.2-4.0.0.224", + "1.3.2-4.0.0.225", + "1.3.2-4.0.0.226", + "1.3.2-4.0.0.227", + "1.3.2-4.0.0.228", + "1.3.2-4.0.0.229", + "1.3.2-4.0.0.230", + "1.3.2-4.0.0.231", + "1.3.2-4.0.0.232", + "1.3.2-4.0.0.233", + "1.3.2-4.0.0.234", + "1.3.2-4.0.0.235", + "1.3.2-4.0.0.236", + "1.3.2-4.0.0.237", + "1.3.2-4.0.0.238", + "1.3.2-4.0.0.239", + "1.3.2-4.0.0.240", + "1.3.2-4.0.0.241", + "1.3.2-4.0.0.242", + "1.3.2-4.0.0.243", + "1.3.2-4.0.0.245", + "1.3.2-4.0.0.246", + "1.3.2-4.0.0.247", + "1.3.2-4.0.0.248", + "1.3.2-4.0.0.249", + "1.3.2-4.0.0.250", + "1.3.2-4.1.1.251", + "1.3.2-4.1.1.252", + "1.3.2-4.1.1.253", + "1.3.2-4.1.1.254", + "1.3.2-4.1.1.255", + "1.3.2-4.1.1.256", + "1.3.2-4.1.1.257", + "1.3.2-4.1.1.258", + "1.3.2-4.1.2.259", + "1.3.2-4.1.2.260", + "1.3.2-4.1.2.261", + "1.3.2-4.1.2.262", + "1.3.2-4.1.2.263", + "1.3.2-4.1.2.264", + "1.3.2-4.1.2.265", + "1.3.2-4.1.2.266", + "1.3.2-4.1.2.267", + "1.3.2-4.1.2.268", + "1.3.2-4.1.2.269", + "1.3.2-4.1.3.270", + "1.3.2-4.1.4.271", + "1.3.2-4.1.4.272", + "1.3.2-4.1.4.274", + "1.3.2-4.1.4.275", + "1.3.2-4.1.4.276", + "1.3.2-4.1.4.277", + "1.3.2-4.1.4.278", + "1.3.2-4.1.4.279", + "1.3.2-4.1.4.280", + "1.3.2-4.1.4.281", + "1.3.2-4.1.4.282", + "1.3.2-4.1.4.284", + "1.3.2-4.1.4.285", + "1.3.2-4.1.4.286", + "1.3.2-4.1.4.287", + "1.3.2-4.1.4.288", + "1.3.2-4.1.4.289", + "1.3.2-4.1.4.290", + "1.3.2-4.1.4.291", + "1.3.2-4.1.4.292", + "1.3.2-4.1.4.294", + "1.3.2-4.1.4.295", + "1.3.2-4.1.4.296", + "1.3.2-4.1.4.297", + "1.3.2-4.1.4.298", + "1.3.2-4.2.5.299", + "1.3.2-4.2.5.300", + "1.3.2-4.2.5.301", + "1.3.2-4.2.5.302", + "1.3.2-4.2.5.303", + "1.3.2-4.2.5.305", + "1.3.2-4.2.5.306", + "1.3.2-4.2.5.307", + "1.3.2-4.2.5.310", + "1.3.2-4.2.5.311", + "1.3.2-4.2.5.312", + "1.3.2-4.2.5.313", + "1.3.2-4.2.5.314", + "1.3.2-4.2.5.315", + "1.3.2-4.2.5.316", + "1.3.2-4.2.5.317", + "1.3.2-4.3.5.318" + ], + "1.4.0": [ + "1.4.0-5.0.0.320", + "1.4.0-5.0.0.321", + "1.4.0-5.0.0.322", + "1.4.0-5.0.0.323", + "1.4.0-5.0.0.324", + "1.4.0-5.0.0.325", + "1.4.0-5.0.0.326" + ], + "1.4.1": [ + "1.4.1-6.0.0.327", + "1.4.1-6.0.0.328", + "1.4.1-6.0.0.329" + ], + "1.4.2": [ + "1.4.2-6.0.1.330", + "1.4.2-6.0.1.331", + "1.4.2-6.0.1.332", + "1.4.2-6.0.1.336", + "1.4.2-6.0.1.337", + "1.4.2-6.0.1.338", + "1.4.2-6.0.1.339", + "1.4.2-6.0.1.341", + "1.4.2-6.0.1.342", + "1.4.2-6.0.1.343", + "1.4.2-6.0.1.345", + "1.4.2-6.0.1.347", + "1.4.2-6.0.1.348", + "1.4.2-6.0.1.349", + "1.4.2-6.0.1.350", + "1.4.2-6.0.1.351", + "1.4.2-6.0.1.353", + "1.4.2-6.0.1.354", + "1.4.2-6.0.1.355" + ], + "1.4.3": [ + "1.4.3-6.2.1.356", + "1.4.3-6.2.1.357", + "1.4.3-6.2.1.358" + ], + "1.4.4": [ + "1.4.4-6.3.0.360", + "1.4.4-6.3.0.361", + "1.4.4-6.3.0.362", + "1.4.4-6.3.0.363", + "1.4.4-6.3.0.364", + "1.4.4-6.3.0.365", + "1.4.4-6.3.0.366", + "1.4.4-6.3.0.367", + "1.4.4-6.3.0.368", + "1.4.4-6.3.0.369", + "1.4.4-6.3.0.370", + "1.4.4-6.3.0.371", + "1.4.4-6.3.0.372", + "1.4.4-6.3.0.373", + "1.4.4-6.3.0.374", + "1.4.4-6.3.0.375", + "1.4.4-6.3.0.376", + "1.4.4-6.3.0.377", + "1.4.4-6.3.0.378" + ], + "1.4.5": [ + "1.4.5-6.4.0.379", + "1.4.5-6.4.0.380", + "1.4.5-6.4.0.381", + "1.4.5-6.4.0.382", + "1.4.5-6.4.0.383", + "1.4.5-6.4.0.384", + "1.4.5-6.4.0.385", + "1.4.5-6.4.0.386", + "1.4.5-6.4.0.387", + "1.4.5-6.4.0.388", + "1.4.5-6.4.0.390", + "1.4.5-6.4.0.393", + "1.4.5-6.4.0.394", + "1.4.5-6.4.0.395", + "1.4.5-6.4.0.396", + "1.4.5-6.4.0.397", + "1.4.5-6.4.0.398", + "1.4.5-6.4.0.399", + "1.4.5-6.4.1.400", + "1.4.5-6.4.1.401", + "1.4.5-6.4.1.402", + "1.4.5-6.4.1.403", + "1.4.5-6.4.1.404", + "1.4.5-6.4.1.405", + "1.4.5-6.4.1.406", + "1.4.5-6.4.1.407", + "1.4.5-6.4.1.408", + "1.4.5-6.4.1.409", + "1.4.5-6.4.1.410", + "1.4.5-6.4.1.411", + "1.4.5-6.4.1.413", + "1.4.5-6.4.1.414", + "1.4.5-6.4.1.416", + "1.4.5-6.4.1.424", + "1.4.5-6.4.1.425", + "1.4.5-6.4.1.426", + "1.4.5-6.4.1.428", + "1.4.5-6.4.1.430", + "1.4.5-6.4.1.432", + "1.4.5-6.4.1.433", + "1.4.5-6.4.1.434", + "1.4.5-6.4.1.435", + "1.4.5-6.4.1.436", + "1.4.5-6.4.1.437", + "1.4.5-6.4.1.438", + "1.4.5-6.4.1.439", + "1.4.5-6.4.1.441", + "1.4.5-6.4.1.442", + "1.4.5-6.4.2.443", + "1.4.5-6.4.2.444", + "1.4.5-6.4.2.445", + "1.4.5-6.4.2.446", + "1.4.5-6.4.2.447", + "1.4.5-6.4.2.448" + ], + "1.4.6": [ + "1.4.6-6.5.0.451", + "1.4.6-6.5.0.452", + "1.4.6-6.5.0.453", + "1.4.6-6.5.0.454", + "1.4.6-6.5.0.455", + "1.4.6-6.5.0.456", + "1.4.6-6.5.0.457", + "1.4.6-6.5.0.458", + "1.4.6-6.5.0.459", + "1.4.6-6.5.0.460", + "1.4.6-6.5.0.461", + "1.4.6-6.5.0.462", + "1.4.6-6.5.0.463", + "1.4.6-6.5.0.464", + "1.4.6-6.5.0.465", + "1.4.6-6.5.0.466", + "1.4.6-6.5.0.467", + "1.4.6-6.5.0.468", + "1.4.6-6.5.0.469", + "1.4.6-6.5.0.470", + "1.4.6-6.5.0.471", + "1.4.6-6.5.0.472", + "1.4.6-6.5.0.473", + "1.4.6-6.5.0.474", + "1.4.6-6.5.0.475", + "1.4.6-6.5.0.476", + "1.4.6-6.5.0.477", + "1.4.6-6.5.0.478", + "1.4.6-6.5.0.479", + "1.4.6-6.5.0.480", + "1.4.6-6.5.0.481", + "1.4.6-6.5.0.482", + "1.4.6-6.5.0.483", + "1.4.6-6.5.0.484", + "1.4.6-6.5.0.486", + "1.4.6-6.5.0.487", + "1.4.6-6.5.0.488", + "1.4.6-6.5.0.489" + ], + "1.4.7": [ + "1.4.7-6.6.0.490", + "1.4.7-6.6.0.491", + "1.4.7-6.6.0.492", + "1.4.7-6.6.0.493", + "1.4.7-6.6.0.494", + "1.4.7-6.6.0.495", + "1.4.7-6.6.0.496", + "1.4.7-6.6.0.497", + "1.4.7-6.6.0.499", + "1.4.7-6.6.0.501", + "1.4.7-6.6.0.502", + "1.4.7-6.6.0.503", + "1.4.7-6.6.0.504", + "1.4.7-6.6.0.505", + "1.4.7-6.6.0.506", + "1.4.7-6.6.0.507", + "1.4.7-6.6.0.509", + "1.4.7-6.6.0.510", + "1.4.7-6.6.0.511", + "1.4.7-6.6.0.515", + "1.4.7-6.6.0.516", + "1.4.7-6.6.0.517", + "1.4.7-6.6.0.518", + "1.4.7-6.6.1.521", + "1.4.7-6.6.1.522", + "1.4.7-6.6.1.523", + "1.4.7-6.6.1.524", + "1.4.7-6.6.1.527", + "1.4.7-6.6.1.528", + "1.4.7-6.6.1.529", + "1.4.7-6.6.1.530", + "1.4.7-6.6.1.531", + "1.4.7-6.6.1.532", + "1.4.7-6.6.2.533", + "1.4.7-6.6.2.534" + ], + "1.5": [ + "1.5-7.7.0.559", + "1.5-7.7.0.560", + "1.5-7.7.0.561", + "1.5-7.7.0.562", + "1.5-7.7.0.563", + "1.5-7.7.0.565", + "1.5-7.7.0.566", + "1.5-7.7.0.567", + "1.5-7.7.0.568", + "1.5-7.7.0.569", + "1.5-7.7.0.571", + "1.5-7.7.0.572", + "1.5-7.7.0.573", + "1.5-7.7.0.574", + "1.5-7.7.0.575", + "1.5-7.7.0.576", + "1.5-7.7.0.577", + "1.5-7.7.0.578", + "1.5-7.7.0.579", + "1.5-7.7.0.580", + "1.5-7.7.0.581", + "1.5-7.7.0.582", + "1.5-7.7.0.583", + "1.5-7.7.0.584", + "1.5-7.7.0.585", + "1.5-7.7.0.586", + "1.5-7.7.0.587", + "1.5-7.7.0.588", + "1.5-7.7.0.589", + "1.5-7.7.0.590", + "1.5-7.7.0.591", + "1.5-7.7.0.592", + "1.5-7.7.0.593", + "1.5-7.7.0.594", + "1.5-7.7.0.595", + "1.5-7.7.0.598" + ], + "1.5.1": [ + "1.5.1-7.7.0.600", + "1.5.1-7.7.0.601", + "1.5.1-7.7.0.602", + "1.5.1-7.7.0.603", + "1.5.1-7.7.0.604", + "1.5.1-7.7.0.605", + "1.5.1-7.7.0.608", + "1.5.1-7.7.0.609", + "1.5.1-7.7.0.610", + "1.5.1-7.7.1.611", + "1.5.1-7.7.1.614", + "1.5.1-7.7.1.615", + "1.5.1-7.7.1.616", + "1.5.1-7.7.1.617", + "1.5.1-7.7.1.618", + "1.5.1-7.7.1.620", + "1.5.1-7.7.1.621", + "1.5.1-7.7.1.622", + "1.5.1-7.7.1.623", + "1.5.1-7.7.1.624", + "1.5.1-7.7.1.625", + "1.5.1-7.7.1.627", + "1.5.1-7.7.1.628", + "1.5.1-7.7.1.629", + "1.5.1-7.7.1.630", + "1.5.1-7.7.1.631", + "1.5.1-7.7.1.632", + "1.5.1-7.7.1.633", + "1.5.1-7.7.1.634", + "1.5.1-7.7.1.635", + "1.5.1-7.7.1.636", + "1.5.1-7.7.1.637", + "1.5.1-7.7.1.638", + "1.5.1-7.7.1.639", + "1.5.1-7.7.1.640", + "1.5.1-7.7.1.642", + "1.5.1-7.7.1.643", + "1.5.1-7.7.1.644", + "1.5.1-7.7.1.645", + "1.5.1-7.7.1.646", + "1.5.1-7.7.1.647", + "1.5.1-7.7.1.648", + "1.5.1-7.7.1.649", + "1.5.1-7.7.1.650", + "1.5.1-7.7.1.651", + "1.5.1-7.7.1.652", + "1.5.1-7.7.1.653", + "1.5.1-7.7.1.654", + "1.5.1-7.7.1.655", + "1.5.1-7.7.1.656", + "1.5.1-7.7.1.657", + "1.5.1-7.7.1.659", + "1.5.1-7.7.1.660", + "1.5.1-7.7.1.661", + "1.5.1-7.7.1.662", + "1.5.1-7.7.1.663", + "1.5.1-7.7.1.664", + "1.5.1-7.7.1.665", + "1.5.1-7.7.1.666", + "1.5.1-7.7.1.667", + "1.5.1-7.7.1.672", + "1.5.1-7.7.1.673", + "1.5.1-7.7.1.674", + "1.5.1-7.7.1.675", + "1.5.1-7.7.1.676", + "1.5.1-7.7.2.678", + "1.5.1-7.7.2.679", + "1.5.1-7.7.2.682" + ], + "1.5.2": [ + "1.5.2-7.8.0.684", + "1.5.2-7.8.0.685", + "1.5.2-7.8.0.686", + "1.5.2-7.8.0.687", + "1.5.2-7.8.0.688", + "1.5.2-7.8.0.689", + "1.5.2-7.8.0.690", + "1.5.2-7.8.0.691", + "1.5.2-7.8.0.692", + "1.5.2-7.8.0.693", + "1.5.2-7.8.0.694", + "1.5.2-7.8.0.695", + "1.5.2-7.8.0.696", + "1.5.2-7.8.0.697", + "1.5.2-7.8.0.698", + "1.5.2-7.8.0.699", + "1.5.2-7.8.0.700", + "1.5.2-7.8.0.701", + "1.5.2-7.8.0.702", + "1.5.2-7.8.0.703", + "1.5.2-7.8.0.704", + "1.5.2-7.8.0.705", + "1.5.2-7.8.0.706", + "1.5.2-7.8.0.707", + "1.5.2-7.8.0.708", + "1.5.2-7.8.0.710", + "1.5.2-7.8.0.711", + "1.5.2-7.8.0.712", + "1.5.2-7.8.0.713", + "1.5.2-7.8.0.715", + "1.5.2-7.8.0.716", + "1.5.2-7.8.0.719", + "1.5.2-7.8.0.720", + "1.5.2-7.8.0.721", + "1.5.2-7.8.0.722", + "1.5.2-7.8.0.723", + "1.5.2-7.8.0.725", + "1.5.2-7.8.0.726", + "1.5.2-7.8.0.727", + "1.5.2-7.8.0.728", + "1.5.2-7.8.0.729", + "1.5.2-7.8.0.730", + "1.5.2-7.8.0.731", + "1.5.2-7.8.0.732", + "1.5.2-7.8.0.733", + "1.5.2-7.8.0.734", + "1.5.2-7.8.0.735", + "1.5.2-7.8.0.736", + "1.5.2-7.8.1.737", + "1.5.2-7.8.1.738" + ], + "1.6.1": [ + "1.6.1-8.9.0.749", + "1.6.1-8.9.0.751", + "1.6.1-8.9.0.753", + "1.6.1-8.9.0.755", + "1.6.1-8.9.0.756", + "1.6.1-8.9.0.757", + "1.6.1-8.9.0.758", + "1.6.1-8.9.0.759", + "1.6.1-8.9.0.760", + "1.6.1-8.9.0.761", + "1.6.1-8.9.0.762", + "1.6.1-8.9.0.763", + "1.6.1-8.9.0.764", + "1.6.1-8.9.0.765", + "1.6.1-8.9.0.766", + "1.6.1-8.9.0.767", + "1.6.1-8.9.0.768", + "1.6.1-8.9.0.771", + "1.6.1-8.9.0.772", + "1.6.1-8.9.0.773", + "1.6.1-8.9.0.774", + "1.6.1-8.9.0.775" + ], + "1.6.2": [ + "1.6.2-9.10.0.776", + "1.6.2-9.10.0.777", + "1.6.2-9.10.0.778", + "1.6.2-9.10.0.779", + "1.6.2-9.10.0.780", + "1.6.2-9.10.0.781", + "1.6.2-9.10.0.784", + "1.6.2-9.10.0.785", + "1.6.2-9.10.0.786", + "1.6.2-9.10.0.787", + "1.6.2-9.10.0.789", + "1.6.2-9.10.0.790", + "1.6.2-9.10.0.791", + "1.6.2-9.10.0.792", + "1.6.2-9.10.0.793", + "1.6.2-9.10.0.794", + "1.6.2-9.10.0.795", + "1.6.2-9.10.0.796", + "1.6.2-9.10.0.797", + "1.6.2-9.10.0.798", + "1.6.2-9.10.0.799", + "1.6.2-9.10.0.800", + "1.6.2-9.10.0.801", + "1.6.2-9.10.0.802", + "1.6.2-9.10.0.803", + "1.6.2-9.10.0.804", + "1.6.2-9.10.0.816", + "1.6.2-9.10.0.817", + "1.6.2-9.10.0.818", + "1.6.2-9.10.0.819", + "1.6.2-9.10.0.820", + "1.6.2-9.10.0.821", + "1.6.2-9.10.0.822", + "1.6.2-9.10.0.823", + "1.6.2-9.10.0.824", + "1.6.2-9.10.0.825", + "1.6.2-9.10.0.826", + "1.6.2-9.10.0.827", + "1.6.2-9.10.0.828", + "1.6.2-9.10.0.829", + "1.6.2-9.10.0.830", + "1.6.2-9.10.0.831", + "1.6.2-9.10.0.832", + "1.6.2-9.10.0.833", + "1.6.2-9.10.0.834", + "1.6.2-9.10.0.835", + "1.6.2-9.10.0.836", + "1.6.2-9.10.0.837", + "1.6.2-9.10.0.838", + "1.6.2-9.10.0.839", + "1.6.2-9.10.0.840", + "1.6.2-9.10.0.841", + "1.6.2-9.10.0.842", + "1.6.2-9.10.0.843", + "1.6.2-9.10.0.844", + "1.6.2-9.10.0.845", + "1.6.2-9.10.0.846", + "1.6.2-9.10.0.847", + "1.6.2-9.10.0.848", + "1.6.2-9.10.1.849", + "1.6.2-9.10.1.850", + "1.6.2-9.10.1.851", + "1.6.2-9.10.1.852", + "1.6.2-9.10.1.853", + "1.6.2-9.10.1.854", + "1.6.2-9.10.1.855", + "1.6.2-9.10.1.856", + "1.6.2-9.10.1.857", + "1.6.2-9.10.1.858", + "1.6.2-9.10.1.859", + "1.6.2-9.10.1.860", + "1.6.2-9.10.1.861", + "1.6.2-9.10.1.862", + "1.6.2-9.10.1.863", + "1.6.2-9.10.1.864", + "1.6.2-9.10.1.865", + "1.6.2-9.10.1.866", + "1.6.2-9.10.1.867", + "1.6.2-9.10.1.869", + "1.6.2-9.10.1.870", + "1.6.2-9.10.1.871" + ], + "1.6.3": [ + "1.6.3-9.11.0.873", + "1.6.3-9.11.0.874", + "1.6.3-9.11.0.875", + "1.6.3-9.11.0.876", + "1.6.3-9.11.0.877", + "1.6.3-9.11.0.878" + ], + "1.6.4": [ + "1.6.4-9.11.0.879", + "1.6.4-9.11.0.880", + "1.6.4-9.11.0.881", + "1.6.4-9.11.0.882", + "1.6.4-9.11.0.883", + "1.6.4-9.11.0.884", + "1.6.4-9.11.0.885", + "1.6.4-9.11.0.886", + "1.6.4-9.11.0.891", + "1.6.4-9.11.0.892", + "1.6.4-9.11.0.893", + "1.6.4-9.11.0.894", + "1.6.4-9.11.0.895", + "1.6.4-9.11.0.896", + "1.6.4-9.11.0.897", + "1.6.4-9.11.0.898", + "1.6.4-9.11.0.899", + "1.6.4-9.11.0.900", + "1.6.4-9.11.0.901", + "1.6.4-9.11.0.902", + "1.6.4-9.11.0.903", + "1.6.4-9.11.0.904", + "1.6.4-9.11.0.905", + "1.6.4-9.11.0.906", + "1.6.4-9.11.0.907", + "1.6.4-9.11.0.908", + "1.6.4-9.11.0.909", + "1.6.4-9.11.0.910", + "1.6.4-9.11.0.911", + "1.6.4-9.11.0.912", + "1.6.4-9.11.0.913", + "1.6.4-9.11.1.914", + "1.6.4-9.11.1.915", + "1.6.4-9.11.1.916", + "1.6.4-9.11.1.917", + "1.6.4-9.11.1.918", + "1.6.4-9.11.1.919", + "1.6.4-9.11.1.920", + "1.6.4-9.11.1.921", + "1.6.4-9.11.1.922", + "1.6.4-9.11.1.923", + "1.6.4-9.11.1.924", + "1.6.4-9.11.1.925", + "1.6.4-9.11.1.926", + "1.6.4-9.11.1.928", + "1.6.4-9.11.1.930", + "1.6.4-9.11.1.931", + "1.6.4-9.11.1.933", + "1.6.4-9.11.1.934", + "1.6.4-9.11.1.935", + "1.6.4-9.11.1.937", + "1.6.4-9.11.1.938", + "1.6.4-9.11.1.939", + "1.6.4-9.11.1.940", + "1.6.4-9.11.1.941", + "1.6.4-9.11.1.942", + "1.6.4-9.11.1.943", + "1.6.4-9.11.1.944", + "1.6.4-9.11.1.945", + "1.6.4-9.11.1.946", + "1.6.4-9.11.1.947", + "1.6.4-9.11.1.948", + "1.6.4-9.11.1.949", + "1.6.4-9.11.1.951", + "1.6.4-9.11.1.952", + "1.6.4-9.11.1.960", + "1.6.4-9.11.1.961", + "1.6.4-9.11.1.963", + "1.6.4-9.11.1.964", + "1.6.4-9.11.1.953", + "1.6.4-9.11.1.965", + "1.6.4-9.11.1.1345" + ], + "1.7.2": [ + "1.7.2-10.12.0.967", + "1.7.2-10.12.0.968", + "1.7.2-10.12.0.969", + "1.7.2-10.12.0.970", + "1.7.2-10.12.0.971", + "1.7.2-10.12.0.972", + "1.7.2-10.12.0.973", + "1.7.2-10.12.0.974", + "1.7.2-10.12.0.975", + "1.7.2-10.12.0.976", + "1.7.2-10.12.0.977", + "1.7.2-10.12.0.979", + "1.7.2-10.12.0.980", + "1.7.2-10.12.0.981", + "1.7.2-10.12.0.982", + "1.7.2-10.12.0.984", + "1.7.2-10.12.0.985", + "1.7.2-10.12.0.986", + "1.7.2-10.12.0.987", + "1.7.2-10.12.0.989", + "1.7.2-10.12.0.990", + "1.7.2-10.12.0.991", + "1.7.2-10.12.0.993", + "1.7.2-10.12.0.994", + "1.7.2-10.12.0.995", + "1.7.2-10.12.0.996", + "1.7.2-10.12.0.997", + "1.7.2-10.12.0.998", + "1.7.2-10.12.0.999", + "1.7.2-10.12.0.1000", + "1.7.2-10.12.0.1001", + "1.7.2-10.12.0.1002", + "1.7.2-10.12.0.1003", + "1.7.2-10.12.0.1004", + "1.7.2-10.12.0.1005", + "1.7.2-10.12.0.1006", + "1.7.2-10.12.0.1007", + "1.7.2-10.12.0.1008", + "1.7.2-10.12.0.1009", + "1.7.2-10.12.0.1010", + "1.7.2-10.12.0.1011", + "1.7.2-10.12.0.1012", + "1.7.2-10.12.0.1013", + "1.7.2-10.12.0.1014", + "1.7.2-10.12.0.1015", + "1.7.2-10.12.0.1016", + "1.7.2-10.12.0.1017", + "1.7.2-10.12.0.1018", + "1.7.2-10.12.0.1019", + "1.7.2-10.12.0.1020", + "1.7.2-10.12.0.1021", + "1.7.2-10.12.0.1022", + "1.7.2-10.12.0.1023", + "1.7.2-10.12.0.1024", + "1.7.2-10.12.0.1025", + "1.7.2-10.12.0.1026", + "1.7.2-10.12.0.1027", + "1.7.2-10.12.0.1028", + "1.7.2-10.12.0.1029", + "1.7.2-10.12.0.1030", + "1.7.2-10.12.0.1031", + "1.7.2-10.12.0.1032", + "1.7.2-10.12.0.1033", + "1.7.2-10.12.0.1034", + "1.7.2-10.12.0.1039", + "1.7.2-10.12.0.1040", + "1.7.2-10.12.0.1041", + "1.7.2-10.12.0.1042", + "1.7.2-10.12.0.1043", + "1.7.2-10.12.0.1044", + "1.7.2-10.12.0.1045", + "1.7.2-10.12.0.1046", + "1.7.2-10.12.0.1047", + "1.7.2-10.12.0.1048", + "1.7.2-10.12.0.1049", + "1.7.2-10.12.0.1050", + "1.7.2-10.12.0.1051", + "1.7.2-10.12.0.1052", + "1.7.2-10.12.0.1053", + "1.7.2-10.12.0.1054", + "1.7.2-10.12.0.1055", + "1.7.2-10.12.0.1056", + "1.7.2-10.12.0.1057", + "1.7.2-10.12.0.1058", + "1.7.2-10.12.0.1059", + "1.7.2-10.12.1.1060", + "1.7.2-10.12.1.1061", + "1.7.2-10.12.1.1063", + "1.7.2-10.12.1.1065", + "1.7.2-10.12.1.1066", + "1.7.2-10.12.1.1067", + "1.7.2-10.12.1.1068", + "1.7.2-10.12.1.1069", + "1.7.2-10.12.1.1070", + "1.7.2-10.12.1.1071", + "1.7.2-10.12.1.1072", + "1.7.2-10.12.1.1073", + "1.7.2-10.12.1.1074", + "1.7.2-10.12.1.1075", + "1.7.2-10.12.1.1076", + "1.7.2-10.12.1.1077", + "1.7.2-10.12.1.1078", + "1.7.2-10.12.1.1079", + "1.7.2-10.12.1.1080", + "1.7.2-10.12.1.1081", + "1.7.2-10.12.1.1082", + "1.7.2-10.12.1.1083", + "1.7.2-10.12.1.1084", + "1.7.2-10.12.1.1085", + "1.7.2-10.12.1.1087", + "1.7.2-10.12.1.1088", + "1.7.2-10.12.1.1090", + "1.7.2-10.12.1.1091", + "1.7.2-10.12.1.1092", + "1.7.2-10.12.1.1093", + "1.7.2-10.12.1.1094", + "1.7.2-10.12.1.1095", + "1.7.2-10.12.1.1096", + "1.7.2-10.12.1.1097", + "1.7.2-10.12.1.1098", + "1.7.2-10.12.1.1099", + "1.7.2-10.12.1.1100", + "1.7.2-10.12.1.1101", + "1.7.2-10.12.1.1103", + "1.7.2-10.12.1.1104", + "1.7.2-10.12.1.1105", + "1.7.2-10.12.1.1106", + "1.7.2-10.12.1.1107", + "1.7.2-10.12.1.1108", + "1.7.2-10.12.1.1109", + "1.7.2-10.12.1.1110", + "1.7.2-10.12.1.1111", + "1.7.2-10.12.1.1112", + "1.7.2-10.12.1.1113", + "1.7.2-10.12.1.1114", + "1.7.2-10.12.1.1115", + "1.7.2-10.12.1.1116", + "1.7.2-10.12.1.1117", + "1.7.2-10.12.1.1118", + "1.7.2-10.12.1.1119", + "1.7.2-10.12.1.1120", + "1.7.2-10.12.2.1121", + "1.7.2-10.12.2.1122", + "1.7.2-10.12.2.1123", + "1.7.2-10.12.2.1124", + "1.7.2-10.12.2.1125", + "1.7.2-10.12.2.1126", + "1.7.2-10.12.2.1127", + "1.7.2-10.12.2.1128", + "1.7.2-10.12.2.1129", + "1.7.2-10.12.2.1130", + "1.7.2-10.12.2.1131", + "1.7.2-10.12.2.1132", + "1.7.2-10.12.2.1133", + "1.7.2-10.12.2.1145", + "1.7.2-10.12.2.1147", + "1.7.2-10.12.2.1154-mc172", + "1.7.2-10.12.2.1155-mc172", + "1.7.2-10.12.2.1161-mc172" + ], + "1.7.10_pre4": [ + "1.7.10_pre4-10.12.2.1137-prerelease", + "1.7.10_pre4-10.12.2.1138-prerelease", + "1.7.10_pre4-10.12.2.1139-prerelease", + "1.7.10_pre4-10.12.2.1141-prerelease", + "1.7.10_pre4-10.12.2.1142-prerelease", + "1.7.10_pre4-10.12.2.1143-prerelease", + "1.7.10_pre4-10.12.2.1144-prerelease", + "1.7.10_pre4-10.12.2.1146-prerelease", + "1.7.10_pre4-10.12.2.1148-prerelease", + "1.7.10_pre4-10.12.2.1149-prerelease" + ], + "1.7.10": [ + "1.7.10-10.13.0.1150", + "1.7.10-10.13.0.1151", + "1.7.10-10.13.0.1152", + "1.7.10-10.13.0.1153", + "1.7.10-10.13.0.1156", + "1.7.10-10.13.0.1157", + "1.7.10-10.13.0.1158", + "1.7.10-10.13.0.1159", + "1.7.10-10.13.0.1160", + "1.7.10-10.13.0.1162", + "1.7.10-10.13.0.1166", + "1.7.10-10.13.0.1167", + "1.7.10-10.13.0.1168", + "1.7.10-10.13.0.1169", + "1.7.10-10.13.0.1170", + "1.7.10-10.13.0.1171", + "1.7.10-10.13.0.1172", + "1.7.10-10.13.0.1174", + "1.7.10-10.13.0.1175", + "1.7.10-10.13.0.1176", + "1.7.10-10.13.0.1177", + "1.7.10-10.13.0.1178", + "1.7.10-10.13.0.1179", + "1.7.10-10.13.0.1180", + "1.7.10-10.13.0.1181", + "1.7.10-10.13.0.1182", + "1.7.10-10.13.0.1183", + "1.7.10-10.13.0.1184", + "1.7.10-10.13.0.1185", + "1.7.10-10.13.0.1186", + "1.7.10-10.13.0.1187", + "1.7.10-10.13.0.1188", + "1.7.10-10.13.0.1189", + "1.7.10-10.13.0.1190", + "1.7.10-10.13.0.1191", + "1.7.10-10.13.0.1194", + "1.7.10-10.13.0.1195", + "1.7.10-10.13.0.1197", + "1.7.10-10.13.0.1198", + "1.7.10-10.13.0.1199", + "1.7.10-10.13.0.1200", + "1.7.10-10.13.0.1201", + "1.7.10-10.13.0.1202", + "1.7.10-10.13.0.1203", + "1.7.10-10.13.0.1204", + "1.7.10-10.13.0.1205", + "1.7.10-10.13.0.1206", + "1.7.10-10.13.0.1207", + "1.7.10-10.13.0.1208", + "1.7.10-10.13.1.1210-new", + "1.7.10-10.13.1.1211-new", + "1.7.10-10.13.1.1212-new", + "1.7.10-10.13.1.1213-new", + "1.7.10-10.13.1.1214-new", + "1.7.10-10.13.1.1215-new", + "1.7.10-10.13.1.1216-new", + "1.7.10-10.13.1.1217", + "1.7.10-10.13.1.1219", + "1.7.10-10.13.1.1220", + "1.7.10-10.13.1.1221", + "1.7.10-10.13.1.1222", + "1.7.10-10.13.1.1223", + "1.7.10-10.13.1.1224", + "1.7.10-10.13.1.1225", + "1.7.10-10.13.1.1226", + "1.7.10-10.13.1.1229", + "1.7.10-10.13.2.1230", + "1.7.10-10.13.2.1231", + "1.7.10-10.13.2.1232", + "1.7.10-10.13.2.1233", + "1.7.10-10.13.2.1234", + "1.7.10-10.13.2.1235", + "1.7.10-10.13.2.1236", + "1.7.10-10.13.2.1240", + "1.7.10-10.13.2.1253", + "1.7.10-10.13.2.1254", + "1.7.10-10.13.2.1256", + "1.7.10-10.13.2.1258", + "1.7.10-10.13.2.1263", + "1.7.10-10.13.2.1264", + "1.7.10-10.13.2.1270", + "1.7.10-10.13.2.1272", + "1.7.10-10.13.2.1275", + "1.7.10-10.13.2.1276", + "1.7.10-10.13.2.1277", + "1.7.10-10.13.2.1283", + "1.7.10-10.13.2.1284", + "1.7.10-10.13.2.1286", + "1.7.10-10.13.2.1291", + "1.7.10-10.13.2.1300-1.7.10", + "1.7.10-10.13.2.1307-1.7.10", + "1.7.10-10.13.2.1340-1.7.10", + "1.7.10-10.13.2.1342-1.7.10", + "1.7.10-10.13.2.1343-1.7.10", + "1.7.10-10.13.2.1346-1.7.10", + "1.7.10-10.13.2.1347-1.7.10", + "1.7.10-10.13.2.1351-1.7.10", + "1.7.10-10.13.2.1352-1.7.10", + "1.7.10-10.13.3.1355-1.7.10", + "1.7.10-10.13.3.1356-1.7.10", + "1.7.10-10.13.3.1358-1.7.10", + "1.7.10-10.13.3.1360-1.7.10", + "1.7.10-10.13.3.1362-1.7.10", + "1.7.10-10.13.3.1363-1.7.10", + "1.7.10-10.13.3.1364-1.7.10", + "1.7.10-10.13.3.1365-1.7.10", + "1.7.10-10.13.3.1366-1.7.10", + "1.7.10-10.13.3.1367-1.7.10", + "1.7.10-10.13.3.1368-1.7.10", + "1.7.10-10.13.3.1369-1.7.10", + "1.7.10-10.13.3.1370-1.7.10", + "1.7.10-10.13.3.1372-1.7.10", + "1.7.10-10.13.3.1373-1.7.10", + "1.7.10-10.13.3.1374-1.7.10", + "1.7.10-10.13.3.1376-1.7.10", + "1.7.10-10.13.3.1377-1.7.10", + "1.7.10-10.13.3.1378-1.7.10", + "1.7.10-10.13.3.1379-1.7.10", + "1.7.10-10.13.3.1380-1.7.10", + "1.7.10-10.13.3.1381-1.7.10", + "1.7.10-10.13.3.1382-1.7.10", + "1.7.10-10.13.3.1383-1.7.10", + "1.7.10-10.13.3.1384-1.7.10", + "1.7.10-10.13.3.1385-1.7.10", + "1.7.10-10.13.3.1387-1.7.10", + "1.7.10-10.13.3.1388-1.7.10", + "1.7.10-10.13.3.1389-1710ls", + "1.7.10-10.13.3.1391-1710ls", + "1.7.10-10.13.3.1393-1710ls", + "1.7.10-10.13.3.1394-1710ls", + "1.7.10-10.13.3.1395-1710ls", + "1.7.10-10.13.3.1399-1.7.10", + "1.7.10-10.13.3.1400-1.7.10", + "1.7.10-10.13.3.1401-1710ls", + "1.7.10-10.13.3.1403-1.7.10", + "1.7.10-10.13.3.1406-1.7.10", + "1.7.10-10.13.3.1407-1.7.10", + "1.7.10-10.13.3.1408-1.7.10", + "1.7.10-10.13.3.1420-1.7.10", + "1.7.10-10.13.3.1422-1.7.10", + "1.7.10-10.13.3.1424-1.7.10", + "1.7.10-10.13.3.1428-1.7.10", + "1.7.10-10.13.4.1445-1.7.10", + "1.7.10-10.13.4.1447-1.7.10", + "1.7.10-10.13.4.1448-1.7.10", + "1.7.10-10.13.4.1451-1.7.10", + "1.7.10-10.13.4.1452-1.7.10", + "1.7.10-10.13.4.1456-1.7.10", + "1.7.10-10.13.4.1469-1.7.10", + "1.7.10-10.13.4.1470-1.7.10", + "1.7.10-10.13.4.1472-1.7.10", + "1.7.10-10.13.4.1481-1.7.10", + "1.7.10-10.13.4.1490-1.7.10", + "1.7.10-10.13.4.1492-1.7.10", + "1.7.10-10.13.4.1517-1.7.10", + "1.7.10-10.13.4.1539-1.7.10", + "1.7.10-10.13.4.1540-1.7.10", + "1.7.10-10.13.4.1541-1.7.10", + "1.7.10-10.13.4.1557-1.7.10", + "1.7.10-10.13.4.1558-1.7.10", + "1.7.10-10.13.4.1564-1.7.10", + "1.7.10-10.13.4.1566-1.7.10", + "1.7.10-10.13.4.1614-1.7.10" + ], + "1.8": [ + "1.8-11.14.0.1237-1.8", + "1.8-11.14.0.1238-1.8", + "1.8-11.14.0.1239-1.8", + "1.8-11.14.0.1241-1.8", + "1.8-11.14.0.1242-1.8", + "1.8-11.14.0.1243-1.8", + "1.8-11.14.0.1244-1.8", + "1.8-11.14.0.1245-1.8", + "1.8-11.14.0.1246-1.8", + "1.8-11.14.0.1247-1.8", + "1.8-11.14.0.1248-1.8", + "1.8-11.14.0.1249-1.8", + "1.8-11.14.0.1251-1.8", + "1.8-11.14.0.1252-1.8", + "1.8-11.14.0.1255-1.8", + "1.8-11.14.0.1257-1.8", + "1.8-11.14.0.1259-1.8", + "1.8-11.14.0.1260-1.8", + "1.8-11.14.0.1261-1.8", + "1.8-11.14.0.1262-1.8", + "1.8-11.14.0.1265-1.8", + "1.8-11.14.0.1266-1.8", + "1.8-11.14.0.1267-1.8", + "1.8-11.14.0.1268-1.8", + "1.8-11.14.0.1269-1.8", + "1.8-11.14.0.1271-1.8", + "1.8-11.14.0.1273-1.8", + "1.8-11.14.0.1274-1.8", + "1.8-11.14.0.1278-1.8", + "1.8-11.14.0.1279-1.8", + "1.8-11.14.0.1280-1.8", + "1.8-11.14.0.1281-1.8", + "1.8-11.14.0.1282-1.8", + "1.8-11.14.0.1285-1.8", + "1.8-11.14.0.1287-1.8", + "1.8-11.14.0.1288-1.8", + "1.8-11.14.0.1289-1.8", + "1.8-11.14.0.1290-1.8", + "1.8-11.14.0.1292-1.8", + "1.8-11.14.0.1293-1.8", + "1.8-11.14.0.1294-1.8", + "1.8-11.14.0.1295-1.8", + "1.8-11.14.0.1296", + "1.8-11.14.0.1297", + "1.8-11.14.0.1298", + "1.8-11.14.0.1299", + "1.8-11.14.1.1301", + "1.8-11.14.1.1302", + "1.8-11.14.1.1303", + "1.8-11.14.1.1305", + "1.8-11.14.1.1306", + "1.8-11.14.1.1308", + "1.8-11.14.1.1309", + "1.8-11.14.1.1310", + "1.8-11.14.1.1311", + "1.8-11.14.1.1312", + "1.8-11.14.1.1313", + "1.8-11.14.1.1314", + "1.8-11.14.1.1315", + "1.8-11.14.1.1316", + "1.8-11.14.1.1317", + "1.8-11.14.1.1318", + "1.8-11.14.1.1319", + "1.8-11.14.1.1320", + "1.8-11.14.1.1321", + "1.8-11.14.1.1322", + "1.8-11.14.1.1323", + "1.8-11.14.1.1324", + "1.8-11.14.1.1325", + "1.8-11.14.1.1326", + "1.8-11.14.1.1327", + "1.8-11.14.1.1328", + "1.8-11.14.1.1329", + "1.8-11.14.1.1332", + "1.8-11.14.1.1333", + "1.8-11.14.1.1334", + "1.8-11.14.1.1335", + "1.8-11.14.1.1336", + "1.8-11.14.1.1337", + "1.8-11.14.1.1338", + "1.8-11.14.1.1339", + "1.8-11.14.1.1341", + "1.8-11.14.1.1349", + "1.8-11.14.1.1350", + "1.8-11.14.1.1353", + "1.8-11.14.1.1354", + "1.8-11.14.1.1357", + "1.8-11.14.1.1359", + "1.8-11.14.1.1361", + "1.8-11.14.1.1371", + "1.8-11.14.1.1375", + "1.8-11.14.1.1390", + "1.8-11.14.1.1392", + "1.8-11.14.1.1396", + "1.8-11.14.1.1397", + "1.8-11.14.1.1398", + "1.8-11.14.1.1402", + "1.8-11.14.1.1404", + "1.8-11.14.1.1405", + "1.8-11.14.1.1409", + "1.8-11.14.1.1410", + "1.8-11.14.1.1411", + "1.8-11.14.1.1412", + "1.8-11.14.1.1413", + "1.8-11.14.1.1414", + "1.8-11.14.1.1415", + "1.8-11.14.1.1416", + "1.8-11.14.1.1417", + "1.8-11.14.1.1418", + "1.8-11.14.1.1419", + "1.8-11.14.2.1421", + "1.8-11.14.2.1423", + "1.8-11.14.2.1426", + "1.8-11.14.2.1427", + "1.8-11.14.2.1429", + "1.8-11.14.2.1430", + "1.8-11.14.2.1431", + "1.8-11.14.2.1433", + "1.8-11.14.2.1434", + "1.8-11.14.2.1435", + "1.8-11.14.2.1436", + "1.8-11.14.2.1437", + "1.8-11.14.2.1439", + "1.8-11.14.2.1440", + "1.8-11.14.2.1441", + "1.8-11.14.2.1442", + "1.8-11.14.2.1443", + "1.8-11.14.2.1444", + "1.8-11.14.3.1446", + "1.8-11.14.3.1449", + "1.8-11.14.3.1450", + "1.8-11.14.3.1453", + "1.8-11.14.3.1457", + "1.8-11.14.3.1458", + "1.8-11.14.3.1459", + "1.8-11.14.3.1460", + "1.8-11.14.3.1461", + "1.8-11.14.3.1462", + "1.8-11.14.3.1463", + "1.8-11.14.3.1464", + "1.8-11.14.3.1465", + "1.8-11.14.3.1466", + "1.8-11.14.3.1467", + "1.8-11.14.3.1468", + "1.8-11.14.3.1473", + "1.8-11.14.3.1474", + "1.8-11.14.3.1475", + "1.8-11.14.3.1476", + "1.8-11.14.3.1479", + "1.8-11.14.3.1480", + "1.8-11.14.3.1482", + "1.8-11.14.3.1483", + "1.8-11.14.3.1484", + "1.8-11.14.3.1485", + "1.8-11.14.3.1486", + "1.8-11.14.3.1487", + "1.8-11.14.3.1491", + "1.8-11.14.3.1493", + "1.8-11.14.3.1494", + "1.8-11.14.3.1495", + "1.8-11.14.3.1496", + "1.8-11.14.3.1497", + "1.8-11.14.3.1498", + "1.8-11.14.3.1499", + "1.8-11.14.3.1500", + "1.8-11.14.3.1501", + "1.8-11.14.3.1502", + "1.8-11.14.3.1503", + "1.8-11.14.3.1504", + "1.8-11.14.3.1505", + "1.8-11.14.3.1506", + "1.8-11.14.3.1507", + "1.8-11.14.3.1508", + "1.8-11.14.3.1509", + "1.8-11.14.3.1510", + "1.8-11.14.3.1511", + "1.8-11.14.3.1512", + "1.8-11.14.3.1513", + "1.8-11.14.3.1514", + "1.8-11.14.3.1515", + "1.8-11.14.3.1516", + "1.8-11.14.3.1518", + "1.8-11.14.3.1519", + "1.8-11.14.3.1520", + "1.8-11.14.3.1521", + "1.8-11.14.3.1523", + "1.8-11.14.3.1524", + "1.8-11.14.3.1525", + "1.8-11.14.3.1526", + "1.8-11.14.3.1529", + "1.8-11.14.3.1530", + "1.8-11.14.3.1531", + "1.8-11.14.3.1532", + "1.8-11.14.3.1533", + "1.8-11.14.3.1534", + "1.8-11.14.3.1535", + "1.8-11.14.3.1542", + "1.8-11.14.3.1543", + "1.8-11.14.3.1544", + "1.8-11.14.3.1545", + "1.8-11.14.3.1546", + "1.8-11.14.3.1547", + "1.8-11.14.3.1548", + "1.8-11.14.3.1549", + "1.8-11.14.3.1550", + "1.8-11.14.3.1551", + "1.8-11.14.3.1552", + "1.8-11.14.3.1553", + "1.8-11.14.3.1554", + "1.8-11.14.3.1555", + "1.8-11.14.3.1556", + "1.8-11.14.3.1559", + "1.8-11.14.3.1560", + "1.8-11.14.3.1561", + "1.8-11.14.3.1562", + "1.8-11.14.4.1563", + "1.8-11.14.4.1565", + "1.8-11.14.4.1568", + "1.8-11.14.4.1569", + "1.8-11.14.4.1570", + "1.8-11.14.4.1571", + "1.8-11.14.4.1572", + "1.8-11.14.4.1577" + ], + "1.8.8": [ + "1.8.8-11.14.4.1575-1.8.8", + "1.8.8-11.14.4.1576-1.8.8", + "1.8.8-11.14.4.1579-1.8.8", + "1.8.8-11.14.4.1580-1.8.8", + "1.8.8-11.14.4.1581-1.8.8", + "1.8.8-11.14.4.1582-1.8.8", + "1.8.8-11.14.4.1583-1.8.8", + "1.8.8-11.14.4.1584-1.8.8", + "1.8.8-11.14.4.1585-1.8.8", + "1.8.8-11.14.4.1586-1.8.8", + "1.8.8-11.14.4.1587-1.8.8", + "1.8.8-11.14.4.1588-1.8.8", + "1.8.8-11.14.4.1589-1.8.8", + "1.8.8-11.14.4.1590-1.8.8", + "1.8.8-11.15.0.1591-1.8.8", + "1.8.8-11.15.0.1592-1.8.8", + "1.8.8-11.15.0.1594-1.8.8", + "1.8.8-11.15.0.1595-1.8.8", + "1.8.8-11.15.0.1596-1.8.8", + "1.8.8-11.15.0.1600-1.8.8", + "1.8.8-11.15.0.1601-1.8.8", + "1.8.8-11.15.0.1602-1.8.8", + "1.8.8-11.15.0.1603-1.8.8", + "1.8.8-11.15.0.1604-1.8.8", + "1.8.8-11.15.0.1605-1.8.8", + "1.8.8-11.15.0.1606-1.8.8", + "1.8.8-11.15.0.1607-1.8.8", + "1.8.8-11.15.0.1608-1.8.8", + "1.8.8-11.15.0.1609-1.8.8", + "1.8.8-11.15.0.1610-1.8.8", + "1.8.8-11.15.0.1611-1.8.8", + "1.8.8-11.15.0.1612-1.8.8", + "1.8.8-11.15.0.1613-1.8.8", + "1.8.8-11.15.0.1615-1.8.8", + "1.8.8-11.15.0.1616-1.8.8", + "1.8.8-11.15.0.1617-1.8.8", + "1.8.8-11.15.0.1618-1.8.8", + "1.8.8-11.15.0.1619-1.8.8", + "1.8.8-11.15.0.1620-1.8.8", + "1.8.8-11.15.0.1621-1.8.8", + "1.8.8-11.15.0.1622-1.8.8", + "1.8.8-11.15.0.1623-1.8.8", + "1.8.8-11.15.0.1624-1.8.8", + "1.8.8-11.15.0.1625-1.8.8", + "1.8.8-11.15.0.1626-1.8.8", + "1.8.8-11.15.0.1627-1.8.8", + "1.8.8-11.15.0.1628-1.8.8", + "1.8.8-11.15.0.1630-1.8.8", + "1.8.8-11.15.0.1632-1.8.8", + "1.8.8-11.15.0.1633-1.8.8", + "1.8.8-11.15.0.1634-1.8.8", + "1.8.8-11.15.0.1635-1.8.8", + "1.8.8-11.15.0.1636-1.8.8", + "1.8.8-11.15.0.1637-1.8.8", + "1.8.8-11.15.0.1638-1.8.8", + "1.8.8-11.15.0.1639-1.8.8", + "1.8.8-11.15.0.1640-1.8.8", + "1.8.8-11.15.0.1641-1.8.8", + "1.8.8-11.15.0.1642-1.8.8", + "1.8.8-11.15.0.1643-1.8.8", + "1.8.8-11.15.0.1644-1.8.8", + "1.8.8-11.15.0.1645-1.8.8", + "1.8.8-11.15.0.1646-1.8.8", + "1.8.8-11.15.0.1647-1.8.8", + "1.8.8-11.15.0.1649-1.8.8", + "1.8.8-11.15.0.1650-1.8.8", + "1.8.8-11.15.0.1651-1.8.8", + "1.8.8-11.15.0.1652-1.8.8", + "1.8.8-11.15.0.1653-1.8.8", + "1.8.8-11.15.0.1654-1.8.8", + "1.8.8-11.15.0.1655" + ], + "1.8.9": [ + "1.8.9-11.15.0.1656", + "1.8.9-11.15.0.1657", + "1.8.9-11.15.0.1658", + "1.8.9-11.15.0.1659", + "1.8.9-11.15.0.1661", + "1.8.9-11.15.0.1662", + "1.8.9-11.15.0.1663", + "1.8.9-11.15.0.1664", + "1.8.9-11.15.0.1665", + "1.8.9-11.15.0.1666", + "1.8.9-11.15.0.1668", + "1.8.9-11.15.0.1669", + "1.8.9-11.15.0.1670", + "1.8.9-11.15.0.1671", + "1.8.9-11.15.0.1672", + "1.8.9-11.15.0.1673", + "1.8.9-11.15.0.1674", + "1.8.9-11.15.0.1675", + "1.8.9-11.15.0.1676", + "1.8.9-11.15.0.1677", + "1.8.9-11.15.0.1681", + "1.8.9-11.15.0.1682", + "1.8.9-11.15.0.1683", + "1.8.9-11.15.0.1684", + "1.8.9-11.15.0.1686", + "1.8.9-11.15.0.1687", + "1.8.9-11.15.0.1688", + "1.8.9-11.15.0.1689", + "1.8.9-11.15.0.1690", + "1.8.9-11.15.0.1691", + "1.8.9-11.15.0.1692", + "1.8.9-11.15.0.1693", + "1.8.9-11.15.0.1694", + "1.8.9-11.15.0.1695", + "1.8.9-11.15.0.1696", + "1.8.9-11.15.0.1697", + "1.8.9-11.15.0.1698", + "1.8.9-11.15.0.1699", + "1.8.9-11.15.0.1700", + "1.8.9-11.15.0.1701", + "1.8.9-11.15.0.1702", + "1.8.9-11.15.0.1703", + "1.8.9-11.15.0.1705", + "1.8.9-11.15.0.1706", + "1.8.9-11.15.0.1707", + "1.8.9-11.15.0.1708", + "1.8.9-11.15.0.1709", + "1.8.9-11.15.0.1710", + "1.8.9-11.15.0.1711", + "1.8.9-11.15.0.1712", + "1.8.9-11.15.0.1713", + "1.8.9-11.15.0.1714", + "1.8.9-11.15.0.1715", + "1.8.9-11.15.0.1716", + "1.8.9-11.15.0.1718", + "1.8.9-11.15.0.1719", + "1.8.9-11.15.0.1720", + "1.8.9-11.15.0.1721", + "1.8.9-11.15.1.1722", + "1.8.9-11.15.1.1723", + "1.8.9-11.15.1.1724", + "1.8.9-11.15.1.1725", + "1.8.9-11.15.1.1726", + "1.8.9-11.15.1.1727", + "1.8.9-11.15.1.1729", + "1.8.9-11.15.1.1730", + "1.8.9-11.15.1.1731", + "1.8.9-11.15.1.1732", + "1.8.9-11.15.1.1733", + "1.8.9-11.15.1.1734", + "1.8.9-11.15.1.1735", + "1.8.9-11.15.1.1736", + "1.8.9-11.15.1.1737", + "1.8.9-11.15.1.1738", + "1.8.9-11.15.1.1739", + "1.8.9-11.15.1.1740", + "1.8.9-11.15.1.1741", + "1.8.9-11.15.1.1742", + "1.8.9-11.15.1.1743", + "1.8.9-11.15.1.1744", + "1.8.9-11.15.1.1745", + "1.8.9-11.15.1.1746", + "1.8.9-11.15.1.1747", + "1.8.9-11.15.1.1748", + "1.8.9-11.15.1.1749", + "1.8.9-11.15.1.1750", + "1.8.9-11.15.1.1751", + "1.8.9-11.15.1.1752", + "1.8.9-11.15.1.1754", + "1.8.9-11.15.1.1755", + "1.8.9-11.15.1.1756", + "1.8.9-11.15.1.1757", + "1.8.9-11.15.1.1758", + "1.8.9-11.15.1.1759", + "1.8.9-11.15.1.1760", + "1.8.9-11.15.1.1761", + "1.8.9-11.15.1.1762", + "1.8.9-11.15.1.1763", + "1.8.9-11.15.1.1764", + "1.8.9-11.15.1.1765", + "1.8.9-11.15.1.1777", + "1.8.9-11.15.1.1783", + "1.8.9-11.15.1.1785", + "1.8.9-11.15.1.1791", + "1.8.9-11.15.1.1794", + "1.8.9-11.15.1.1808", + "1.8.9-11.15.1.1847", + "1.8.9-11.15.1.1855", + "1.8.9-11.15.1.1872", + "1.8.9-11.15.1.1873", + "1.8.9-11.15.1.1875", + "1.8.9-11.15.1.1890-1.8.9", + "1.8.9-11.15.1.1902-1.8.9", + "1.8.9-11.15.1.2318-1.8.9" + ], + "1.9": [ + "1.9-12.16.0.1766-1.9", + "1.9-12.16.0.1767-1.9", + "1.9-12.16.0.1768-1.9", + "1.9-12.16.0.1769-1.9", + "1.9-12.16.0.1770-1.9", + "1.9-12.16.0.1771-1.9", + "1.9-12.16.0.1772-1.9", + "1.9-12.16.0.1773-1.9", + "1.9-12.16.0.1774-1.9", + "1.9-12.16.0.1775-1.9", + "1.9-12.16.0.1776-1.9", + "1.9-12.16.0.1778-1.9", + "1.9-12.16.0.1779-1.9", + "1.9-12.16.0.1780-1.9", + "1.9-12.16.0.1781-1.9", + "1.9-12.16.0.1782-1.9", + "1.9-12.16.0.1784-1.9", + "1.9-12.16.0.1786-1.9", + "1.9-12.16.0.1787-1.9", + "1.9-12.16.0.1788-1.9", + "1.9-12.16.0.1789-1.9", + "1.9-12.16.0.1790-1.9", + "1.9-12.16.0.1792-1.9", + "1.9-12.16.0.1793-1.9", + "1.9-12.16.0.1795-1.9", + "1.9-12.16.0.1796-1.9", + "1.9-12.16.0.1797-1.9", + "1.9-12.16.0.1798-1.9", + "1.9-12.16.0.1799-1.9", + "1.9-12.16.0.1800-1.9", + "1.9-12.16.0.1801-1.9", + "1.9-12.16.0.1802-1.9", + "1.9-12.16.0.1803-1.9", + "1.9-12.16.0.1804-1.9", + "1.9-12.16.0.1805-1.9", + "1.9-12.16.0.1806-1.9", + "1.9-12.16.0.1807-1.9", + "1.9-12.16.0.1809-1.9", + "1.9-12.16.0.1810-1.9", + "1.9-12.16.0.1811-1.9", + "1.9-12.16.0.1812-1.9", + "1.9-12.16.0.1813-1.9", + "1.9-12.16.0.1814-1.9", + "1.9-12.16.0.1815-1.9", + "1.9-12.16.0.1816-1.9", + "1.9-12.16.0.1817-1.9", + "1.9-12.16.0.1819-1.9", + "1.9-12.16.0.1820-1.9", + "1.9-12.16.0.1821-1.9", + "1.9-12.16.0.1822-1.9", + "1.9-12.16.0.1823-1.9", + "1.9-12.16.0.1824-1.9", + "1.9-12.16.0.1825-1.9", + "1.9-12.16.0.1826-1.9", + "1.9-12.16.0.1827-1.9", + "1.9-12.16.0.1828-1.9", + "1.9-12.16.0.1829-1.9", + "1.9-12.16.0.1830-1.9", + "1.9-12.16.0.1831-1.9", + "1.9-12.16.0.1832-1.9", + "1.9-12.16.0.1833-1.9", + "1.9-12.16.0.1834-1.9", + "1.9-12.16.0.1835-1.9", + "1.9-12.16.0.1836-1.9", + "1.9-12.16.0.1837-1.9", + "1.9-12.16.0.1838-1.9", + "1.9-12.16.0.1839-1.9", + "1.9-12.16.0.1840-1.9", + "1.9-12.16.0.1841-1.9", + "1.9-12.16.0.1842-1.9", + "1.9-12.16.0.1843-1.9", + "1.9-12.16.0.1844-1.9", + "1.9-12.16.0.1845-1.9", + "1.9-12.16.0.1846-1.9", + "1.9-12.16.0.1848-1.9", + "1.9-12.16.0.1849-1.9", + "1.9-12.16.0.1850-1.9", + "1.9-12.16.0.1851-1.9", + "1.9-12.16.0.1852-1.9", + "1.9-12.16.0.1853-1.9", + "1.9-12.16.0.1854-1.9", + "1.9-12.16.0.1856-1.9", + "1.9-12.16.0.1857-1.9", + "1.9-12.16.0.1858-1.9", + "1.9-12.16.0.1859-1.9", + "1.9-12.16.0.1860-1.9", + "1.9-12.16.0.1861-1.9", + "1.9-12.16.0.1862-1.9", + "1.9-12.16.0.1863-1.9", + "1.9-12.16.0.1864-1.9", + "1.9-12.16.0.1865-1.9", + "1.9-12.16.0.1866-1.9", + "1.9-12.16.0.1867-1.9", + "1.9-12.16.0.1868-1.9", + "1.9-12.16.0.1869-1.9", + "1.9-12.16.0.1870-1.9", + "1.9-12.16.0.1871-1.9", + "1.9-12.16.0.1874-1.9", + "1.9-12.16.0.1877-1.9", + "1.9-12.16.0.1878-1.9", + "1.9-12.16.0.1879-1.9", + "1.9-12.16.0.1880-1.9", + "1.9-12.16.0.1881-1.9", + "1.9-12.16.0.1882-1.9", + "1.9-12.16.0.1883-1.9", + "1.9-12.16.0.1884-1.9", + "1.9-12.16.0.1885-1.9", + "1.9-12.16.0.1886", + "1.9-12.16.1.1887", + "1.9-12.16.1.1888", + "1.9-12.16.1.1889", + "1.9-12.16.1.1891", + "1.9-12.16.1.1892", + "1.9-12.16.1.1893", + "1.9-12.16.1.1894", + "1.9-12.16.1.1895", + "1.9-12.16.1.1896", + "1.9-12.16.1.1897", + "1.9-12.16.1.1898", + "1.9-12.16.1.1899", + "1.9-12.16.1.1900", + "1.9-12.16.1.1901", + "1.9-12.16.1.1904", + "1.9-12.16.1.1905", + "1.9-12.16.1.1906", + "1.9-12.16.1.1907", + "1.9-12.16.1.1923", + "1.9-12.16.1.1934", + "1.9-12.16.1.1938-1.9.0" + ], + "1.9.4": [ + "1.9.4-12.17.0.1908-1.9.4", + "1.9.4-12.17.0.1909-1.9.4", + "1.9.4-12.17.0.1910-1.9.4", + "1.9.4-12.17.0.1912-1.9.4", + "1.9.4-12.17.0.1913-1.9.4", + "1.9.4-12.17.0.1914-1.9.4", + "1.9.4-12.17.0.1915-1.9.4", + "1.9.4-12.17.0.1916-1.9.4", + "1.9.4-12.17.0.1917-1.9.4", + "1.9.4-12.17.0.1918-1.9.4", + "1.9.4-12.17.0.1919-EHUnit", + "1.9.4-12.17.0.1920-1.9.4", + "1.9.4-12.17.0.1921-1.9.4", + "1.9.4-12.17.0.1922-1.9.4", + "1.9.4-12.17.0.1924-1.9.4", + "1.9.4-12.17.0.1925-1.9.4", + "1.9.4-12.17.0.1926-1.9.4", + "1.9.4-12.17.0.1927-1.9.4", + "1.9.4-12.17.0.1928-1.9.4", + "1.9.4-12.17.0.1929-1.9.4", + "1.9.4-12.17.0.1930-1.9.4", + "1.9.4-12.17.0.1931-1.9.4", + "1.9.4-12.17.0.1932-1.9.4", + "1.9.4-12.17.0.1933-1.9.4", + "1.9.4-12.17.0.1935-1.9.4", + "1.9.4-12.17.0.1936-1.9.4", + "1.9.4-12.17.0.1937", + "1.9.4-12.17.0.1939", + "1.9.4-12.17.0.1940", + "1.9.4-12.17.0.1941", + "1.9.4-12.17.0.1943", + "1.9.4-12.17.0.1944", + "1.9.4-12.17.0.1945", + "1.9.4-12.17.0.1946", + "1.9.4-12.17.0.1947", + "1.9.4-12.17.0.1948", + "1.9.4-12.17.0.1949", + "1.9.4-12.17.0.1950", + "1.9.4-12.17.0.1951", + "1.9.4-12.17.0.1952", + "1.9.4-12.17.0.1953", + "1.9.4-12.17.0.1954", + "1.9.4-12.17.0.1955", + "1.9.4-12.17.0.1956", + "1.9.4-12.17.0.1957", + "1.9.4-12.17.0.1958", + "1.9.4-12.17.0.1959", + "1.9.4-12.17.0.1960", + "1.9.4-12.17.0.1961", + "1.9.4-12.17.0.1962", + "1.9.4-12.17.0.1963", + "1.9.4-12.17.0.1964", + "1.9.4-12.17.0.1965", + "1.9.4-12.17.0.1966", + "1.9.4-12.17.0.1967", + "1.9.4-12.17.0.1968", + "1.9.4-12.17.0.1969", + "1.9.4-12.17.0.1970", + "1.9.4-12.17.0.1972", + "1.9.4-12.17.0.1973", + "1.9.4-12.17.0.1974-1.9.4", + "1.9.4-12.17.0.1975", + "1.9.4-12.17.0.1976", + "1.9.4-12.17.0.1987", + "1.9.4-12.17.0.1990", + "1.9.4-12.17.0.2051", + "1.9.4-12.17.0.2317-1.9.4" + ], + "1.10": [ + "1.10-12.18.0.1981-1.10.0", + "1.10-12.18.0.1982-1.10.0", + "1.10-12.18.0.1983-1.10.0", + "1.10-12.18.0.1984-1.10.0", + "1.10-12.18.0.1985-1.10.0", + "1.10-12.18.0.1986-1.10.0", + "1.10-12.18.0.1988-1.10.0", + "1.10-12.18.0.1989-1.10.0", + "1.10-12.18.0.1991-1.10.0", + "1.10-12.18.0.1992-1.10.0", + "1.10-12.18.0.1993-1.10.0", + "1.10-12.18.0.1994-1.10.0", + "1.10-12.18.0.1995-1.10.0", + "1.10-12.18.0.1996-1.10.0", + "1.10-12.18.0.1997-1.10.0", + "1.10-12.18.0.1998-1.10.0", + "1.10-12.18.0.1999-1.10.0", + "1.10-12.18.0.2000-1.10.0" + ], + "1.10.2": [ + "1.10.2-12.18.0.2001-1.10.0", + "1.10.2-12.18.0.2002-1.10.0", + "1.10.2-12.18.0.2003-1.10.0", + "1.10.2-12.18.0.2004-1.10.0", + "1.10.2-12.18.0.2005-1.10.0", + "1.10.2-12.18.0.2006-1.10.0", + "1.10.2-12.18.0.2007-1.10.0", + "1.10.2-12.18.0.2008", + "1.10.2-12.18.0.2009", + "1.10.2-12.18.0.2010", + "1.10.2-12.18.1.2011", + "1.10.2-12.18.1.2012", + "1.10.2-12.18.1.2013", + "1.10.2-12.18.1.2014", + "1.10.2-12.18.1.2015-failtests", + "1.10.2-12.18.1.2016-failtests", + "1.10.2-12.18.1.2017", + "1.10.2-12.18.1.2018", + "1.10.2-12.18.1.2019", + "1.10.2-12.18.1.2020", + "1.10.2-12.18.1.2021", + "1.10.2-12.18.1.2022", + "1.10.2-12.18.1.2023", + "1.10.2-12.18.1.2024", + "1.10.2-12.18.1.2025", + "1.10.2-12.18.1.2026", + "1.10.2-12.18.1.2027", + "1.10.2-12.18.1.2028", + "1.10.2-12.18.1.2029", + "1.10.2-12.18.1.2030", + "1.10.2-12.18.1.2031", + "1.10.2-12.18.1.2032", + "1.10.2-12.18.1.2033", + "1.10.2-12.18.1.2034", + "1.10.2-12.18.1.2035", + "1.10.2-12.18.1.2036", + "1.10.2-12.18.1.2037", + "1.10.2-12.18.1.2038", + "1.10.2-12.18.1.2039", + "1.10.2-12.18.1.2040", + "1.10.2-12.18.1.2041", + "1.10.2-12.18.1.2042", + "1.10.2-12.18.1.2043", + "1.10.2-12.18.1.2044", + "1.10.2-12.18.1.2045", + "1.10.2-12.18.1.2046", + "1.10.2-12.18.1.2047", + "1.10.2-12.18.1.2048", + "1.10.2-12.18.1.2049", + "1.10.2-12.18.1.2050", + "1.10.2-12.18.1.2052", + "1.10.2-12.18.1.2053", + "1.10.2-12.18.1.2054", + "1.10.2-12.18.1.2055", + "1.10.2-12.18.1.2056", + "1.10.2-12.18.1.2057", + "1.10.2-12.18.1.2058", + "1.10.2-12.18.1.2059", + "1.10.2-12.18.1.2060", + "1.10.2-12.18.1.2061", + "1.10.2-12.18.1.2062", + "1.10.2-12.18.1.2063", + "1.10.2-12.18.1.2064", + "1.10.2-12.18.1.2065", + "1.10.2-12.18.1.2066", + "1.10.2-12.18.1.2067", + "1.10.2-12.18.1.2068", + "1.10.2-12.18.1.2069", + "1.10.2-12.18.1.2070", + "1.10.2-12.18.1.2071", + "1.10.2-12.18.1.2072", + "1.10.2-12.18.1.2073", + "1.10.2-12.18.1.2074", + "1.10.2-12.18.1.2075", + "1.10.2-12.18.1.2076", + "1.10.2-12.18.1.2077", + "1.10.2-12.18.1.2078", + "1.10.2-12.18.1.2079", + "1.10.2-12.18.1.2080", + "1.10.2-12.18.1.2081", + "1.10.2-12.18.1.2082", + "1.10.2-12.18.1.2083", + "1.10.2-12.18.1.2084", + "1.10.2-12.18.1.2085", + "1.10.2-12.18.1.2086", + "1.10.2-12.18.1.2087", + "1.10.2-12.18.1.2088", + "1.10.2-12.18.1.2089", + "1.10.2-12.18.1.2090", + "1.10.2-12.18.1.2091", + "1.10.2-12.18.1.2092", + "1.10.2-12.18.1.2093", + "1.10.2-12.18.1.2094", + "1.10.2-12.18.1.2095", + "1.10.2-12.18.1.2096", + "1.10.2-12.18.2.2097", + "1.10.2-12.18.2.2098", + "1.10.2-12.18.2.2099", + "1.10.2-12.18.2.2100", + "1.10.2-12.18.2.2101", + "1.10.2-12.18.2.2102", + "1.10.2-12.18.2.2103", + "1.10.2-12.18.2.2104", + "1.10.2-12.18.2.2105", + "1.10.2-12.18.2.2106", + "1.10.2-12.18.2.2107", + "1.10.2-12.18.2.2108", + "1.10.2-12.18.2.2109", + "1.10.2-12.18.2.2110", + "1.10.2-12.18.2.2111", + "1.10.2-12.18.2.2112", + "1.10.2-12.18.2.2113", + "1.10.2-12.18.2.2114", + "1.10.2-12.18.2.2115", + "1.10.2-12.18.2.2116", + "1.10.2-12.18.2.2117", + "1.10.2-12.18.2.2118", + "1.10.2-12.18.2.2119", + "1.10.2-12.18.2.2120", + "1.10.2-12.18.2.2121", + "1.10.2-12.18.2.2122", + "1.10.2-12.18.2.2123", + "1.10.2-12.18.2.2124", + "1.10.2-12.18.2.2125", + "1.10.2-12.18.2.2132", + "1.10.2-12.18.2.2134", + "1.10.2-12.18.2.2139", + "1.10.2-12.18.2.2140", + "1.10.2-12.18.2.2147", + "1.10.2-12.18.2.2151", + "1.10.2-12.18.2.2166", + "1.10.2-12.18.2.2170", + "1.10.2-12.18.2.2171", + "1.10.2-12.18.2.2179", + "1.10.2-12.18.2.2182", + "1.10.2-12.18.2.2183", + "1.10.2-12.18.3.2185", + "1.10.2-12.18.3.2202", + "1.10.2-12.18.3.2209", + "1.10.2-12.18.3.2215", + "1.10.2-12.18.3.2217", + "1.10.2-12.18.3.2219", + "1.10.2-12.18.3.2221", + "1.10.2-12.18.3.2234", + "1.10.2-12.18.3.2239", + "1.10.2-12.18.3.2254", + "1.10.2-12.18.3.2272", + "1.10.2-12.18.3.2281", + "1.10.2-12.18.3.2297", + "1.10.2-12.18.3.2316", + "1.10.2-12.18.3.2422", + "1.10.2-12.18.3.2477", + "1.10.2-12.18.3.2488", + "1.10.2-12.18.3.2511" + ], + "1.11": [ + "1.11-13.19.0.2126-1.11.x", + "1.11-13.19.0.2127-1.11.x", + "1.11-13.19.0.2128-1.11.x", + "1.11-13.19.0.2129-1.11.x", + "1.11-13.19.0.2130", + "1.11-13.19.0.2131", + "1.11-13.19.0.2133", + "1.11-13.19.0.2135", + "1.11-13.19.0.2136", + "1.11-13.19.0.2137", + "1.11-13.19.0.2138", + "1.11-13.19.0.2141", + "1.11-13.19.0.2142", + "1.11-13.19.0.2143", + "1.11-13.19.0.2144", + "1.11-13.19.0.2145", + "1.11-13.19.0.2146", + "1.11-13.19.0.2148", + "1.11-13.19.0.2149", + "1.11-13.19.0.2150", + "1.11-13.19.0.2152", + "1.11-13.19.0.2153", + "1.11-13.19.0.2154", + "1.11-13.19.0.2155", + "1.11-13.19.0.2156", + "1.11-13.19.0.2157", + "1.11-13.19.0.2159", + "1.11-13.19.0.2160", + "1.11-13.19.0.2161", + "1.11-13.19.0.2162", + "1.11-13.19.0.2163", + "1.11-13.19.0.2164", + "1.11-13.19.0.2165", + "1.11-13.19.0.2167", + "1.11-13.19.0.2168", + "1.11-13.19.0.2169", + "1.11-13.19.0.2172", + "1.11-13.19.0.2173", + "1.11-13.19.0.2174", + "1.11-13.19.0.2175", + "1.11-13.19.0.2176", + "1.11-13.19.0.2177", + "1.11-13.19.0.2178", + "1.11-13.19.0.2180", + "1.11-13.19.0.2181", + "1.11-13.19.0.2184", + "1.11-13.19.0.2186", + "1.11-13.19.0.2187", + "1.11-13.19.1.2188", + "1.11-13.19.1.2189", + "1.11-13.19.1.2190", + "1.11-13.19.1.2191", + "1.11-13.19.1.2192", + "1.11-13.19.1.2193", + "1.11-13.19.1.2194", + "1.11-13.19.1.2195", + "1.11-13.19.1.2196", + "1.11-13.19.1.2197", + "1.11-13.19.1.2198", + "1.11-13.19.1.2199" + ], + "1.11.2": [ + "1.11.2-13.20.0.2200", + "1.11.2-13.20.0.2201", + "1.11.2-13.20.0.2203", + "1.11.2-13.20.0.2204", + "1.11.2-13.20.0.2205", + "1.11.2-13.20.0.2206", + "1.11.2-13.20.0.2207", + "1.11.2-13.20.0.2208", + "1.11.2-13.20.0.2210", + "1.11.2-13.20.0.2211", + "1.11.2-13.20.0.2212", + "1.11.2-13.20.0.2213", + "1.11.2-13.20.0.2214", + "1.11.2-13.20.0.2216", + "1.11.2-13.20.0.2218", + "1.11.2-13.20.0.2220", + "1.11.2-13.20.0.2222", + "1.11.2-13.20.0.2223", + "1.11.2-13.20.0.2224", + "1.11.2-13.20.0.2225", + "1.11.2-13.20.0.2226", + "1.11.2-13.20.0.2227", + "1.11.2-13.20.0.2228", + "1.11.2-13.20.0.2229", + "1.11.2-13.20.0.2230", + "1.11.2-13.20.0.2231", + "1.11.2-13.20.0.2232", + "1.11.2-13.20.0.2233", + "1.11.2-13.20.0.2235", + "1.11.2-13.20.0.2236", + "1.11.2-13.20.0.2237", + "1.11.2-13.20.0.2238", + "1.11.2-13.20.0.2240", + "1.11.2-13.20.0.2241", + "1.11.2-13.20.0.2242", + "1.11.2-13.20.0.2243", + "1.11.2-13.20.0.2244", + "1.11.2-13.20.0.2245-3630", + "1.11.2-13.20.0.2246", + "1.11.2-13.20.0.2247", + "1.11.2-13.20.0.2248", + "1.11.2-13.20.0.2249", + "1.11.2-13.20.0.2250", + "1.11.2-13.20.0.2251", + "1.11.2-13.20.0.2252", + "1.11.2-13.20.0.2253", + "1.11.2-13.20.0.2255", + "1.11.2-13.20.0.2256", + "1.11.2-13.20.0.2257", + "1.11.2-13.20.0.2258", + "1.11.2-13.20.0.2259", + "1.11.2-13.20.0.2260", + "1.11.2-13.20.0.2261", + "1.11.2-13.20.0.2262", + "1.11.2-13.20.0.2263", + "1.11.2-13.20.0.2264", + "1.11.2-13.20.0.2265", + "1.11.2-13.20.0.2266", + "1.11.2-13.20.0.2267", + "1.11.2-13.20.0.2268", + "1.11.2-13.20.0.2269", + "1.11.2-13.20.0.2270", + "1.11.2-13.20.0.2271", + "1.11.2-13.20.0.2273", + "1.11.2-13.20.0.2274", + "1.11.2-13.20.0.2276", + "1.11.2-13.20.0.2277", + "1.11.2-13.20.0.2278", + "1.11.2-13.20.0.2279", + "1.11.2-13.20.0.2280", + "1.11.2-13.20.0.2282", + "1.11.2-13.20.0.2283", + "1.11.2-13.20.0.2284", + "1.11.2-13.20.0.2285", + "1.11.2-13.20.0.2286", + "1.11.2-13.20.0.2287", + "1.11.2-13.20.0.2288", + "1.11.2-13.20.0.2289", + "1.11.2-13.20.0.2290", + "1.11.2-13.20.0.2291", + "1.11.2-13.20.0.2292", + "1.11.2-13.20.0.2293", + "1.11.2-13.20.0.2294", + "1.11.2-13.20.0.2295", + "1.11.2-13.20.0.2296", + "1.11.2-13.20.0.2298", + "1.11.2-13.20.0.2299", + "1.11.2-13.20.0.2300", + "1.11.2-13.20.0.2301", + "1.11.2-13.20.0.2302", + "1.11.2-13.20.0.2303", + "1.11.2-13.20.0.2304", + "1.11.2-13.20.0.2305", + "1.11.2-13.20.0.2306", + "1.11.2-13.20.0.2307", + "1.11.2-13.20.0.2308", + "1.11.2-13.20.0.2309", + "1.11.2-13.20.0.2310", + "1.11.2-13.20.0.2311", + "1.11.2-13.20.0.2312", + "1.11.2-13.20.0.2313", + "1.11.2-13.20.0.2314", + "1.11.2-13.20.0.2315", + "1.11.2-13.20.0.2345", + "1.11.2-13.20.0.2356", + "1.11.2-13.20.0.2366", + "1.11.2-13.20.1.2386", + "1.11.2-13.20.1.2388", + "1.11.2-13.20.1.2391", + "1.11.2-13.20.1.2393", + "1.11.2-13.20.1.2414", + "1.11.2-13.20.1.2421", + "1.11.2-13.20.1.2425", + "1.11.2-13.20.1.2429", + "1.11.2-13.20.1.2454", + "1.11.2-13.20.1.2476", + "1.11.2-13.20.1.2504", + "1.11.2-13.20.1.2505", + "1.11.2-13.20.1.2506", + "1.11.2-13.20.1.2507", + "1.11.2-13.20.1.2510", + "1.11.2-13.20.1.2513", + "1.11.2-13.20.1.2516", + "1.11.2-13.20.1.2530", + "1.11.2-13.20.1.2563", + "1.11.2-13.20.1.2579", + "1.11.2-13.20.1.2588" + ], + "1.12": [ + "1.12-14.21.0.2320", + "1.12-14.21.0.2321", + "1.12-14.21.0.2322", + "1.12-14.21.0.2323", + "1.12-14.21.0.2324", + "1.12-14.21.0.2325", + "1.12-14.21.0.2326", + "1.12-14.21.0.2327", + "1.12-14.21.0.2328", + "1.12-14.21.0.2329", + "1.12-14.21.0.2330", + "1.12-14.21.0.2331", + "1.12-14.21.0.2332", + "1.12-14.21.0.2333", + "1.12-14.21.0.2334", + "1.12-14.21.0.2335", + "1.12-14.21.0.2336", + "1.12-14.21.0.2337", + "1.12-14.21.0.2338", + "1.12-14.21.0.2339", + "1.12-14.21.0.2340", + "1.12-14.21.0.2341", + "1.12-14.21.0.2342", + "1.12-14.21.0.2343", + "1.12-14.21.0.2344", + "1.12-14.21.0.2346", + "1.12-14.21.0.2347", + "1.12-14.21.0.2348", + "1.12-14.21.0.2349", + "1.12-14.21.0.2350", + "1.12-14.21.0.2351", + "1.12-14.21.0.2352", + "1.12-14.21.0.2353", + "1.12-14.21.0.2354", + "1.12-14.21.0.2355", + "1.12-14.21.0.2357", + "1.12-14.21.0.2358", + "1.12-14.21.0.2359", + "1.12-14.21.0.2360", + "1.12-14.21.0.2361", + "1.12-14.21.0.2362", + "1.12-14.21.0.2363", + "1.12-14.21.0.2364", + "1.12-14.21.0.2365", + "1.12-14.21.0.2367", + "1.12-14.21.0.2368", + "1.12-14.21.0.2369", + "1.12-14.21.0.2370", + "1.12-14.21.0.2371", + "1.12-14.21.0.2372", + "1.12-14.21.0.2373", + "1.12-14.21.0.2374", + "1.12-14.21.0.2375", + "1.12-14.21.0.2376", + "1.12-14.21.0.2377", + "1.12-14.21.0.2378", + "1.12-14.21.0.2379", + "1.12-14.21.0.2380", + "1.12-14.21.0.2381", + "1.12-14.21.0.2382", + "1.12-14.21.0.2383", + "1.12-14.21.0.2384", + "1.12-14.21.0.2385", + "1.12-14.21.1.2387", + "1.12-14.21.1.2389", + "1.12-14.21.1.2390", + "1.12-14.21.1.2392", + "1.12-14.21.1.2394", + "1.12-14.21.1.2395", + "1.12-14.21.1.2396", + "1.12-14.21.1.2397", + "1.12-14.21.1.2398", + "1.12-14.21.1.2399", + "1.12-14.21.1.2400", + "1.12-14.21.1.2401", + "1.12-14.21.1.2402", + "1.12-14.21.1.2403", + "1.12-14.21.1.2404", + "1.12-14.21.1.2405", + "1.12-14.21.1.2406", + "1.12-14.21.1.2407", + "1.12-14.21.1.2408", + "1.12-14.21.1.2409", + "1.12-14.21.1.2410", + "1.12-14.21.1.2411", + "1.12-14.21.1.2412", + "1.12-14.21.1.2413", + "1.12-14.21.1.2415", + "1.12-14.21.1.2416", + "1.12-14.21.1.2417", + "1.12-14.21.1.2418", + "1.12-14.21.1.2419", + "1.12-14.21.1.2420", + "1.12-14.21.1.2423", + "1.12-14.21.1.2424", + "1.12-14.21.1.2426", + "1.12-14.21.1.2427", + "1.12-14.21.1.2428", + "1.12-14.21.1.2430", + "1.12-14.21.1.2431", + "1.12-14.21.1.2432", + "1.12-14.21.1.2433", + "1.12-14.21.1.2434", + "1.12-14.21.1.2435", + "1.12-14.21.1.2436", + "1.12-14.21.1.2437", + "1.12-14.21.1.2438", + "1.12-14.21.1.2439", + "1.12-14.21.1.2440", + "1.12-14.21.1.2441", + "1.12-14.21.1.2442", + "1.12-14.21.1.2443" + ], + "1.12.1": [ + "1.12.1-14.22.0.2444", + "1.12.1-14.22.0.2445", + "1.12.1-14.22.0.2446", + "1.12.1-14.22.0.2447", + "1.12.1-14.22.0.2448", + "1.12.1-14.22.0.2449", + "1.12.1-14.22.0.2450", + "1.12.1-14.22.0.2451", + "1.12.1-14.22.0.2452", + "1.12.1-14.22.0.2453", + "1.12.1-14.22.0.2455", + "1.12.1-14.22.0.2456", + "1.12.1-14.22.0.2457", + "1.12.1-14.22.0.2458", + "1.12.1-14.22.0.2459", + "1.12.1-14.22.0.2460", + "1.12.1-14.22.0.2461", + "1.12.1-14.22.0.2462", + "1.12.1-14.22.0.2463", + "1.12.1-14.22.0.2464", + "1.12.1-14.22.0.2465", + "1.12.1-14.22.0.2466", + "1.12.1-14.22.0.2467", + "1.12.1-14.22.0.2468", + "1.12.1-14.22.0.2469", + "1.12.1-14.22.0.2470", + "1.12.1-14.22.0.2471", + "1.12.1-14.22.0.2472", + "1.12.1-14.22.0.2473", + "1.12.1-14.22.0.2474", + "1.12.1-14.22.0.2475", + "1.12.1-14.22.1.2478", + "1.12.1-14.22.1.2479", + "1.12.1-14.22.1.2480", + "1.12.1-14.22.1.2481", + "1.12.1-14.22.1.2482", + "1.12.1-14.22.1.2483", + "1.12.1-14.22.1.2484", + "1.12.1-14.22.1.2485" + ], + "1.12.2": [ + "1.12.2-14.23.0.2486", + "1.12.2-14.23.0.2487", + "1.12.2-14.23.0.2489", + "1.12.2-14.23.0.2490", + "1.12.2-14.23.0.2491", + "1.12.2-14.23.0.2492", + "1.12.2-14.23.0.2493", + "1.12.2-14.23.0.2494", + "1.12.2-14.23.0.2495", + "1.12.2-14.23.0.2496", + "1.12.2-14.23.0.2497", + "1.12.2-14.23.0.2498", + "1.12.2-14.23.0.2499", + "1.12.2-14.23.0.2500", + "1.12.2-14.23.0.2501", + "1.12.2-14.23.0.2502", + "1.12.2-14.23.0.2503", + "1.12.2-14.23.0.2508", + "1.12.2-14.23.0.2509", + "1.12.2-14.23.0.2512", + "1.12.2-14.23.0.2514", + "1.12.2-14.23.0.2515", + "1.12.2-14.23.0.2517", + "1.12.2-14.23.0.2518", + "1.12.2-14.23.0.2519", + "1.12.2-14.23.0.2520", + "1.12.2-14.23.0.2521", + "1.12.2-14.23.0.2522", + "1.12.2-14.23.0.2523", + "1.12.2-14.23.0.2524", + "1.12.2-14.23.0.2525", + "1.12.2-14.23.0.2526", + "1.12.2-14.23.0.2527", + "1.12.2-14.23.0.2528", + "1.12.2-14.23.0.2529", + "1.12.2-14.23.0.2531", + "1.12.2-14.23.0.2532", + "1.12.2-14.23.0.2533", + "1.12.2-14.23.0.2534", + "1.12.2-14.23.0.2535", + "1.12.2-14.23.0.2536", + "1.12.2-14.23.0.2537", + "1.12.2-14.23.0.2538", + "1.12.2-14.23.0.2539", + "1.12.2-14.23.0.2540", + "1.12.2-14.23.0.2541", + "1.12.2-14.23.0.2542", + "1.12.2-14.23.0.2543", + "1.12.2-14.23.0.2544", + "1.12.2-14.23.0.2545", + "1.12.2-14.23.0.2546", + "1.12.2-14.23.0.2547", + "1.12.2-14.23.0.2548", + "1.12.2-14.23.0.2549", + "1.12.2-14.23.0.2550", + "1.12.2-14.23.0.2551", + "1.12.2-14.23.0.2552", + "1.12.2-14.23.0.2553", + "1.12.2-14.23.1.2554", + "1.12.2-14.23.1.2555", + "1.12.2-14.23.1.2556", + "1.12.2-14.23.1.2557", + "1.12.2-14.23.1.2558", + "1.12.2-14.23.1.2559", + "1.12.2-14.23.1.2560", + "1.12.2-14.23.1.2561", + "1.12.2-14.23.1.2562", + "1.12.2-14.23.1.2564", + "1.12.2-14.23.1.2565", + "1.12.2-14.23.1.2566", + "1.12.2-14.23.1.2567", + "1.12.2-14.23.1.2568", + "1.12.2-14.23.1.2569", + "1.12.2-14.23.1.2570", + "1.12.2-14.23.1.2571", + "1.12.2-14.23.1.2572", + "1.12.2-14.23.1.2573", + "1.12.2-14.23.1.2574", + "1.12.2-14.23.1.2575", + "1.12.2-14.23.1.2576", + "1.12.2-14.23.1.2577", + "1.12.2-14.23.1.2578", + "1.12.2-14.23.1.2580", + "1.12.2-14.23.1.2581", + "1.12.2-14.23.1.2582", + "1.12.2-14.23.1.2583", + "1.12.2-14.23.1.2584", + "1.12.2-14.23.1.2585", + "1.12.2-14.23.1.2586", + "1.12.2-14.23.1.2587", + "1.12.2-14.23.1.2589", + "1.12.2-14.23.1.2590", + "1.12.2-14.23.1.2591", + "1.12.2-14.23.1.2592", + "1.12.2-14.23.1.2593", + "1.12.2-14.23.1.2594", + "1.12.2-14.23.1.2595", + "1.12.2-14.23.1.2596", + "1.12.2-14.23.1.2597", + "1.12.2-14.23.1.2598", + "1.12.2-14.23.1.2599", + "1.12.2-14.23.1.2600", + "1.12.2-14.23.1.2601", + "1.12.2-14.23.1.2602", + "1.12.2-14.23.1.2603", + "1.12.2-14.23.1.2604", + "1.12.2-14.23.1.2605", + "1.12.2-14.23.1.2606", + "1.12.2-14.23.1.2607", + "1.12.2-14.23.1.2608", + "1.12.2-14.23.1.2609", + "1.12.2-14.23.1.2610", + "1.12.2-14.23.2.2611", + "1.12.2-14.23.2.2612", + "1.12.2-14.23.2.2613", + "1.12.2-14.23.2.2614", + "1.12.2-14.23.2.2615", + "1.12.2-14.23.2.2616", + "1.12.2-14.23.2.2617", + "1.12.2-14.23.2.2618", + "1.12.2-14.23.2.2619", + "1.12.2-14.23.2.2620", + "1.12.2-14.23.2.2621", + "1.12.2-14.23.2.2622", + "1.12.2-14.23.2.2623", + "1.12.2-14.23.2.2624", + "1.12.2-14.23.2.2625", + "1.12.2-14.23.2.2626", + "1.12.2-14.23.2.2627", + "1.12.2-14.23.2.2628", + "1.12.2-14.23.2.2629", + "1.12.2-14.23.2.2630", + "1.12.2-14.23.2.2631", + "1.12.2-14.23.2.2632", + "1.12.2-14.23.2.2633", + "1.12.2-14.23.2.2634", + "1.12.2-14.23.2.2635", + "1.12.2-14.23.2.2636", + "1.12.2-14.23.2.2637", + "1.12.2-14.23.2.2638", + "1.12.2-14.23.2.2639", + "1.12.2-14.23.2.2640", + "1.12.2-14.23.2.2641", + "1.12.2-14.23.2.2642", + "1.12.2-14.23.2.2643", + "1.12.2-14.23.2.2644", + "1.12.2-14.23.2.2645", + "1.12.2-14.23.2.2646", + "1.12.2-14.23.2.2647", + "1.12.2-14.23.2.2648", + "1.12.2-14.23.2.2649", + "1.12.2-14.23.2.2650", + "1.12.2-14.23.2.2651", + "1.12.2-14.23.2.2652", + "1.12.2-14.23.2.2653", + "1.12.2-14.23.2.2654", + "1.12.2-14.23.3.2655", + "1.12.2-14.23.3.2658", + "1.12.2-14.23.3.2659", + "1.12.2-14.23.3.2660", + "1.12.2-14.23.3.2661", + "1.12.2-14.23.3.2662", + "1.12.2-14.23.3.2663", + "1.12.2-14.23.3.2664", + "1.12.2-14.23.3.2665", + "1.12.2-14.23.3.2666", + "1.12.2-14.23.3.2667", + "1.12.2-14.23.3.2668", + "1.12.2-14.23.3.2669", + "1.12.2-14.23.3.2670", + "1.12.2-14.23.3.2671", + "1.12.2-14.23.3.2672", + "1.12.2-14.23.3.2673", + "1.12.2-14.23.3.2674", + "1.12.2-14.23.3.2675", + "1.12.2-14.23.3.2676", + "1.12.2-14.23.3.2677", + "1.12.2-14.23.3.2678", + "1.12.2-14.23.3.2679", + "1.12.2-14.23.3.2680", + "1.12.2-14.23.3.2681", + "1.12.2-14.23.3.2682", + "1.12.2-14.23.3.2683", + "1.12.2-14.23.3.2684", + "1.12.2-14.23.3.2685", + "1.12.2-14.23.3.2686", + "1.12.2-14.23.3.2688", + "1.12.2-14.23.3.2689", + "1.12.2-14.23.3.2690", + "1.12.2-14.23.3.2691", + "1.12.2-14.23.3.2692", + "1.12.2-14.23.3.2693", + "1.12.2-14.23.3.2694", + "1.12.2-14.23.3.2695", + "1.12.2-14.23.3.2696", + "1.12.2-14.23.3.2697", + "1.12.2-14.23.3.2698", + "1.12.2-14.23.3.2699", + "1.12.2-14.23.3.2700", + "1.12.2-14.23.3.2701", + "1.12.2-14.23.3.2702", + "1.12.2-14.23.4.2703", + "1.12.2-14.23.4.2704", + "1.12.2-14.23.4.2705", + "1.12.2-14.23.4.2706", + "1.12.2-14.23.4.2707", + "1.12.2-14.23.4.2708", + "1.12.2-14.23.4.2709", + "1.12.2-14.23.4.2710", + "1.12.2-14.23.4.2711", + "1.12.2-14.23.4.2712", + "1.12.2-14.23.4.2713", + "1.12.2-14.23.4.2714", + "1.12.2-14.23.4.2715", + "1.12.2-14.23.4.2716", + "1.12.2-14.23.4.2717", + "1.12.2-14.23.4.2718", + "1.12.2-14.23.4.2719", + "1.12.2-14.23.4.2720-4627", + "1.12.2-14.23.4.2721", + "1.12.2-14.23.4.2722", + "1.12.2-14.23.4.2723", + "1.12.2-14.23.4.2724", + "1.12.2-14.23.4.2725", + "1.12.2-14.23.4.2726", + "1.12.2-14.23.4.2727", + "1.12.2-14.23.4.2728", + "1.12.2-14.23.4.2729", + "1.12.2-14.23.4.2730", + "1.12.2-14.23.4.2732", + "1.12.2-14.23.4.2733", + "1.12.2-14.23.4.2734", + "1.12.2-14.23.4.2735", + "1.12.2-14.23.4.2736", + "1.12.2-14.23.4.2737", + "1.12.2-14.23.4.2738", + "1.12.2-14.23.4.2739", + "1.12.2-14.23.4.2740", + "1.12.2-14.23.4.2741", + "1.12.2-14.23.4.2742", + "1.12.2-14.23.4.2743", + "1.12.2-14.23.4.2744", + "1.12.2-14.23.4.2745", + "1.12.2-14.23.4.2746", + "1.12.2-14.23.4.2747", + "1.12.2-14.23.4.2748", + "1.12.2-14.23.4.2749", + "1.12.2-14.23.4.2750", + "1.12.2-14.23.4.2751", + "1.12.2-14.23.4.2752", + "1.12.2-14.23.4.2753", + "1.12.2-14.23.4.2754", + "1.12.2-14.23.4.2755", + "1.12.2-14.23.4.2756", + "1.12.2-14.23.4.2757", + "1.12.2-14.23.4.2758", + "1.12.2-14.23.4.2759", + "1.12.2-14.23.4.2760", + "1.12.2-14.23.4.2761", + "1.12.2-14.23.4.2762", + "1.12.2-14.23.4.2763", + "1.12.2-14.23.4.2764", + "1.12.2-14.23.4.2765", + "1.12.2-14.23.4.2766", + "1.12.2-14.23.4.2767", + "1.12.2-14.23.5.2768", + "1.12.2-14.23.5.2769", + "1.12.2-14.23.5.2770", + "1.12.2-14.23.5.2771", + "1.12.2-14.23.5.2772", + "1.12.2-14.23.5.2773", + "1.12.2-14.23.5.2774", + "1.12.2-14.23.5.2775", + "1.12.2-14.23.5.2776", + "1.12.2-14.23.5.2777", + "1.12.2-14.23.5.2778", + "1.12.2-14.23.5.2779", + "1.12.2-14.23.5.2780", + "1.12.2-14.23.5.2781", + "1.12.2-14.23.5.2782", + "1.12.2-14.23.5.2783", + "1.12.2-14.23.5.2784", + "1.12.2-14.23.5.2785", + "1.12.2-14.23.5.2786", + "1.12.2-14.23.5.2787", + "1.12.2-14.23.5.2788", + "1.12.2-14.23.5.2789", + "1.12.2-14.23.5.2793", + "1.12.2-14.23.5.2794", + "1.12.2-14.23.5.2795", + "1.12.2-14.23.5.2796", + "1.12.2-14.23.5.2797", + "1.12.2-14.23.5.2798", + "1.12.2-14.23.5.2799", + "1.12.2-14.23.5.2800", + "1.12.2-14.23.5.2801", + "1.12.2-14.23.5.2802", + "1.12.2-14.23.5.2803", + "1.12.2-14.23.5.2804", + "1.12.2-14.23.5.2805", + "1.12.2-14.23.5.2806", + "1.12.2-14.23.5.2807", + "1.12.2-14.23.5.2808", + "1.12.2-14.23.5.2809", + "1.12.2-14.23.5.2810", + "1.12.2-14.23.5.2811", + "1.12.2-14.23.5.2812", + "1.12.2-14.23.5.2813", + "1.12.2-14.23.5.2814", + "1.12.2-14.23.5.2815", + "1.12.2-14.23.5.2816", + "1.12.2-14.23.5.2817", + "1.12.2-14.23.5.2818", + "1.12.2-14.23.5.2819", + "1.12.2-14.23.5.2820", + "1.12.2-14.23.5.2821", + "1.12.2-14.23.5.2822", + "1.12.2-14.23.5.2823", + "1.12.2-14.23.5.2824", + "1.12.2-14.23.5.2825", + "1.12.2-14.23.5.2826", + "1.12.2-14.23.5.2827", + "1.12.2-14.23.5.2828", + "1.12.2-14.23.5.2829", + "1.12.2-14.23.5.2830", + "1.12.2-14.23.5.2831", + "1.12.2-14.23.5.2832", + "1.12.2-14.23.5.2833", + "1.12.2-14.23.5.2834", + "1.12.2-14.23.5.2835", + "1.12.2-14.23.5.2836", + "1.12.2-14.23.5.2837", + "1.12.2-14.23.5.2838", + "1.12.2-14.23.5.2839", + "1.12.2-14.23.5.2840", + "1.12.2-14.23.5.2841", + "1.12.2-14.23.5.2842", + "1.12.2-14.23.5.2843", + "1.12.2-14.23.5.2844", + "1.12.2-14.23.5.2845", + "1.12.2-14.23.5.2846", + "1.12.2-14.23.5.2847", + "1.12.2-14.23.5.2851", + "1.12.2-14.23.5.2852", + "1.12.2-14.23.5.2854", + "1.12.2-14.23.5.2855", + "1.12.2-14.23.5.2856", + "1.12.2-14.23.5.2857", + "1.12.2-14.23.5.2858", + "1.12.2-14.23.5.2859", + "1.12.2-14.23.5.2860" + ], + "1.13.2": [ + "1.13.2-25.0.9", + "1.13.2-25.0.10", + "1.13.2-25.0.11", + "1.13.2-25.0.12", + "1.13.2-25.0.13", + "1.13.2-25.0.14", + "1.13.2-25.0.17", + "1.13.2-25.0.20", + "1.13.2-25.0.21", + "1.13.2-25.0.22", + "1.13.2-25.0.23", + "1.13.2-25.0.26", + "1.13.2-25.0.27", + "1.13.2-25.0.28", + "1.13.2-25.0.29", + "1.13.2-25.0.30", + "1.13.2-25.0.31", + "1.13.2-25.0.32", + "1.13.2-25.0.33", + "1.13.2-25.0.34", + "1.13.2-25.0.35", + "1.13.2-25.0.36", + "1.13.2-25.0.37", + "1.13.2-25.0.40", + "1.13.2-25.0.41", + "1.13.2-25.0.42", + "1.13.2-25.0.43", + "1.13.2-25.0.44", + "1.13.2-25.0.45", + "1.13.2-25.0.47", + "1.13.2-25.0.48", + "1.13.2-25.0.49", + "1.13.2-25.0.50", + "1.13.2-25.0.51", + "1.13.2-25.0.52", + "1.13.2-25.0.53", + "1.13.2-25.0.54", + "1.13.2-25.0.55", + "1.13.2-25.0.56", + "1.13.2-25.0.57", + "1.13.2-25.0.58", + "1.13.2-25.0.59", + "1.13.2-25.0.60", + "1.13.2-25.0.61", + "1.13.2-25.0.63", + "1.13.2-25.0.64", + "1.13.2-25.0.66", + "1.13.2-25.0.68", + "1.13.2-25.0.69", + "1.13.2-25.0.70", + "1.13.2-25.0.71", + "1.13.2-25.0.73", + "1.13.2-25.0.74", + "1.13.2-25.0.76", + "1.13.2-25.0.77", + "1.13.2-25.0.78", + "1.13.2-25.0.79", + "1.13.2-25.0.80", + "1.13.2-25.0.81", + "1.13.2-25.0.82", + "1.13.2-25.0.84", + "1.13.2-25.0.85", + "1.13.2-25.0.87", + "1.13.2-25.0.88", + "1.13.2-25.0.89", + "1.13.2-25.0.90", + "1.13.2-25.0.91", + "1.13.2-25.0.92", + "1.13.2-25.0.93", + "1.13.2-25.0.94", + "1.13.2-25.0.95", + "1.13.2-25.0.96", + "1.13.2-25.0.99", + "1.13.2-25.0.100", + "1.13.2-25.0.102", + "1.13.2-25.0.103", + "1.13.2-25.0.107", + "1.13.2-25.0.108", + "1.13.2-25.0.109", + "1.13.2-25.0.110", + "1.13.2-25.0.114", + "1.13.2-25.0.121", + "1.13.2-25.0.128", + "1.13.2-25.0.134", + "1.13.2-25.0.135", + "1.13.2-25.0.141", + "1.13.2-25.0.142", + "1.13.2-25.0.144", + "1.13.2-25.0.145", + "1.13.2-25.0.146", + "1.13.2-25.0.147", + "1.13.2-25.0.149", + "1.13.2-25.0.154", + "1.13.2-25.0.160", + "1.13.2-25.0.168", + "1.13.2-25.0.174", + "1.13.2-25.0.175", + "1.13.2-25.0.182", + "1.13.2-25.0.183", + "1.13.2-25.0.187", + "1.13.2-25.0.189", + "1.13.2-25.0.190", + "1.13.2-25.0.191", + "1.13.2-25.0.192", + "1.13.2-25.0.193", + "1.13.2-25.0.194", + "1.13.2-25.0.198", + "1.13.2-25.0.205", + "1.13.2-25.0.206", + "1.13.2-25.0.207", + "1.13.2-25.0.208", + "1.13.2-25.0.209", + "1.13.2-25.0.210", + "1.13.2-25.0.214", + "1.13.2-25.0.215", + "1.13.2-25.0.216", + "1.13.2-25.0.218", + "1.13.2-25.0.219", + "1.13.2-25.0.222", + "1.13.2-25.0.223" + ], + "1.14.2": [ + "1.14.2-26.0.0", + "1.14.2-26.0.2", + "1.14.2-26.0.3", + "1.14.2-26.0.4", + "1.14.2-26.0.5", + "1.14.2-26.0.6", + "1.14.2-26.0.7", + "1.14.2-26.0.8", + "1.14.2-26.0.10", + "1.14.2-26.0.12", + "1.14.2-26.0.13", + "1.14.2-26.0.14", + "1.14.2-26.0.15", + "1.14.2-26.0.16", + "1.14.2-26.0.17", + "1.14.2-26.0.18", + "1.14.2-26.0.19", + "1.14.2-26.0.21", + "1.14.2-26.0.22", + "1.14.2-26.0.23", + "1.14.2-26.0.25", + "1.14.2-26.0.28", + "1.14.2-26.0.29", + "1.14.2-26.0.30", + "1.14.2-26.0.32", + "1.14.2-26.0.33", + "1.14.2-26.0.35", + "1.14.2-26.0.37", + "1.14.2-26.0.39", + "1.14.2-26.0.40", + "1.14.2-26.0.41", + "1.14.2-26.0.42", + "1.14.2-26.0.43", + "1.14.2-26.0.47", + "1.14.2-26.0.48", + "1.14.2-26.0.49", + "1.14.2-26.0.50", + "1.14.2-26.0.51", + "1.14.2-26.0.52", + "1.14.2-26.0.54", + "1.14.2-26.0.55", + "1.14.2-26.0.56", + "1.14.2-26.0.57", + "1.14.2-26.0.60", + "1.14.2-26.0.61", + "1.14.2-26.0.62", + "1.14.2-26.0.63" + ], + "1.14.3": [ + "1.14.3-27.0.0", + "1.14.3-27.0.1", + "1.14.3-27.0.2", + "1.14.3-27.0.3", + "1.14.3-27.0.4", + "1.14.3-27.0.5", + "1.14.3-27.0.7", + "1.14.3-27.0.8", + "1.14.3-27.0.9", + "1.14.3-27.0.10", + "1.14.3-27.0.11", + "1.14.3-27.0.12", + "1.14.3-27.0.13", + "1.14.3-27.0.14", + "1.14.3-27.0.15", + "1.14.3-27.0.16", + "1.14.3-27.0.17", + "1.14.3-27.0.18", + "1.14.3-27.0.19", + "1.14.3-27.0.20", + "1.14.3-27.0.21", + "1.14.3-27.0.22", + "1.14.3-27.0.23", + "1.14.3-27.0.24", + "1.14.3-27.0.25", + "1.14.3-27.0.26", + "1.14.3-27.0.29", + "1.14.3-27.0.30", + "1.14.3-27.0.31", + "1.14.3-27.0.38", + "1.14.3-27.0.40", + "1.14.3-27.0.42", + "1.14.3-27.0.43", + "1.14.3-27.0.47", + "1.14.3-27.0.49", + "1.14.3-27.0.50", + "1.14.3-27.0.51", + "1.14.3-27.0.52", + "1.14.3-27.0.53", + "1.14.3-27.0.54", + "1.14.3-27.0.55", + "1.14.3-27.0.56", + "1.14.3-27.0.57", + "1.14.3-27.0.58", + "1.14.3-27.0.59", + "1.14.3-27.0.60" + ], + "1.14.4": [ + "1.14.4-28.0.1", + "1.14.4-28.0.2", + "1.14.4-28.0.3", + "1.14.4-28.0.4", + "1.14.4-28.0.5", + "1.14.4-28.0.9", + "1.14.4-28.0.11", + "1.14.4-28.0.12", + "1.14.4-28.0.13", + "1.14.4-28.0.14", + "1.14.4-28.0.16", + "1.14.4-28.0.17", + "1.14.4-28.0.18", + "1.14.4-28.0.19", + "1.14.4-28.0.20", + "1.14.4-28.0.21", + "1.14.4-28.0.22", + "1.14.4-28.0.23", + "1.14.4-28.0.24", + "1.14.4-28.0.25", + "1.14.4-28.0.26", + "1.14.4-28.0.27", + "1.14.4-28.0.28", + "1.14.4-28.0.29", + "1.14.4-28.0.30", + "1.14.4-28.0.32", + "1.14.4-28.0.34", + "1.14.4-28.0.35", + "1.14.4-28.0.37", + "1.14.4-28.0.38", + "1.14.4-28.0.39", + "1.14.4-28.0.40", + "1.14.4-28.0.41", + "1.14.4-28.0.45", + "1.14.4-28.0.46", + "1.14.4-28.0.47", + "1.14.4-28.0.48", + "1.14.4-28.0.49", + "1.14.4-28.0.51", + "1.14.4-28.0.55", + "1.14.4-28.0.56", + "1.14.4-28.0.58", + "1.14.4-28.0.62", + "1.14.4-28.0.63", + "1.14.4-28.0.65", + "1.14.4-28.0.67", + "1.14.4-28.0.68", + "1.14.4-28.0.69", + "1.14.4-28.0.70", + "1.14.4-28.0.73", + "1.14.4-28.0.74", + "1.14.4-28.0.75", + "1.14.4-28.0.76", + "1.14.4-28.0.81", + "1.14.4-28.0.82", + "1.14.4-28.0.83", + "1.14.4-28.0.84", + "1.14.4-28.0.85", + "1.14.4-28.0.86", + "1.14.4-28.0.87", + "1.14.4-28.0.88", + "1.14.4-28.0.90", + "1.14.4-28.0.91", + "1.14.4-28.0.92", + "1.14.4-28.0.93", + "1.14.4-28.0.94", + "1.14.4-28.0.95", + "1.14.4-28.0.100", + "1.14.4-28.0.101", + "1.14.4-28.0.102", + "1.14.4-28.0.104", + "1.14.4-28.0.105", + "1.14.4-28.0.106", + "1.14.4-28.0.107", + "1.14.4-28.1.0", + "1.14.4-28.1.1", + "1.14.4-28.1.2", + "1.14.4-28.1.3", + "1.14.4-28.1.4", + "1.14.4-28.1.5", + "1.14.4-28.1.6", + "1.14.4-28.1.7", + "1.14.4-28.1.8", + "1.14.4-28.1.10", + "1.14.4-28.1.11", + "1.14.4-28.1.14", + "1.14.4-28.1.15", + "1.14.4-28.1.16", + "1.14.4-28.1.17", + "1.14.4-28.1.18", + "1.14.4-28.1.19", + "1.14.4-28.1.20", + "1.14.4-28.1.22", + "1.14.4-28.1.23", + "1.14.4-28.1.24", + "1.14.4-28.1.25", + "1.14.4-28.1.26", + "1.14.4-28.1.28", + "1.14.4-28.1.30", + "1.14.4-28.1.31", + "1.14.4-28.1.32", + "1.14.4-28.1.33", + "1.14.4-28.1.34", + "1.14.4-28.1.35", + "1.14.4-28.1.36", + "1.14.4-28.1.37", + "1.14.4-28.1.38", + "1.14.4-28.1.39", + "1.14.4-28.1.40", + "1.14.4-28.1.41", + "1.14.4-28.1.42", + "1.14.4-28.1.44", + "1.14.4-28.1.45", + "1.14.4-28.1.46", + "1.14.4-28.1.47", + "1.14.4-28.1.48", + "1.14.4-28.1.49", + "1.14.4-28.1.50", + "1.14.4-28.1.56", + "1.14.4-28.1.58", + "1.14.4-28.1.59", + "1.14.4-28.1.60", + "1.14.4-28.1.61", + "1.14.4-28.1.62", + "1.14.4-28.1.64", + "1.14.4-28.1.65", + "1.14.4-28.1.66", + "1.14.4-28.1.67", + "1.14.4-28.1.68", + "1.14.4-28.1.69", + "1.14.4-28.1.70", + "1.14.4-28.1.71", + "1.14.4-28.1.72", + "1.14.4-28.1.73", + "1.14.4-28.1.74", + "1.14.4-28.1.75", + "1.14.4-28.1.76", + "1.14.4-28.1.77", + "1.14.4-28.1.78", + "1.14.4-28.1.79", + "1.14.4-28.1.80", + "1.14.4-28.1.81", + "1.14.4-28.1.85", + "1.14.4-28.1.86", + "1.14.4-28.1.87", + "1.14.4-28.1.88", + "1.14.4-28.1.90", + "1.14.4-28.1.91", + "1.14.4-28.1.92", + "1.14.4-28.1.93", + "1.14.4-28.1.94", + "1.14.4-28.1.95", + "1.14.4-28.1.96", + "1.14.4-28.1.97", + "1.14.4-28.1.98", + "1.14.4-28.1.99", + "1.14.4-28.1.102", + "1.14.4-28.1.103", + "1.14.4-28.1.104", + "1.14.4-28.1.105", + "1.14.4-28.1.106", + "1.14.4-28.1.107", + "1.14.4-28.1.108", + "1.14.4-28.1.109", + "1.14.4-28.1.110", + "1.14.4-28.1.111", + "1.14.4-28.1.113", + "1.14.4-28.1.114", + "1.14.4-28.1.115", + "1.14.4-28.1.116", + "1.14.4-28.1.117", + "1.14.4-28.1.118", + "1.14.4-28.2.0", + "1.14.4-28.2.1", + "1.14.4-28.2.2", + "1.14.4-28.2.3", + "1.14.4-28.2.4", + "1.14.4-28.2.5", + "1.14.4-28.2.6", + "1.14.4-28.2.10", + "1.14.4-28.2.11", + "1.14.4-28.2.12", + "1.14.4-28.2.13", + "1.14.4-28.2.14", + "1.14.4-28.2.15", + "1.14.4-28.2.16", + "1.14.4-28.2.17", + "1.14.4-28.2.18", + "1.14.4-28.2.19", + "1.14.4-28.2.20", + "1.14.4-28.2.21", + "1.14.4-28.2.23", + "1.14.4-28.2.25", + "1.14.4-28.2.26" + ], + "1.15": [ + "1.15-29.0.0", + "1.15-29.0.1", + "1.15-29.0.2", + "1.15-29.0.3", + "1.15-29.0.4" + ], + "1.15.1": [ + "1.15.1-30.0.0", + "1.15.1-30.0.2", + "1.15.1-30.0.4", + "1.15.1-30.0.5", + "1.15.1-30.0.7", + "1.15.1-30.0.8", + "1.15.1-30.0.10", + "1.15.1-30.0.11", + "1.15.1-30.0.12", + "1.15.1-30.0.13", + "1.15.1-30.0.14", + "1.15.1-30.0.15", + "1.15.1-30.0.16", + "1.15.1-30.0.17", + "1.15.1-30.0.18", + "1.15.1-30.0.19", + "1.15.1-30.0.20", + "1.15.1-30.0.21", + "1.15.1-30.0.22", + "1.15.1-30.0.24", + "1.15.1-30.0.25", + "1.15.1-30.0.26", + "1.15.1-30.0.27", + "1.15.1-30.0.28", + "1.15.1-30.0.29", + "1.15.1-30.0.30", + "1.15.1-30.0.31", + "1.15.1-30.0.32", + "1.15.1-30.0.33", + "1.15.1-30.0.35", + "1.15.1-30.0.36", + "1.15.1-30.0.38", + "1.15.1-30.0.39", + "1.15.1-30.0.40", + "1.15.1-30.0.41", + "1.15.1-30.0.42", + "1.15.1-30.0.43", + "1.15.1-30.0.48", + "1.15.1-30.0.49", + "1.15.1-30.0.50", + "1.15.1-30.0.51" + ], + "1.15.2": [ + "1.15.2-31.0.0", + "1.15.2-31.0.1", + "1.15.2-31.0.2", + "1.15.2-31.0.4", + "1.15.2-31.0.7", + "1.15.2-31.0.8", + "1.15.2-31.0.9", + "1.15.2-31.0.11", + "1.15.2-31.0.12", + "1.15.2-31.0.13", + "1.15.2-31.0.14", + "1.15.2-31.0.15", + "1.15.2-31.0.16", + "1.15.2-31.0.17", + "1.15.2-31.0.19", + "1.15.2-31.1.0", + "1.15.2-31.1.1", + "1.15.2-31.1.2", + "1.15.2-31.1.3", + "1.15.2-31.1.5", + "1.15.2-31.1.8", + "1.15.2-31.1.9", + "1.15.2-31.1.10", + "1.15.2-31.1.11", + "1.15.2-31.1.12", + "1.15.2-31.1.13", + "1.15.2-31.1.14", + "1.15.2-31.1.15", + "1.15.2-31.1.16", + "1.15.2-31.1.17", + "1.15.2-31.1.18", + "1.15.2-31.1.19", + "1.15.2-31.1.20", + "1.15.2-31.1.21", + "1.15.2-31.1.22", + "1.15.2-31.1.23", + "1.15.2-31.1.24", + "1.15.2-31.1.25", + "1.15.2-31.1.26", + "1.15.2-31.1.27", + "1.15.2-31.1.28", + "1.15.2-31.1.29", + "1.15.2-31.1.30", + "1.15.2-31.1.32", + "1.15.2-31.1.34", + "1.15.2-31.1.35", + "1.15.2-31.1.36", + "1.15.2-31.1.37", + "1.15.2-31.1.39", + "1.15.2-31.1.40", + "1.15.2-31.1.41", + "1.15.2-31.1.42", + "1.15.2-31.1.43", + "1.15.2-31.1.44", + "1.15.2-31.1.45", + "1.15.2-31.1.46", + "1.15.2-31.1.47", + "1.15.2-31.1.48", + "1.15.2-31.1.49", + "1.15.2-31.1.50", + "1.15.2-31.1.51", + "1.15.2-31.1.55", + "1.15.2-31.1.57", + "1.15.2-31.1.59", + "1.15.2-31.1.60", + "1.15.2-31.1.61", + "1.15.2-31.1.62", + "1.15.2-31.1.63", + "1.15.2-31.1.64", + "1.15.2-31.1.65", + "1.15.2-31.1.66", + "1.15.2-31.1.67", + "1.15.2-31.1.70", + "1.15.2-31.1.71", + "1.15.2-31.1.72", + "1.15.2-31.1.73", + "1.15.2-31.1.74", + "1.15.2-31.1.75", + "1.15.2-31.1.76", + "1.15.2-31.1.77", + "1.15.2-31.1.78", + "1.15.2-31.1.79", + "1.15.2-31.1.80", + "1.15.2-31.1.81", + "1.15.2-31.1.84", + "1.15.2-31.1.85", + "1.15.2-31.1.86", + "1.15.2-31.1.87", + "1.15.2-31.1.88", + "1.15.2-31.1.89", + "1.15.2-31.1.91", + "1.15.2-31.1.92", + "1.15.2-31.1.93", + "1.15.2-31.1.95", + "1.15.2-31.1.97", + "1.15.2-31.1.98", + "1.15.2-31.1.99", + "1.15.2-31.2.0", + "1.15.2-31.2.1", + "1.15.2-31.2.2", + "1.15.2-31.2.3", + "1.15.2-31.2.4", + "1.15.2-31.2.5", + "1.15.2-31.2.7", + "1.15.2-31.2.8", + "1.15.2-31.2.9", + "1.15.2-31.2.10", + "1.15.2-31.2.12", + "1.15.2-31.2.13", + "1.15.2-31.2.15", + "1.15.2-31.2.16", + "1.15.2-31.2.17", + "1.15.2-31.2.18", + "1.15.2-31.2.19", + "1.15.2-31.2.20", + "1.15.2-31.2.21", + "1.15.2-31.2.22", + "1.15.2-31.2.23", + "1.15.2-31.2.24", + "1.15.2-31.2.25", + "1.15.2-31.2.26", + "1.15.2-31.2.27", + "1.15.2-31.2.28", + "1.15.2-31.2.29", + "1.15.2-31.2.30", + "1.15.2-31.2.31", + "1.15.2-31.2.33", + "1.15.2-31.2.35", + "1.15.2-31.2.36", + "1.15.2-31.2.37", + "1.15.2-31.2.38", + "1.15.2-31.2.40", + "1.15.2-31.2.41", + "1.15.2-31.2.43", + "1.15.2-31.2.44", + "1.15.2-31.2.45", + "1.15.2-31.2.46", + "1.15.2-31.2.47", + "1.15.2-31.2.48", + "1.15.2-31.2.49", + "1.15.2-31.2.50", + "1.15.2-31.2.52", + "1.15.2-31.2.53", + "1.15.2-31.2.54", + "1.15.2-31.2.55", + "1.15.2-31.2.56", + "1.15.2-31.2.57", + "1.15.2-31.2.60" + ], + "1.16.1": [ + "1.16.1-32.0.1", + "1.16.1-32.0.2", + "1.16.1-32.0.6", + "1.16.1-32.0.7", + "1.16.1-32.0.8", + "1.16.1-32.0.9", + "1.16.1-32.0.10", + "1.16.1-32.0.12", + "1.16.1-32.0.13", + "1.16.1-32.0.14", + "1.16.1-32.0.15", + "1.16.1-32.0.16", + "1.16.1-32.0.17", + "1.16.1-32.0.18", + "1.16.1-32.0.19", + "1.16.1-32.0.20", + "1.16.1-32.0.21", + "1.16.1-32.0.23", + "1.16.1-32.0.24", + "1.16.1-32.0.25", + "1.16.1-32.0.26", + "1.16.1-32.0.27", + "1.16.1-32.0.28", + "1.16.1-32.0.29", + "1.16.1-32.0.30", + "1.16.1-32.0.31", + "1.16.1-32.0.32", + "1.16.1-32.0.33", + "1.16.1-32.0.34", + "1.16.1-32.0.35", + "1.16.1-32.0.36", + "1.16.1-32.0.38", + "1.16.1-32.0.39", + "1.16.1-32.0.40", + "1.16.1-32.0.41", + "1.16.1-32.0.43", + "1.16.1-32.0.44", + "1.16.1-32.0.46", + "1.16.1-32.0.47", + "1.16.1-32.0.48", + "1.16.1-32.0.49", + "1.16.1-32.0.50", + "1.16.1-32.0.51", + "1.16.1-32.0.52", + "1.16.1-32.0.53", + "1.16.1-32.0.54", + "1.16.1-32.0.55", + "1.16.1-32.0.56", + "1.16.1-32.0.57", + "1.16.1-32.0.59", + "1.16.1-32.0.60", + "1.16.1-32.0.61", + "1.16.1-32.0.62", + "1.16.1-32.0.63", + "1.16.1-32.0.64", + "1.16.1-32.0.65", + "1.16.1-32.0.66", + "1.16.1-32.0.67", + "1.16.1-32.0.68", + "1.16.1-32.0.69", + "1.16.1-32.0.70", + "1.16.1-32.0.71", + "1.16.1-32.0.72", + "1.16.1-32.0.73", + "1.16.1-32.0.74", + "1.16.1-32.0.75", + "1.16.1-32.0.76", + "1.16.1-32.0.77", + "1.16.1-32.0.79", + "1.16.1-32.0.80", + "1.16.1-32.0.81", + "1.16.1-32.0.82", + "1.16.1-32.0.83", + "1.16.1-32.0.84", + "1.16.1-32.0.85", + "1.16.1-32.0.86", + "1.16.1-32.0.88", + "1.16.1-32.0.90", + "1.16.1-32.0.91", + "1.16.1-32.0.92", + "1.16.1-32.0.93", + "1.16.1-32.0.95", + "1.16.1-32.0.96", + "1.16.1-32.0.97", + "1.16.1-32.0.98", + "1.16.1-32.0.99", + "1.16.1-32.0.101", + "1.16.1-32.0.104", + "1.16.1-32.0.105", + "1.16.1-32.0.106", + "1.16.1-32.0.107", + "1.16.1-32.0.108" + ], + "1.16.2": [ + "1.16.2-33.0.0", + "1.16.2-33.0.2", + "1.16.2-33.0.3", + "1.16.2-33.0.5", + "1.16.2-33.0.6", + "1.16.2-33.0.7", + "1.16.2-33.0.8", + "1.16.2-33.0.9", + "1.16.2-33.0.10", + "1.16.2-33.0.11", + "1.16.2-33.0.12", + "1.16.2-33.0.13", + "1.16.2-33.0.14", + "1.16.2-33.0.15", + "1.16.2-33.0.16", + "1.16.2-33.0.17", + "1.16.2-33.0.18", + "1.16.2-33.0.19", + "1.16.2-33.0.20", + "1.16.2-33.0.21", + "1.16.2-33.0.22", + "1.16.2-33.0.23", + "1.16.2-33.0.30", + "1.16.2-33.0.31", + "1.16.2-33.0.32", + "1.16.2-33.0.34", + "1.16.2-33.0.35", + "1.16.2-33.0.36", + "1.16.2-33.0.37", + "1.16.2-33.0.40", + "1.16.2-33.0.41", + "1.16.2-33.0.42", + "1.16.2-33.0.43", + "1.16.2-33.0.44", + "1.16.2-33.0.45", + "1.16.2-33.0.46", + "1.16.2-33.0.49", + "1.16.2-33.0.50", + "1.16.2-33.0.54", + "1.16.2-33.0.55", + "1.16.2-33.0.56", + "1.16.2-33.0.57", + "1.16.2-33.0.58", + "1.16.2-33.0.59", + "1.16.2-33.0.60", + "1.16.2-33.0.61" + ], + "1.16.3": [ + "1.16.3-34.0.0", + "1.16.3-34.0.1", + "1.16.3-34.0.2", + "1.16.3-34.0.3", + "1.16.3-34.0.4", + "1.16.3-34.0.5", + "1.16.3-34.0.6", + "1.16.3-34.0.7", + "1.16.3-34.0.8", + "1.16.3-34.0.9", + "1.16.3-34.0.10", + "1.16.3-34.0.11", + "1.16.3-34.0.12", + "1.16.3-34.0.13", + "1.16.3-34.0.14", + "1.16.3-34.0.16", + "1.16.3-34.0.17", + "1.16.3-34.0.18", + "1.16.3-34.0.19", + "1.16.3-34.0.20", + "1.16.3-34.0.21", + "1.16.3-34.1.0", + "1.16.3-34.1.1", + "1.16.3-34.1.2", + "1.16.3-34.1.3", + "1.16.3-34.1.4", + "1.16.3-34.1.5", + "1.16.3-34.1.7", + "1.16.3-34.1.9", + "1.16.3-34.1.10", + "1.16.3-34.1.11", + "1.16.3-34.1.12", + "1.16.3-34.1.13", + "1.16.3-34.1.14", + "1.16.3-34.1.15", + "1.16.3-34.1.16", + "1.16.3-34.1.17", + "1.16.3-34.1.18", + "1.16.3-34.1.19", + "1.16.3-34.1.20", + "1.16.3-34.1.21", + "1.16.3-34.1.22", + "1.16.3-34.1.23", + "1.16.3-34.1.24", + "1.16.3-34.1.25", + "1.16.3-34.1.27", + "1.16.3-34.1.28", + "1.16.3-34.1.29", + "1.16.3-34.1.30", + "1.16.3-34.1.31", + "1.16.3-34.1.32", + "1.16.3-34.1.33", + "1.16.3-34.1.34", + "1.16.3-34.1.35", + "1.16.3-34.1.39", + "1.16.3-34.1.40", + "1.16.3-34.1.41", + "1.16.3-34.1.42" + ], + "1.16.4": [ + "1.16.4-35.0.0", + "1.16.4-35.0.1", + "1.16.4-35.0.2", + "1.16.4-35.0.3", + "1.16.4-35.0.4", + "1.16.4-35.0.5", + "1.16.4-35.0.6", + "1.16.4-35.0.7", + "1.16.4-35.0.9", + "1.16.4-35.0.10", + "1.16.4-35.0.11", + "1.16.4-35.0.12", + "1.16.4-35.0.13", + "1.16.4-35.0.14", + "1.16.4-35.0.15", + "1.16.4-35.0.16", + "1.16.4-35.0.17", + "1.16.4-35.0.18", + "1.16.4-35.0.19", + "1.16.4-35.0.20", + "1.16.4-35.0.22", + "1.16.4-35.1.0", + "1.16.4-35.1.1", + "1.16.4-35.1.2", + "1.16.4-35.1.3", + "1.16.4-35.1.4", + "1.16.4-35.1.5", + "1.16.4-35.1.6", + "1.16.4-35.1.7", + "1.16.4-35.1.8", + "1.16.4-35.1.9", + "1.16.4-35.1.10", + "1.16.4-35.1.11", + "1.16.4-35.1.12", + "1.16.4-35.1.13", + "1.16.4-35.1.15", + "1.16.4-35.1.16", + "1.16.4-35.1.17", + "1.16.4-35.1.18", + "1.16.4-35.1.20", + "1.16.4-35.1.21", + "1.16.4-35.1.22", + "1.16.4-35.1.23", + "1.16.4-35.1.24", + "1.16.4-35.1.26", + "1.16.4-35.1.27", + "1.16.4-35.1.28", + "1.16.4-35.1.29", + "1.16.4-35.1.31", + "1.16.4-35.1.32", + "1.16.4-35.1.33", + "1.16.4-35.1.34", + "1.16.4-35.1.35", + "1.16.4-35.1.36", + "1.16.4-35.1.37" + ], + "1.16.5": [ + "1.16.5-36.0.0", + "1.16.5-36.0.1", + "1.16.5-36.0.2", + "1.16.5-36.0.4", + "1.16.5-36.0.7", + "1.16.5-36.0.8", + "1.16.5-36.0.9", + "1.16.5-36.0.10", + "1.16.5-36.0.11", + "1.16.5-36.0.12", + "1.16.5-36.0.13", + "1.16.5-36.0.14", + "1.16.5-36.0.15", + "1.16.5-36.0.16", + "1.16.5-36.0.17", + "1.16.5-36.0.18", + "1.16.5-36.0.19", + "1.16.5-36.0.20", + "1.16.5-36.0.21", + "1.16.5-36.0.22", + "1.16.5-36.0.23", + "1.16.5-36.0.24", + "1.16.5-36.0.25", + "1.16.5-36.0.26", + "1.16.5-36.0.27", + "1.16.5-36.0.28", + "1.16.5-36.0.29", + "1.16.5-36.0.30", + "1.16.5-36.0.31", + "1.16.5-36.0.32", + "1.16.5-36.0.33", + "1.16.5-36.0.34", + "1.16.5-36.0.35", + "1.16.5-36.0.36", + "1.16.5-36.0.37", + "1.16.5-36.0.39", + "1.16.5-36.0.40", + "1.16.5-36.0.41", + "1.16.5-36.0.42", + "1.16.5-36.0.43", + "1.16.5-36.0.44", + "1.16.5-36.0.45", + "1.16.5-36.0.46", + "1.16.5-36.0.48", + "1.16.5-36.0.52", + "1.16.5-36.0.53", + "1.16.5-36.0.54", + "1.16.5-36.0.55", + "1.16.5-36.0.58", + "1.16.5-36.0.59", + "1.16.5-36.0.60", + "1.16.5-36.0.61", + "1.16.5-36.0.62", + "1.16.5-36.0.63", + "1.16.5-36.1.0", + "1.16.5-36.1.1", + "1.16.5-36.1.2", + "1.16.5-36.1.3", + "1.16.5-36.1.4", + "1.16.5-36.1.6", + "1.16.5-36.1.7", + "1.16.5-36.1.8", + "1.16.5-36.1.9", + "1.16.5-36.1.10", + "1.16.5-36.1.12", + "1.16.5-36.1.13", + "1.16.5-36.1.14", + "1.16.5-36.1.15", + "1.16.5-36.1.16", + "1.16.5-36.1.17", + "1.16.5-36.1.18", + "1.16.5-36.1.19", + "1.16.5-36.1.20", + "1.16.5-36.1.21", + "1.16.5-36.1.22", + "1.16.5-36.1.23", + "1.16.5-36.1.24", + "1.16.5-36.1.25", + "1.16.5-36.1.26", + "1.16.5-36.1.27", + "1.16.5-36.1.28", + "1.16.5-36.1.29", + "1.16.5-36.1.30", + "1.16.5-36.1.31", + "1.16.5-36.1.32", + "1.16.5-36.1.33", + "1.16.5-36.1.34", + "1.16.5-36.1.35", + "1.16.5-36.1.36", + "1.16.5-36.1.51", + "1.16.5-36.1.52", + "1.16.5-36.1.53", + "1.16.5-36.1.58", + "1.16.5-36.1.61", + "1.16.5-36.1.62", + "1.16.5-36.1.63", + "1.16.5-36.1.65", + "1.16.5-36.1.66", + "1.16.5-36.2.0", + "1.16.5-36.2.1", + "1.16.5-36.2.2", + "1.16.5-36.2.3", + "1.16.5-36.2.4", + "1.16.5-36.2.5", + "1.16.5-36.2.6", + "1.16.5-36.2.8", + "1.16.5-36.2.9", + "1.16.5-36.2.10", + "1.16.5-36.2.11", + "1.16.5-36.2.12", + "1.16.5-36.2.13", + "1.16.5-36.2.14", + "1.16.5-36.2.15", + "1.16.5-36.2.16", + "1.16.5-36.2.17", + "1.16.5-36.2.18", + "1.16.5-36.2.19", + "1.16.5-36.2.20", + "1.16.5-36.2.21", + "1.16.5-36.2.22", + "1.16.5-36.2.23", + "1.16.5-36.2.25", + "1.16.5-36.2.26", + "1.16.5-36.2.27", + "1.16.5-36.2.28", + "1.16.5-36.2.29", + "1.16.5-36.2.30", + "1.16.5-36.2.31", + "1.16.5-36.2.32", + "1.16.5-36.2.33", + "1.16.5-36.2.34", + "1.16.5-36.2.35", + "1.16.5-36.2.39", + "1.16.5-36.2.40", + "1.16.5-36.2.41", + "1.16.5-36.2.42" + ], + "1.17.1": [ + "1.17.1-37.0.0", + "1.17.1-37.0.1", + "1.17.1-37.0.2", + "1.17.1-37.0.3", + "1.17.1-37.0.5", + "1.17.1-37.0.7", + "1.17.1-37.0.8", + "1.17.1-37.0.9", + "1.17.1-37.0.10", + "1.17.1-37.0.11", + "1.17.1-37.0.12", + "1.17.1-37.0.13", + "1.17.1-37.0.15", + "1.17.1-37.0.16", + "1.17.1-37.0.17", + "1.17.1-37.0.18", + "1.17.1-37.0.19", + "1.17.1-37.0.20", + "1.17.1-37.0.21", + "1.17.1-37.0.22", + "1.17.1-37.0.24", + "1.17.1-37.0.25", + "1.17.1-37.0.26", + "1.17.1-37.0.27", + "1.17.1-37.0.28", + "1.17.1-37.0.29", + "1.17.1-37.0.30", + "1.17.1-37.0.31", + "1.17.1-37.0.32", + "1.17.1-37.0.33", + "1.17.1-37.0.34", + "1.17.1-37.0.35", + "1.17.1-37.0.36", + "1.17.1-37.0.37", + "1.17.1-37.0.38", + "1.17.1-37.0.39", + "1.17.1-37.0.40", + "1.17.1-37.0.41", + "1.17.1-37.0.42", + "1.17.1-37.0.43", + "1.17.1-37.0.44", + "1.17.1-37.0.45", + "1.17.1-37.0.46", + "1.17.1-37.0.47", + "1.17.1-37.0.48", + "1.17.1-37.0.49", + "1.17.1-37.0.50", + "1.17.1-37.0.51", + "1.17.1-37.0.52", + "1.17.1-37.0.53", + "1.17.1-37.0.54", + "1.17.1-37.0.55", + "1.17.1-37.0.56", + "1.17.1-37.0.57", + "1.17.1-37.0.58", + "1.17.1-37.0.59", + "1.17.1-37.0.60", + "1.17.1-37.0.61", + "1.17.1-37.0.62", + "1.17.1-37.0.64", + "1.17.1-37.0.65", + "1.17.1-37.0.66", + "1.17.1-37.0.67", + "1.17.1-37.0.68", + "1.17.1-37.0.69", + "1.17.1-37.0.70", + "1.17.1-37.0.71", + "1.17.1-37.0.72", + "1.17.1-37.0.73", + "1.17.1-37.0.74", + "1.17.1-37.0.75", + "1.17.1-37.0.76", + "1.17.1-37.0.78", + "1.17.1-37.0.80", + "1.17.1-37.0.81", + "1.17.1-37.0.82", + "1.17.1-37.0.83", + "1.17.1-37.0.84", + "1.17.1-37.0.85", + "1.17.1-37.0.86", + "1.17.1-37.0.87", + "1.17.1-37.0.88", + "1.17.1-37.0.89", + "1.17.1-37.0.90", + "1.17.1-37.0.91", + "1.17.1-37.0.94", + "1.17.1-37.0.95", + "1.17.1-37.0.97", + "1.17.1-37.0.98", + "1.17.1-37.0.102", + "1.17.1-37.0.103", + "1.17.1-37.0.104", + "1.17.1-37.0.105", + "1.17.1-37.0.107", + "1.17.1-37.0.108", + "1.17.1-37.0.109", + "1.17.1-37.0.110", + "1.17.1-37.0.111", + "1.17.1-37.0.112", + "1.17.1-37.0.113", + "1.17.1-37.0.114", + "1.17.1-37.0.116", + "1.17.1-37.0.117", + "1.17.1-37.0.118", + "1.17.1-37.0.119", + "1.17.1-37.0.120", + "1.17.1-37.0.121", + "1.17.1-37.0.122", + "1.17.1-37.0.123", + "1.17.1-37.0.125", + "1.17.1-37.0.126", + "1.17.1-37.0.127", + "1.17.1-37.1.0", + "1.17.1-37.1.1" + ], + "1.18": [ + "1.18-38.0.0", + "1.18-38.0.1", + "1.18-38.0.2", + "1.18-38.0.3", + "1.18-38.0.4", + "1.18-38.0.5", + "1.18-38.0.6", + "1.18-38.0.8", + "1.18-38.0.10", + "1.18-38.0.11", + "1.18-38.0.12", + "1.18-38.0.13", + "1.18-38.0.14", + "1.18-38.0.15", + "1.18-38.0.16", + "1.18-38.0.17" + ], + "1.18.1": [ + "1.18.1-39.0.0", + "1.18.1-39.0.1", + "1.18.1-39.0.2", + "1.18.1-39.0.3", + "1.18.1-39.0.4", + "1.18.1-39.0.5", + "1.18.1-39.0.6", + "1.18.1-39.0.7", + "1.18.1-39.0.8", + "1.18.1-39.0.9", + "1.18.1-39.0.10", + "1.18.1-39.0.11", + "1.18.1-39.0.12", + "1.18.1-39.0.13", + "1.18.1-39.0.14", + "1.18.1-39.0.15", + "1.18.1-39.0.16", + "1.18.1-39.0.17", + "1.18.1-39.0.18", + "1.18.1-39.0.19", + "1.18.1-39.0.20", + "1.18.1-39.0.22", + "1.18.1-39.0.36", + "1.18.1-39.0.37", + "1.18.1-39.0.38", + "1.18.1-39.0.40", + "1.18.1-39.0.43", + "1.18.1-39.0.44", + "1.18.1-39.0.45", + "1.18.1-39.0.46", + "1.18.1-39.0.47", + "1.18.1-39.0.48", + "1.18.1-39.0.49", + "1.18.1-39.0.50", + "1.18.1-39.0.51", + "1.18.1-39.0.52", + "1.18.1-39.0.53", + "1.18.1-39.0.54", + "1.18.1-39.0.55", + "1.18.1-39.0.56", + "1.18.1-39.0.57", + "1.18.1-39.0.58", + "1.18.1-39.0.59", + "1.18.1-39.0.60", + "1.18.1-39.0.61", + "1.18.1-39.0.62", + "1.18.1-39.0.63", + "1.18.1-39.0.64", + "1.18.1-39.0.65", + "1.18.1-39.0.66", + "1.18.1-39.0.67", + "1.18.1-39.0.68", + "1.18.1-39.0.69", + "1.18.1-39.0.70", + "1.18.1-39.0.71", + "1.18.1-39.0.72", + "1.18.1-39.0.73", + "1.18.1-39.0.74", + "1.18.1-39.0.75", + "1.18.1-39.0.76", + "1.18.1-39.0.77", + "1.18.1-39.0.78", + "1.18.1-39.0.79", + "1.18.1-39.0.80", + "1.18.1-39.0.81", + "1.18.1-39.0.82", + "1.18.1-39.0.83", + "1.18.1-39.0.84", + "1.18.1-39.0.85", + "1.18.1-39.0.86", + "1.18.1-39.0.87", + "1.18.1-39.0.88", + "1.18.1-39.0.89", + "1.18.1-39.0.90", + "1.18.1-39.1.0", + "1.18.1-39.1.1", + "1.18.1-39.1.2" + ], + "1.18.2": [ + "1.18.2-40.0.0", + "1.18.2-40.0.1", + "1.18.2-40.0.2", + "1.18.2-40.0.3", + "1.18.2-40.0.4", + "1.18.2-40.0.5", + "1.18.2-40.0.6", + "1.18.2-40.0.7", + "1.18.2-40.0.8", + "1.18.2-40.0.9", + "1.18.2-40.0.10", + "1.18.2-40.0.11", + "1.18.2-40.0.12", + "1.18.2-40.0.13", + "1.18.2-40.0.14", + "1.18.2-40.0.15", + "1.18.2-40.0.16", + "1.18.2-40.0.17", + "1.18.2-40.0.18", + "1.18.2-40.0.19", + "1.18.2-40.0.20", + "1.18.2-40.0.21", + "1.18.2-40.0.22", + "1.18.2-40.0.23", + "1.18.2-40.0.24", + "1.18.2-40.0.25", + "1.18.2-40.0.26", + "1.18.2-40.0.27", + "1.18.2-40.0.28", + "1.18.2-40.0.29", + "1.18.2-40.0.30", + "1.18.2-40.0.31", + "1.18.2-40.0.32", + "1.18.2-40.0.33", + "1.18.2-40.0.34", + "1.18.2-40.0.35", + "1.18.2-40.0.36", + "1.18.2-40.0.38", + "1.18.2-40.0.39", + "1.18.2-40.0.40", + "1.18.2-40.0.41", + "1.18.2-40.0.42", + "1.18.2-40.0.43", + "1.18.2-40.0.44", + "1.18.2-40.0.45", + "1.18.2-40.0.46", + "1.18.2-40.0.47", + "1.18.2-40.0.48", + "1.18.2-40.0.49", + "1.18.2-40.0.51", + "1.18.2-40.0.52", + "1.18.2-40.0.53", + "1.18.2-40.0.54", + "1.18.2-40.1.0", + "1.18.2-40.1.1", + "1.18.2-40.1.2", + "1.18.2-40.1.3", + "1.18.2-40.1.4", + "1.18.2-40.1.5", + "1.18.2-40.1.6", + "1.18.2-40.1.8", + "1.18.2-40.1.10", + "1.18.2-40.1.11", + "1.18.2-40.1.12", + "1.18.2-40.1.13", + "1.18.2-40.1.14", + "1.18.2-40.1.15", + "1.18.2-40.1.16", + "1.18.2-40.1.17", + "1.18.2-40.1.18", + "1.18.2-40.1.19", + "1.18.2-40.1.20", + "1.18.2-40.1.22", + "1.18.2-40.1.21", + "1.18.2-40.1.23", + "1.18.2-40.1.24", + "1.18.2-40.1.25", + "1.18.2-40.1.26", + "1.18.2-40.1.27", + "1.18.2-40.1.28", + "1.18.2-40.1.29", + "1.18.2-40.1.30", + "1.18.2-40.1.31", + "1.18.2-40.1.34", + "1.18.2-40.1.35", + "1.18.2-40.1.36", + "1.18.2-40.1.41", + "1.18.2-40.1.44", + "1.18.2-40.1.45", + "1.18.2-40.1.46", + "1.18.2-40.1.47", + "1.18.2-40.1.48", + "1.18.2-40.1.51", + "1.18.2-40.1.52", + "1.18.2-40.1.53", + "1.18.2-40.1.54", + "1.18.2-40.1.55", + "1.18.2-40.1.56", + "1.18.2-40.1.57", + "1.18.2-40.1.59", + "1.18.2-40.1.60", + "1.18.2-40.1.61", + "1.18.2-40.1.62", + "1.18.2-40.1.67", + "1.18.2-40.1.68", + "1.18.2-40.1.69", + "1.18.2-40.1.70", + "1.18.2-40.1.71", + "1.18.2-40.1.73", + "1.18.2-40.1.74", + "1.18.2-40.1.75", + "1.18.2-40.1.76", + "1.18.2-40.1.78", + "1.18.2-40.1.79", + "1.18.2-40.1.80", + "1.18.2-40.1.81", + "1.18.2-40.1.82", + "1.18.2-40.1.84", + "1.18.2-40.1.85", + "1.18.2-40.1.86", + "1.18.2-40.1.87", + "1.18.2-40.1.92", + "1.18.2-40.1.93", + "1.18.2-40.2.0", + "1.18.2-40.2.1", + "1.18.2-40.2.2", + "1.18.2-40.2.4", + "1.18.2-40.2.5", + "1.18.2-40.2.6", + "1.18.2-40.2.7", + "1.18.2-40.2.8", + "1.18.2-40.2.9", + "1.18.2-40.2.10", + "1.18.2-40.2.11", + "1.18.2-40.2.13", + "1.18.2-40.2.14", + "1.18.2-40.2.15", + "1.18.2-40.2.17", + "1.18.2-40.2.18", + "1.18.2-40.2.19", + "1.18.2-40.2.21", + "1.18.2-40.2.24", + "1.18.2-40.2.25", + "1.18.2-40.2.26", + "1.18.2-40.2.27", + "1.18.2-40.2.29", + "1.18.2-40.2.31", + "1.18.2-40.2.33", + "1.18.2-40.2.34", + "1.18.2-40.3.0", + "1.18.2-40.3.1", + "1.18.2-40.3.3", + "1.18.2-40.3.6", + "1.18.2-40.3.7", + "1.18.2-40.3.9", + "1.18.2-40.3.10", + "1.18.2-40.3.11" + ], + "1.19": [ + "1.19-41.0.1", + "1.19-41.0.2", + "1.19-41.0.3", + "1.19-41.0.4", + "1.19-41.0.5", + "1.19-41.0.7", + "1.19-41.0.9", + "1.19-41.0.11", + "1.19-41.0.12", + "1.19-41.0.13", + "1.19-41.0.14", + "1.19-41.0.15", + "1.19-41.0.16", + "1.19-41.0.17", + "1.19-41.0.18", + "1.19-41.0.19", + "1.19-41.0.20", + "1.19-41.0.21", + "1.19-41.0.22", + "1.19-41.0.24", + "1.19-41.0.26", + "1.19-41.0.25", + "1.19-41.0.27", + "1.19-41.0.28", + "1.19-41.0.29", + "1.19-41.0.30", + "1.19-41.0.31", + "1.19-41.0.32", + "1.19-41.0.33", + "1.19-41.0.34", + "1.19-41.0.35", + "1.19-41.0.36", + "1.19-41.0.37", + "1.19-41.0.38", + "1.19-41.0.42", + "1.19-41.0.43", + "1.19-41.0.44", + "1.19-41.0.45", + "1.19-41.0.46", + "1.19-41.0.47", + "1.19-41.0.48", + "1.19-41.0.49", + "1.19-41.0.50", + "1.19-41.0.51", + "1.19-41.0.54", + "1.19-41.0.56", + "1.19-41.0.57", + "1.19-41.0.60", + "1.19-41.0.61", + "1.19-41.0.62", + "1.19-41.0.63", + "1.19-41.0.64", + "1.19-41.0.67", + "1.19-41.0.68", + "1.19-41.0.69", + "1.19-41.0.70", + "1.19-41.0.71", + "1.19-41.0.76", + "1.19-41.0.77", + "1.19-41.0.78", + "1.19-41.0.79", + "1.19-41.0.80", + "1.19-41.0.81", + "1.19-41.0.82", + "1.19-41.0.83", + "1.19-41.0.84", + "1.19-41.0.85", + "1.19-41.0.86", + "1.19-41.0.87", + "1.19-41.0.88", + "1.19-41.0.91", + "1.19-41.0.92", + "1.19-41.0.93", + "1.19-41.0.94", + "1.19-41.0.96", + "1.19-41.0.98", + "1.19-41.0.99", + "1.19-41.0.100", + "1.19-41.0.103", + "1.19-41.0.104", + "1.19-41.0.105", + "1.19-41.0.106", + "1.19-41.0.107", + "1.19-41.0.108", + "1.19-41.0.109", + "1.19-41.0.110", + "1.19-41.0.111", + "1.19-41.0.112", + "1.19-41.0.113", + "1.19-41.1.0" + ], + "1.19.1": [ + "1.19.1-42.0.0", + "1.19.1-42.0.1", + "1.19.1-42.0.2", + "1.19.1-42.0.3", + "1.19.1-42.0.4", + "1.19.1-42.0.5", + "1.19.1-42.0.8", + "1.19.1-42.0.9" + ], + "1.19.2": [ + "1.19.2-43.0.0", + "1.19.2-43.0.1", + "1.19.2-43.0.2", + "1.19.2-43.0.3", + "1.19.2-43.0.4", + "1.19.2-43.0.5", + "1.19.2-43.0.7", + "1.19.2-43.0.8", + "1.19.2-43.0.10", + "1.19.2-43.0.11", + "1.19.2-43.0.12", + "1.19.2-43.0.13", + "1.19.2-43.0.15", + "1.19.2-43.0.16", + "1.19.2-43.0.17", + "1.19.2-43.0.18", + "1.19.2-43.0.19", + "1.19.2-43.0.20", + "1.19.2-43.0.21", + "1.19.2-43.0.22", + "1.19.2-43.1.0", + "1.19.2-43.1.1", + "1.19.2-43.1.2", + "1.19.2-43.1.3", + "1.19.2-43.1.4", + "1.19.2-43.1.7", + "1.19.2-43.1.10", + "1.19.2-43.1.12", + "1.19.2-43.1.13", + "1.19.2-43.1.14", + "1.19.2-43.1.15", + "1.19.2-43.1.16", + "1.19.2-43.1.17", + "1.19.2-43.1.23", + "1.19.2-43.1.24", + "1.19.2-43.1.25", + "1.19.2-43.1.26", + "1.19.2-43.1.27", + "1.19.2-43.1.28", + "1.19.2-43.1.29", + "1.19.2-43.1.30", + "1.19.2-43.1.32", + "1.19.2-43.1.33", + "1.19.2-43.1.34", + "1.19.2-43.1.35", + "1.19.2-43.1.36", + "1.19.2-43.1.37", + "1.19.2-43.1.38", + "1.19.2-43.1.39", + "1.19.2-43.1.40", + "1.19.2-43.1.41", + "1.19.2-43.1.42", + "1.19.2-43.1.43", + "1.19.2-43.1.47", + "1.19.2-43.1.52", + "1.19.2-43.1.53", + "1.19.2-43.1.55", + "1.19.2-43.1.57", + "1.19.2-43.1.58", + "1.19.2-43.1.59", + "1.19.2-43.1.60", + "1.19.2-43.1.64", + "1.19.2-43.1.65", + "1.19.2-43.2.0", + "1.19.2-43.1.63", + "1.19.2-43.2.1", + "1.19.2-43.2.2", + "1.19.2-43.2.3", + "1.19.2-43.2.4", + "1.19.2-43.2.5", + "1.19.2-43.2.6", + "1.19.2-43.2.7", + "1.19.2-43.2.8", + "1.19.2-43.2.9", + "1.19.2-43.2.10", + "1.19.2-43.2.11", + "1.19.2-43.2.12", + "1.19.2-43.2.13", + "1.19.2-43.2.14", + "1.19.2-43.2.17", + "1.19.2-43.2.18", + "1.19.2-43.2.19", + "1.19.2-43.2.20", + "1.19.2-43.2.21", + "1.19.2-43.2.22", + "1.19.2-43.2.23", + "1.19.2-43.3.0", + "1.19.2-43.3.2", + "1.19.2-43.3.5", + "1.19.2-43.3.6", + "1.19.2-43.3.7", + "1.19.2-43.3.8", + "1.19.2-43.3.9", + "1.19.2-43.3.10", + "1.19.2-43.3.12", + "1.19.2-43.3.13", + "1.19.2-43.3.14", + "1.19.2-43.4.0", + "1.19.2-43.4.1", + "1.19.2-43.4.2", + "1.19.2-43.4.4", + "1.19.2-43.4.5", + "1.19.2-43.4.6", + "1.19.2-43.4.7", + "1.19.2-43.4.9", + "1.19.2-43.4.10", + "1.19.2-43.4.12", + "1.19.2-43.4.13", + "1.19.2-43.4.16", + "1.19.2-43.4.19", + "1.19.2-43.4.20", + "1.19.2-43.4.22", + "1.19.2-43.4.23", + "1.19.2-43.5.0", + "1.19.2-43.5.1" + ], + "1.19.3": [ + "1.19.3-44.0.0", + "1.19.3-44.0.1", + "1.19.3-44.0.4", + "1.19.3-44.0.5", + "1.19.3-44.0.6", + "1.19.3-44.0.7", + "1.19.3-44.0.10", + "1.19.3-44.0.11", + "1.19.3-44.0.17", + "1.19.3-44.0.18", + "1.19.3-44.0.22", + "1.19.3-44.0.23", + "1.19.3-44.0.29", + "1.19.3-44.0.30", + "1.19.3-44.0.35", + "1.19.3-44.0.36", + "1.19.3-44.0.37", + "1.19.3-44.0.40", + "1.19.3-44.0.41", + "1.19.3-44.0.42", + "1.19.3-44.0.48", + "1.19.3-44.0.49", + "1.19.3-44.1.0", + "1.19.3-44.1.1", + "1.19.3-44.1.2", + "1.19.3-44.1.3", + "1.19.3-44.1.4", + "1.19.3-44.1.5", + "1.19.3-44.1.6", + "1.19.3-44.1.7", + "1.19.3-44.1.8", + "1.19.3-44.1.9", + "1.19.3-44.1.10", + "1.19.3-44.1.12", + "1.19.3-44.1.16", + "1.19.3-44.1.17", + "1.19.3-44.1.18", + "1.19.3-44.1.20", + "1.19.3-44.1.21", + "1.19.3-44.1.22", + "1.19.3-44.1.23" + ], + "1.19.4": [ + "1.19.4-45.0.0", + "1.19.4-45.0.1", + "1.19.4-45.0.4", + "1.19.4-45.0.6", + "1.19.4-45.0.8", + "1.19.4-45.0.9", + "1.19.4-45.0.10", + "1.19.4-45.0.11", + "1.19.4-45.0.12", + "1.19.4-45.0.13", + "1.19.4-45.0.18", + "1.19.4-45.0.19", + "1.19.4-45.0.20", + "1.19.4-45.0.22", + "1.19.4-45.0.23", + "1.19.4-45.0.24", + "1.19.4-45.0.25", + "1.19.4-45.0.26", + "1.19.4-45.0.27", + "1.19.4-45.0.29", + "1.19.4-45.0.30", + "1.19.4-45.0.31", + "1.19.4-45.0.35", + "1.19.4-45.0.36", + "1.19.4-45.0.37", + "1.19.4-45.0.38", + "1.19.4-45.0.39", + "1.19.4-45.0.40", + "1.19.4-45.0.41", + "1.19.4-45.0.42", + "1.19.4-45.0.43", + "1.19.4-45.0.44", + "1.19.4-45.0.45", + "1.19.4-45.0.46", + "1.19.4-45.0.47", + "1.19.4-45.0.49", + "1.19.4-45.0.50", + "1.19.4-45.0.52", + "1.19.4-45.0.53", + "1.19.4-45.0.55", + "1.19.4-45.0.57", + "1.19.4-45.0.58", + "1.19.4-45.0.59", + "1.19.4-45.0.63", + "1.19.4-45.0.64", + "1.19.4-45.0.66", + "1.19.4-45.1.0", + "1.19.4-45.1.2", + "1.19.4-45.1.4", + "1.19.4-45.1.5", + "1.19.4-45.1.6", + "1.19.4-45.1.7", + "1.19.4-45.1.8", + "1.19.4-45.1.9", + "1.19.4-45.1.10", + "1.19.4-45.1.11", + "1.19.4-45.1.12", + "1.19.4-45.1.13", + "1.19.4-45.1.14", + "1.19.4-45.1.15", + "1.19.4-45.1.16", + "1.19.4-45.1.17", + "1.19.4-45.1.18", + "1.19.4-45.1.19", + "1.19.4-45.2.0", + "1.19.4-45.2.2", + "1.19.4-45.2.3", + "1.19.4-45.2.4", + "1.19.4-45.2.6", + "1.19.4-45.2.7", + "1.19.4-45.2.8", + "1.19.4-45.2.9", + "1.19.4-45.2.10", + "1.19.4-45.2.12", + "1.19.4-45.2.14", + "1.19.4-45.2.15", + "1.19.4-45.2.16", + "1.19.4-45.3.0", + "1.19.4-45.3.1", + "1.19.4-45.3.2", + "1.19.4-45.3.3", + "1.19.4-45.3.6", + "1.19.4-45.3.7", + "1.19.4-45.3.8", + "1.19.4-45.3.9", + "1.19.4-45.3.10", + "1.19.4-45.3.12", + "1.19.4-45.3.13", + "1.19.4-45.3.15", + "1.19.4-45.3.17", + "1.19.4-45.3.20", + "1.19.4-45.3.23", + "1.19.4-45.3.24", + "1.19.4-45.3.27", + "1.19.4-45.4.0", + "1.19.4-45.4.1", + "1.19.4-45.4.2" + ], + "1.20": [ + "1.20-46.0.1", + "1.20-46.0.2", + "1.20-46.0.10", + "1.20-46.0.11", + "1.20-46.0.12", + "1.20-46.0.13", + "1.20-46.0.14" + ], + "1.20.1": [ + "1.20.1-47.0.0", + "1.20.1-47.0.1", + "1.20.1-47.0.2", + "1.20.1-47.0.3", + "1.20.1-47.0.4", + "1.20.1-47.0.5", + "1.20.1-47.0.6", + "1.20.1-47.0.14", + "1.20.1-47.0.15", + "1.20.1-47.0.16", + "1.20.1-47.0.17", + "1.20.1-47.0.18", + "1.20.1-47.0.19", + "1.20.1-47.0.34", + "1.20.1-47.0.35", + "1.20.1-47.0.39", + "1.20.1-47.0.42", + "1.20.1-47.0.43", + "1.20.1-47.0.44", + "1.20.1-47.0.45", + "1.20.1-47.0.46", + "1.20.1-47.0.49", + "1.20.1-47.0.50", + "1.20.1-47.1.0", + "1.20.1-47.1.1", + "1.20.1-47.1.3", + "1.20.1-47.1.4", + "1.20.1-47.1.5", + "1.20.1-47.1.6", + "1.20.1-47.1.7", + "1.20.1-47.1.8", + "1.20.1-47.1.10", + "1.20.1-47.1.12", + "1.20.1-47.1.13", + "1.20.1-47.1.14", + "1.20.1-47.1.15", + "1.20.1-47.1.16", + "1.20.1-47.1.17", + "1.20.1-47.1.18", + "1.20.1-47.1.19", + "1.20.1-47.1.21", + "1.20.1-47.1.22", + "1.20.1-47.1.23", + "1.20.1-47.1.25", + "1.20.1-47.1.26", + "1.20.1-47.1.27", + "1.20.1-47.1.28", + "1.20.1-47.1.29", + "1.20.1-47.1.30", + "1.20.1-47.1.32", + "1.20.1-47.1.33", + "1.20.1-47.1.36", + "1.20.1-47.1.37", + "1.20.1-47.1.39", + "1.20.1-47.1.40", + "1.20.1-47.1.41", + "1.20.1-47.1.42", + "1.20.1-47.1.43", + "1.20.1-47.1.44", + "1.20.1-47.1.46", + "1.20.1-47.1.47", + "1.20.1-47.2.0", + "1.20.1-47.2.1", + "1.20.1-47.2.4", + "1.20.1-47.2.5", + "1.20.1-47.2.6", + "1.20.1-47.2.7", + "1.20.1-47.2.8", + "1.20.1-47.2.14", + "1.20.1-47.2.16", + "1.20.1-47.2.17", + "1.20.1-47.2.18", + "1.20.1-47.2.19", + "1.20.1-47.2.20", + "1.20.1-47.2.21", + "1.20.1-47.2.23", + "1.20.1-47.2.29", + "1.20.1-47.2.30", + "1.20.1-47.2.31", + "1.20.1-47.2.32", + "1.20.1-47.2.36", + "1.20.1-47.3.0", + "1.20.1-47.3.1", + "1.20.1-47.3.2", + "1.20.1-47.3.3", + "1.20.1-47.3.4", + "1.20.1-47.3.5", + "1.20.1-47.3.6", + "1.20.1-47.3.7", + "1.20.1-47.3.10", + "1.20.1-47.3.11", + "1.20.1-47.3.12", + "1.20.1-47.3.13", + "1.20.1-47.3.14", + "1.20.1-47.3.15", + "1.20.1-47.3.16", + "1.20.1-47.3.19", + "1.20.1-47.3.20", + "1.20.1-47.3.22", + "1.20.1-47.3.24", + "1.20.1-47.3.25", + "1.20.1-47.3.27", + "1.20.1-47.3.28", + "1.20.1-47.3.29", + "1.20.1-47.3.31", + "1.20.1-47.3.32", + "1.20.1-47.3.33", + "1.20.1-47.3.34", + "1.20.1-47.3.37", + "1.20.1-47.3.38", + "1.20.1-47.3.39", + "1.20.1-47.4.0", + "1.20.1-47.4.1", + "1.20.1-47.4.2", + "1.20.1-47.4.3", + "1.20.1-47.4.4", + "1.20.1-47.4.5", + "1.20.1-47.4.6", + "1.20.1-47.4.8" + ], + "1.20.2": [ + "1.20.2-48.0.0", + "1.20.2-48.0.1", + "1.20.2-48.0.4", + "1.20.2-48.0.6", + "1.20.2-48.0.7", + "1.20.2-48.0.8", + "1.20.2-48.0.10", + "1.20.2-48.0.11", + "1.20.2-48.0.12", + "1.20.2-48.0.13", + "1.20.2-48.0.17", + "1.20.2-48.0.18", + "1.20.2-48.0.19", + "1.20.2-48.0.20", + "1.20.2-48.0.22", + "1.20.2-48.0.23", + "1.20.2-48.0.24", + "1.20.2-48.0.26", + "1.20.2-48.0.29", + "1.20.2-48.0.30", + "1.20.2-48.0.31", + "1.20.2-48.0.32", + "1.20.2-48.0.33", + "1.20.2-48.0.34", + "1.20.2-48.0.35", + "1.20.2-48.0.36", + "1.20.2-48.0.37", + "1.20.2-48.0.38", + "1.20.2-48.0.39", + "1.20.2-48.0.40", + "1.20.2-48.0.41", + "1.20.2-48.0.42", + "1.20.2-48.0.43", + "1.20.2-48.0.44", + "1.20.2-48.0.45", + "1.20.2-48.0.47", + "1.20.2-48.0.48", + "1.20.2-48.0.49", + "1.20.2-48.1.0" + ], + "1.20.3": [ + "1.20.3-49.0.1", + "1.20.3-49.0.2" + ], + "1.20.4": [ + "1.20.4-49.0.3", + "1.20.4-49.0.4", + "1.20.4-49.0.7", + "1.20.4-49.0.8", + "1.20.4-49.0.9", + "1.20.4-49.0.10", + "1.20.4-49.0.11", + "1.20.4-49.0.12", + "1.20.4-49.0.13", + "1.20.4-49.0.14", + "1.20.4-49.0.16", + "1.20.4-49.0.19", + "1.20.4-49.0.21", + "1.20.4-49.0.22", + "1.20.4-49.0.24", + "1.20.4-49.0.26", + "1.20.4-49.0.27", + "1.20.4-49.0.28", + "1.20.4-49.0.30", + "1.20.4-49.0.31", + "1.20.4-49.0.32", + "1.20.4-49.0.33", + "1.20.4-49.0.34", + "1.20.4-49.0.38", + "1.20.4-49.0.39", + "1.20.4-49.0.40", + "1.20.4-49.0.41", + "1.20.4-49.0.42", + "1.20.4-49.0.43", + "1.20.4-49.0.45", + "1.20.4-49.0.46", + "1.20.4-49.0.48", + "1.20.4-49.0.49", + "1.20.4-49.0.50", + "1.20.4-49.0.51", + "1.20.4-49.0.52", + "1.20.4-49.0.53", + "1.20.4-49.1.0", + "1.20.4-49.1.1", + "1.20.4-49.1.2", + "1.20.4-49.1.3", + "1.20.4-49.1.4", + "1.20.4-49.1.5", + "1.20.4-49.1.8", + "1.20.4-49.1.10", + "1.20.4-49.1.12", + "1.20.4-49.1.13", + "1.20.4-49.1.14", + "1.20.4-49.1.15", + "1.20.4-49.1.16", + "1.20.4-49.1.17", + "1.20.4-49.1.19", + "1.20.4-49.1.21", + "1.20.4-49.1.22", + "1.20.4-49.1.23", + "1.20.4-49.1.25", + "1.20.4-49.1.26", + "1.20.4-49.1.27", + "1.20.4-49.1.29", + "1.20.4-49.1.32", + "1.20.4-49.1.33", + "1.20.4-49.1.34", + "1.20.4-49.1.35", + "1.20.4-49.1.36", + "1.20.4-49.1.37", + "1.20.4-49.1.40", + "1.20.4-49.1.41", + "1.20.4-49.2.0", + "1.20.4-49.2.1" + ], + "1.20.6": [ + "1.20.6-50.0.0", + "1.20.6-50.0.1", + "1.20.6-50.0.2", + "1.20.6-50.0.4", + "1.20.6-50.0.5", + "1.20.6-50.0.6", + "1.20.6-50.0.7", + "1.20.6-50.0.8", + "1.20.6-50.0.9", + "1.20.6-50.0.10", + "1.20.6-50.0.11", + "1.20.6-50.0.12", + "1.20.6-50.0.13", + "1.20.6-50.0.14", + "1.20.6-50.0.15", + "1.20.6-50.0.16", + "1.20.6-50.0.17", + "1.20.6-50.0.18", + "1.20.6-50.0.19", + "1.20.6-50.0.20", + "1.20.6-50.0.21", + "1.20.6-50.0.22", + "1.20.6-50.0.24", + "1.20.6-50.0.25", + "1.20.6-50.0.26", + "1.20.6-50.0.28", + "1.20.6-50.0.29", + "1.20.6-50.0.30", + "1.20.6-50.0.31", + "1.20.6-50.0.34", + "1.20.6-50.0.36", + "1.20.6-50.0.37", + "1.20.6-50.1.0", + "1.20.6-50.1.1", + "1.20.6-50.1.2", + "1.20.6-50.1.3", + "1.20.6-50.1.4", + "1.20.6-50.1.5", + "1.20.6-50.1.6", + "1.20.6-50.1.7", + "1.20.6-50.1.8", + "1.20.6-50.1.9", + "1.20.6-50.1.10", + "1.20.6-50.1.12", + "1.20.6-50.1.13", + "1.20.6-50.1.14", + "1.20.6-50.1.15", + "1.20.6-50.1.16", + "1.20.6-50.1.17", + "1.20.6-50.1.18", + "1.20.6-50.1.19", + "1.20.6-50.1.20", + "1.20.6-50.1.21", + "1.20.6-50.1.22", + "1.20.6-50.1.23", + "1.20.6-50.1.24", + "1.20.6-50.1.25", + "1.20.6-50.1.26", + "1.20.6-50.1.27", + "1.20.6-50.1.29", + "1.20.6-50.1.30", + "1.20.6-50.1.31", + "1.20.6-50.1.32", + "1.20.6-50.1.34", + "1.20.6-50.1.35", + "1.20.6-50.1.37", + "1.20.6-50.1.39", + "1.20.6-50.1.42", + "1.20.6-50.1.43", + "1.20.6-50.1.45", + "1.20.6-50.1.46", + "1.20.6-50.1.47", + "1.20.6-50.1.48", + "1.20.6-50.1.51", + "1.20.6-50.2.0", + "1.20.6-50.2.1" + ], + "1.21": [ + "1.21-51.0.0", + "1.21-51.0.1", + "1.21-51.0.3", + "1.21-51.0.4", + "1.21-51.0.5", + "1.21-51.0.6", + "1.21-51.0.7", + "1.21-51.0.8", + "1.21-51.0.13", + "1.21-51.0.15", + "1.21-51.0.16", + "1.21-51.0.17", + "1.21-51.0.18", + "1.21-51.0.21", + "1.21-51.0.22", + "1.21-51.0.23", + "1.21-51.0.24", + "1.21-51.0.25", + "1.21-51.0.26", + "1.21-51.0.28", + "1.21-51.0.29", + "1.21-51.0.30", + "1.21-51.0.31", + "1.21-51.0.32", + "1.21-51.0.33" + ], + "1.21.1": [ + "1.21.1-52.0.0", + "1.21.1-52.0.1", + "1.21.1-52.0.2", + "1.21.1-52.0.3", + "1.21.1-52.0.4", + "1.21.1-52.0.5", + "1.21.1-52.0.6", + "1.21.1-52.0.7", + "1.21.1-52.0.8", + "1.21.1-52.0.9", + "1.21.1-52.0.10", + "1.21.1-52.0.11", + "1.21.1-52.0.12", + "1.21.1-52.0.13", + "1.21.1-52.0.15", + "1.21.1-52.0.16", + "1.21.1-52.0.17", + "1.21.1-52.0.18", + "1.21.1-52.0.19", + "1.21.1-52.0.20", + "1.21.1-52.0.21", + "1.21.1-52.0.22", + "1.21.1-52.0.23", + "1.21.1-52.0.24", + "1.21.1-52.0.25", + "1.21.1-52.0.26", + "1.21.1-52.0.27", + "1.21.1-52.0.28", + "1.21.1-52.0.29", + "1.21.1-52.0.30", + "1.21.1-52.0.32", + "1.21.1-52.0.33", + "1.21.1-52.0.34", + "1.21.1-52.0.35", + "1.21.1-52.0.36", + "1.21.1-52.0.37", + "1.21.1-52.0.38", + "1.21.1-52.0.39", + "1.21.1-52.0.40", + "1.21.1-52.0.42", + "1.21.1-52.0.45", + "1.21.1-52.0.47", + "1.21.1-52.0.48", + "1.21.1-52.0.49", + "1.21.1-52.0.50", + "1.21.1-52.0.51", + "1.21.1-52.0.52", + "1.21.1-52.0.53", + "1.21.1-52.0.56", + "1.21.1-52.0.57", + "1.21.1-52.1.0", + "1.21.1-52.1.1", + "1.21.1-52.1.2", + "1.21.1-52.1.3" + ], + "1.21.3": [ + "1.21.3-53.0.0", + "1.21.3-53.0.1", + "1.21.3-53.0.2", + "1.21.3-53.0.3", + "1.21.3-53.0.4", + "1.21.3-53.0.5", + "1.21.3-53.0.7", + "1.21.3-53.0.8", + "1.21.3-53.0.9", + "1.21.3-53.0.10", + "1.21.3-53.0.11", + "1.21.3-53.0.12", + "1.21.3-53.0.13", + "1.21.3-53.0.14", + "1.21.3-53.0.17", + "1.21.3-53.0.19", + "1.21.3-53.0.21", + "1.21.3-53.0.23", + "1.21.3-53.0.24", + "1.21.3-53.0.25", + "1.21.3-53.0.26", + "1.21.3-53.0.27", + "1.21.3-53.0.28", + "1.21.3-53.0.29", + "1.21.3-53.0.30", + "1.21.3-53.0.32", + "1.21.3-53.0.33", + "1.21.3-53.0.34", + "1.21.3-53.0.35", + "1.21.3-53.0.36", + "1.21.3-53.0.37", + "1.21.3-53.0.39", + "1.21.3-53.0.42", + "1.21.3-53.0.44", + "1.21.3-53.0.45", + "1.21.3-53.0.47", + "1.21.3-53.0.48", + "1.21.3-53.0.49", + "1.21.3-53.0.51", + "1.21.3-53.0.52", + "1.21.3-53.0.53", + "1.21.3-53.0.55", + "1.21.3-53.1.0", + "1.21.3-53.1.1", + "1.21.3-53.1.2" + ], + "1.21.4": [ + "1.21.4-54.0.0", + "1.21.4-54.0.1", + "1.21.4-54.0.3", + "1.21.4-54.0.5", + "1.21.4-54.0.6", + "1.21.4-54.0.7", + "1.21.4-54.0.9", + "1.21.4-54.0.10", + "1.21.4-54.0.11", + "1.21.4-54.0.12", + "1.21.4-54.0.13", + "1.21.4-54.0.14", + "1.21.4-54.0.15", + "1.21.4-54.0.16", + "1.21.4-54.0.17", + "1.21.4-54.0.18", + "1.21.4-54.0.20", + "1.21.4-54.0.21", + "1.21.4-54.0.24", + "1.21.4-54.0.25", + "1.21.4-54.0.26", + "1.21.4-54.0.27", + "1.21.4-54.0.29", + "1.21.4-54.0.30", + "1.21.4-54.0.31", + "1.21.4-54.0.32", + "1.21.4-54.0.33", + "1.21.4-54.0.34", + "1.21.4-54.0.35", + "1.21.4-54.0.36", + "1.21.4-54.0.37", + "1.21.4-54.0.38", + "1.21.4-54.1.0", + "1.21.4-54.1.1", + "1.21.4-54.1.2", + "1.21.4-54.1.3", + "1.21.4-54.1.4", + "1.21.4-54.1.5", + "1.21.4-54.1.6" + ], + "1.21.5": [ + "1.21.5-55.0.0", + "1.21.5-55.0.1", + "1.21.5-55.0.2", + "1.21.5-55.0.3", + "1.21.5-55.0.4", + "1.21.5-55.0.5", + "1.21.5-55.0.6", + "1.21.5-55.0.7", + "1.21.5-55.0.8", + "1.21.5-55.0.9", + "1.21.5-55.0.10", + "1.21.5-55.0.11", + "1.21.5-55.0.12", + "1.21.5-55.0.14", + "1.21.5-55.0.15", + "1.21.5-55.0.16", + "1.21.5-55.0.17", + "1.21.5-55.0.19", + "1.21.5-55.0.20", + "1.21.5-55.0.21", + "1.21.5-55.0.22", + "1.21.5-55.0.23", + "1.21.5-55.0.24", + "1.21.5-55.0.25", + "1.21.5-55.1.0" + ], + "1.21.6": [ + "1.21.6-56.0.0", + "1.21.6-56.0.1", + "1.21.6-56.0.2", + "1.21.6-56.0.3", + "1.21.6-56.0.4", + "1.21.6-56.0.5", + "1.21.6-56.0.6", + "1.21.6-56.0.7", + "1.21.6-56.0.8", + "1.21.6-56.0.9" + ], + "1.21.7": [ + "1.21.7-57.0.0", + "1.21.7-57.0.1", + "1.21.7-57.0.2", + "1.21.7-57.0.3" + ], + "1.21.8": [ + "1.21.8-58.0.0", + "1.21.8-58.0.1", + "1.21.8-58.0.2", + "1.21.8-58.0.3", + "1.21.8-58.0.4", + "1.21.8-58.0.5", + "1.21.8-58.0.6", + "1.21.8-58.0.7", + "1.21.8-58.0.8", + "1.21.8-58.0.9", + "1.21.8-58.0.10", + "1.21.8-58.1.0", + "1.21.8-58.1.1", + "1.21.8-58.1.2" + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a7062999..928d4338 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,112 +1,165 @@ { "name": "minecraft-java-core", - "version": "3.5.7", + "version": "4.2.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "minecraft-java-core", - "version": "3.5.7", + "version": "4.2.3", "license": "CCANC", "dependencies": { - "adm-zip": "^0.5.9", - "minecraft-loader": "^1.3.0", - "node-fetch": "^2.6.9", - "prompt": "^1.2.1", - "tslib": "^2.4.1" + "prompt": "^1.3.0", + "semver": "^7.7.2", + "tslib": "^2.8.1" }, "devDependencies": { - "@types/node": "^18.11.13", - "@types/node-fetch": "^2.6.2", - "rimraf": "^3.0.2", - "typescript": "^4.9.4" + "@types/node": "^22.10.2", + "@types/semver": "^7.7.0", + "rimraf": "^6.0.1", + "typescript": "^5.7.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "license": "MIT", "engines": { "node": ">=0.1.90" } }, - "node_modules/@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", - "dev": true + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } }, - "node_modules/@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "node_modules/@types/node": { + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" + "undici-types": "~6.20.0" } }, - "node_modules/adm-zip": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", - "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", + "node_modules/@types/semver": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=6.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/async": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "license": "MIT" }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/colors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==", + "license": "MIT", "engines": { "node": ">=0.1.90" } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { - "delayed-stream": "~1.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 8" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, "node_modules/cycle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", @@ -115,14 +168,19 @@ "node": ">=0.4.0" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, - "engines": { - "node": ">=0.4.0" - } + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" }, "node_modules/eyes": { "version": "0.1.8", @@ -132,160 +190,173 @@ "node": "> 0.1.90" } }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, + "license": "ISC", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">= 6" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", "dev": true, + "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "license": "MIT" + }, + "node_modules/jackspeak": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", + "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/lru-cache": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", + "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", "dev": true, + "license": "ISC", "engines": { - "node": ">= 0.6" + "node": "20 || >=22" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "dev": true, + "license": "ISC", "dependencies": { - "mime-db": "1.52.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minecraft-loader": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/minecraft-loader/-/minecraft-loader-1.3.0.tgz", - "integrity": "sha512-r+tXeGBb8CyIVfpLTL1fdG7GQv0yfzygktYk3BVWMYNFLhd3nGBxN/HCR5Lo53iir8m9P/2X9S2jGJ74BDqbHQ==", - "dependencies": { - "adm-zip": "^0.5.10", - "node-fetch": "^2.6.9" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "ISC", "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" } }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "license": "ISC" }, - "node_modules/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "dependencies": { - "wrappy": "1" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, "engines": { - "node": ">=0.10.0" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/prompt": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.3.0.tgz", "integrity": "sha512-ZkaRWtaLBZl7KKAKndKYUL8WqNT+cQHKRZnT4RYYms48jQkFw3rrBL+/N5K/KtdEveHkxs982MX2BkDKub2ZMg==", + "license": "MIT", "dependencies": { "@colors/colors": "1.5.0", "async": "3.2.3", @@ -301,6 +372,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "license": "ISC", "dependencies": { "mute-stream": "~0.0.4" }, @@ -312,20 +384,74 @@ "version": "0.1.8", "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", "integrity": "sha512-xcBILK2pA9oh4SiinPEZfhP8HfrB/ha+a2fTMyl7Om2WjlDVrOQy99N2MXXlUHqGJz4qEu2duXxHJjDWuK/0xg==", + "license": "Apache 2.0", "engines": { "node": ">= 0.4.0" } }, "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dev": true, + "license": "ISC", "dependencies": { - "glob": "^7.1.3" + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", "bin": { - "rimraf": "bin.js" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -335,51 +461,163 @@ "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", "engines": { "node": "*" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, "node_modules/winston": { "version": "2.4.7", "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.7.tgz", "integrity": "sha512-vLB4BqzCKDnnZH9PHGoS2ycawueX4HLqENXQitvFHczhgW2vFpSOn31LZtVr1KU8YTw7DS4tM+cqyovxo8taVg==", + "license": "MIT", "dependencies": { "async": "^2.6.4", "colors": "1.0.x", @@ -396,15 +634,108 @@ "version": "2.6.4", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", "dependencies": { "lodash": "^4.17.14" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } } } } diff --git a/package.json b/package.json index a68e30da..56072a91 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minecraft-java-core", - "version": "3.5.7", + "version": "4.2.3", "types": "./build/Index.d.ts", "exports": { ".": { @@ -11,7 +11,11 @@ "description": "A library starting minecraft game NW.js and Electron.js", "scripts": { "dev": "rimraf ./build && tsc -w", - "build": "rimraf ./build && tsc" + "build": "rimraf ./build && tsc", + "prepublishOnly": "npm i && npm run build" + }, + "engines": { + "node": ">=18.0.0" }, "files": [ "assets/**", @@ -31,17 +35,15 @@ "author": "Luuxis", "license": "CCANC", "dependencies": { - "adm-zip": "^0.5.9", - "minecraft-loader": "^1.3.0", - "node-fetch": "^2.6.9", - "prompt": "^1.2.1", - "tslib": "^2.4.1" + "prompt": "^1.3.0", + "semver": "^7.7.2", + "tslib": "^2.8.1" }, "devDependencies": { - "@types/node": "^18.11.13", - "@types/node-fetch": "^2.6.2", - "rimraf": "^3.0.2", - "typescript": "^4.9.4" + "@types/node": "^22.10.2", + "@types/semver": "^7.7.0", + "rimraf": "^6.0.1", + "typescript": "^5.7.2" }, "bugs": { "url": "https://github.com/luuxis/minecraft-java-core/issues" diff --git a/src/Authenticator/AZauth.ts b/src/Authenticator/AZauth.ts index 819e4c2d..d52e7731 100755 --- a/src/Authenticator/AZauth.ts +++ b/src/Authenticator/AZauth.ts @@ -1,105 +1,211 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ -import nodeFetch from 'node-fetch'; +import { Buffer } from 'node:buffer'; + +// This interface defines the structure of the user object +// returned by the AZauth service. You can adapt it to your needs. +interface AZauthUser { + access_token?: string; + client_token?: string; + uuid?: string; + name?: string; + user_properties?: string; + user_info?: { + id?: string; + banned?: boolean; + money?: number; + role?: string; + verified?: boolean; + }; + meta?: { + online: boolean; + type: string; + }; + profile?: { + skins: Array<{ + url: string; + base64?: string; + }>; + }; + // Error-related fields + error?: boolean; + reason?: string; + message?: string; + A2F?: boolean; +} export default class AZauth { - url: string; - constructor(url: string) { - this.url = `${url}/api/auth`; - } - - async login(username: string, password: string, A2F: any = null) { - let response = await nodeFetch(`${this.url}/authenticate`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - email: username, - password: password, - code: A2F - }), - }).then((res: any) => res.json()) - - if (response.status == 'pending' && response.reason == '2fa') { - return { A2F: true }; - } - - if (response.status == 'error') { - return { - error: true, - reason: response.reason, - message: response.message - }; - } - - return { - access_token: response.access_token, - client_token: response.uuid, - uuid: response.uuid, - name: response.username, - user_properties: '{}', - user_info: { - banned: response.banned, - money: response.money, - role: response.role - }, - meta: { - online: false, - type: 'AZauth', - } - } - } - - async verify(user: any) { - let response = await nodeFetch(`${this.url}/verify`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - access_token: user.access_token - }), - }).then((res: any) => res.json()) - - if (response.status == 'error') { - return { - error: true, - reason: response.reason, - message: response.message - }; - } - - return { - access_token: response.access_token, - client_token: response.uuid, - uuid: response.uuid, - name: response.username, - user_properties: '{}', - user_info: { - banned: response.banned, - money: response.money, - role: response.role - }, - meta: { - online: false, - type: 'AZauth', - } - } - } - - async signout(user: any) { - let auth = await nodeFetch(`${this.url}/logout`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - access_token: user.access_token - }), - }).then((res: any) => res.json()) - if (auth.error) return false; - return true - } -} \ No newline at end of file + private url: string; + private skinAPI: string; + + /** + * The constructor prepares the authentication and skin URLs from the base URL. + * @param url The base URL of the AZauth server + */ + constructor(url: string) { + // '/api/auth' for authentication, '/api/skin-api/skins' for skin data + this.url = new URL('/api/auth', url).toString(); + this.skinAPI = new URL('/api/skin-api/skins', url).toString(); + } + + /** + * Authenticates a user using their username/email and password. + * Optionally, a 2FA code can be provided. + * + * @param username The email or username for authentication + * @param password The password + * @param A2F Optional 2FA code + * @returns A Promise that resolves to an AZauthUser object + */ + public async login(username: string, password: string, A2F: string | null = null): Promise { + const response = await fetch(`${this.url}/authenticate`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + email: username, + password, + code: A2F + }) + }); + + const data = await response.json(); + + // If the server indicates that 2FA is required + if (data.status === 'pending' && data.reason === '2fa') { + return { A2F: true }; + } + + // If the server returns an error status + if (data.status === 'error') { + return { + error: true, + reason: data.reason, + message: data.message + }; + } + + // If authentication is successful, return the complete user object + return { + access_token: data.access_token, + client_token: data.uuid, + uuid: data.uuid, + name: data.username, + user_properties: '{}', + user_info: { + id: data.id, + banned: data.banned, + money: data.money, + role: data.role, + verified: data.email_verified + }, + meta: { + online: false, + type: 'AZauth' + }, + profile: { + skins: [await this.skin(data.id)] + } + }; + } + + /** + * Verifies an existing session (e.g., for refreshing tokens). + * @param user An AZauthUser object containing at least the access token + * @returns A Promise that resolves to an updated AZauthUser object or an error object + */ + public async verify(user: AZauthUser): Promise { + const response = await fetch(`${this.url}/verify`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + access_token: user.access_token + }) + }); + + const data = await response.json(); + + // If the server indicates an error + if (data.status === 'error') { + return { + error: true, + reason: data.reason, + message: data.message + }; + } + + // Return the updated user session object + return { + access_token: data.access_token, + client_token: data.uuid, + uuid: data.uuid, + name: data.username, + user_properties: '{}', + user_info: { + id: data.id, + banned: data.banned, + money: data.money, + role: data.role, + verified: data.email_verified + }, + meta: { + online: false, + type: 'AZauth' + }, + profile: { + skins: [await this.skin(data.id)] + } + }; + } + + /** + * Logs out a user from the AZauth service (invalidates the token). + * @param user The AZauthUser object with a valid access token + * @returns A Promise that resolves to true if logout is successful, otherwise false + */ + public async signout(user: AZauthUser): Promise { + const response = await fetch(`${this.url}/logout`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + access_token: user.access_token + }) + }); + + const data = await response.json(); + if (data.error) return false; + return true; + } + + /** + * Retrieves the skin of a user by their ID (UUID). + * If the skin exists, returns both the direct URL and a base64-encoded PNG. + * If the skin doesn't exist, only the URL is returned. + * + * @param uuid The UUID or ID of the user + * @returns A Promise resolving to an object with the skin URL (and optional base64 data) + */ + private async skin(uuid: string): Promise<{ url: string; base64?: string }> { + let response = await fetch(`${this.skinAPI}/${uuid}`, { + method: 'GET', + headers: { 'Content-Type': 'application/json' } + }); + + // If the skin is not found (404), return only the URL + if (response.status === 404) { + return { + url: `${this.skinAPI}/${uuid}` + }; + } + + // Otherwise, convert the skin image to a base64-encoded string + const arrayBuffer = await response.arrayBuffer(); + const buffer = Buffer.from(arrayBuffer); + return { + url: `${this.skinAPI}/${uuid}`, + base64: `data:image/png;base64,${buffer.toString('base64')}` + }; + } +} diff --git a/src/Authenticator/GUI/Electron.ts b/src/Authenticator/GUI/Electron.ts index db0d6f70..7196a921 100755 --- a/src/Authenticator/GUI/Electron.ts +++ b/src/Authenticator/GUI/Electron.ts @@ -1,6 +1,6 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ const path = require('path') @@ -14,7 +14,7 @@ const defaultProperties = { icon: path.join(__dirname, '../../../assets/icons', `Microsoft.${(process.platform === 'win32') ? 'ico' : 'png'}`), } -module.exports = async function (url: string) { +module.exports = async function (url: string, redirect_uri: string = "https://login.live.com/oauth20_desktop.srf") { await new Promise((resolve: any) => { app.whenReady().then(() => { session.defaultSession.cookies.get({ domain: 'live.com' }).then((cookies: any) => { @@ -40,7 +40,7 @@ module.exports = async function (url: string) { mainWindow.webContents.on("did-finish-load", () => { const loc = mainWindow.webContents.getURL(); - if (loc.startsWith("https://login.live.com/oauth20_desktop.srf")) { + if (loc.startsWith(redirect_uri)) { const urlParams = new URLSearchParams(loc.substr(loc.indexOf("?") + 1)).get("code"); if (urlParams) { resolve(urlParams); diff --git a/src/Authenticator/GUI/NW.ts b/src/Authenticator/GUI/NW.ts index 0985f61a..1fe3f8d7 100755 --- a/src/Authenticator/GUI/NW.ts +++ b/src/Authenticator/GUI/NW.ts @@ -1,9 +1,8 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ -'use strict'; import path from 'path'; const defaultProperties = { @@ -15,7 +14,7 @@ const defaultProperties = { icon: path.join(__dirname, '../../../assets/icons/Microsoft.png') } -module.exports = async function (url: string) { +module.exports = async function (url: string, redirect_uri: string = "https://login.live.com/oauth20_desktop.srf") { await new Promise((resolve: any) => { //@ts-ignore nw.Window.get().cookies.getAll({ domain: "live.com" }, async (cookies) => { @@ -34,7 +33,7 @@ module.exports = async function (url: string) { let interval = null; let code; interval = setInterval(() => { - if (Window.window.document.location.href.startsWith("https://login.live.com/oauth20_desktop.srf")) { + if (Window.window.document.location.href.startsWith(redirect_uri)) { clearInterval(interval); try { code = Window.window.document.location.href.split("code=")[1].split("&")[0]; diff --git a/src/Authenticator/GUI/Terminal.ts b/src/Authenticator/GUI/Terminal.ts index 0349fb4c..9eddb839 100755 --- a/src/Authenticator/GUI/Terminal.ts +++ b/src/Authenticator/GUI/Terminal.ts @@ -1,6 +1,6 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ import prompt from 'prompt'; diff --git a/src/Authenticator/Microsoft.ts b/src/Authenticator/Microsoft.ts index d5a14e31..8b7aa6cd 100755 --- a/src/Authenticator/Microsoft.ts +++ b/src/Authenticator/Microsoft.ts @@ -1,212 +1,348 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ -import nodeFetch from 'node-fetch'; +import { Buffer } from 'node:buffer'; import crypto from 'crypto'; +// Possible client types (Electron, NW.js, or terminal usage) +export type MicrosoftClientType = 'electron' | 'nwjs' | 'terminal'; -export default class Microsoft { - client_id: string; - type: 'electron' | 'nwjs' | 'terminal'; - - constructor(client_id: string) { - if (client_id === '' || !client_id) client_id = '00000000402b5328'; - this.client_id = client_id; - - if (!!process && !!process.versions && !!process.versions.electron) { - this.type = 'electron'; - } else if (!!process && !!process.versions && !!process.versions.nw) { - this.type = 'nwjs'; - } else { - this.type = 'terminal'; - } - } - - async getAuth(type: string, url: string) { - if (!url) url = `https://login.live.com/oauth20_authorize.srf?client_id=${this.client_id}&response_type=code&redirect_uri=https://login.live.com/oauth20_desktop.srf&scope=XboxLive.signin%20offline_access&cobrandid=8058f65d-ce06-4c30-9559-473c9275a65d&prompt=select_account`; - if (!type) type = this.type; - - if (type == "electron") { - let usercode = await (require('./GUI/Electron.js'))(url) - if (usercode === "cancel") return false; - else return await this.url(usercode); - } else if (type == "nwjs") { - let usercode = await (require('./GUI/NW.js'))(url) - if (usercode === "cancel") return false; - else return await this.url(usercode); - } else if (type == "terminal") { - let usercode = await (require('./GUI/Terminal.js'))(url) - if (usercode === "cancel") return false; - else return await this.url(usercode); - } - } - - async url(code: string) { - let oauth2 = await nodeFetch("https://login.live.com/oauth20_token.srf", { - method: "POST", - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - }, - body: `client_id=${this.client_id}&code=${code}&grant_type=authorization_code&redirect_uri=https://login.live.com/oauth20_desktop.srf` - }).then(res => res.json()).catch(err => { return { error: err } });; - if (oauth2.error) return oauth2; - return await this.getAccount(oauth2) - } - - async refresh(acc: any) { - let timeStamp = Math.floor(Date.now() / 1000) - let oauth2 = await nodeFetch("https://login.live.com/oauth20_token.srf", { - method: "POST", - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - }, - body: `grant_type=refresh_token&client_id=${this.client_id}&refresh_token=${acc.refresh_token}` - }).then(res => res.json()).catch(err => { return { error: err } });; - if (oauth2.error) { - oauth2.errorType = "oauth2"; - return oauth2 - }; - - if (timeStamp < (acc?.meta?.access_token_expires_in - 7200)) { - let profile = await this.getProfile(acc) - acc.refresh_token = oauth2.refresh_token - acc.profile = { - skins: profile.skins, - capes: profile.capes - } - return acc - } else { - return await this.getAccount(oauth2) - } - } - - async getAccount(oauth2: any) { - let xbl = await nodeFetch("https://user.auth.xboxlive.com/user/authenticate", { - method: "post", - body: JSON.stringify({ - Properties: { - AuthMethod: "RPS", - SiteName: "user.auth.xboxlive.com", - RpsTicket: "d=" + oauth2.access_token - }, - RelyingParty: "http://auth.xboxlive.com", - TokenType: "JWT" - }), - headers: { "Content-Type": "application/json", Accept: "application/json" }, - }).then(res => res.json()).catch(err => { return { error: err } });; - if (xbl.error) { - xbl.errorType = "xbl"; - return xbl - } - - let xsts = await nodeFetch("https://xsts.auth.xboxlive.com/xsts/authorize", { - method: "POST", - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - Properties: { - SandboxId: "RETAIL", - UserTokens: [xbl.Token] - }, - RelyingParty: "rp://api.minecraftservices.com/", - TokenType: "JWT" - }) - }).then(res => res.json()); - if (xsts.error) { - xsts.errorType = "xsts"; - return xsts - } - - let xboxAccount = await nodeFetch("https://xsts.auth.xboxlive.com/xsts/authorize", { - method: "POST", - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - Properties: { - SandboxId: "RETAIL", - UserTokens: [xbl.Token] - }, - RelyingParty: "http://xboxlive.com", - TokenType: "JWT" - }) - }).then(res => res.json()).catch(err => { return { error: err } }); - if (xsts.error) { - xsts.errorType = "xboxAccount"; - return xsts - } - - let mcLogin = await nodeFetch("https://api.minecraftservices.com/authentication/login_with_xbox", { - method: "POST", - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ "identityToken": `XBL3.0 x=${xbl.DisplayClaims.xui[0].uhs};${xsts.Token}` }) - }).then(res => res.json()).catch(err => { return { error: err } }); - if (mcLogin.error) { - mcLogin.errorType = "mcLogin"; - return mcLogin - } - - let profile = await this.getProfile(mcLogin); - if (profile.error) { - profile.errorType = "profile"; - return profile - } - - return { - access_token: mcLogin.access_token, - client_token: crypto.randomBytes(16).toString('hex'), - uuid: profile.id, - name: profile.name, - refresh_token: oauth2.refresh_token, - user_properties: '{}', - meta: { - xuid: xboxAccount.DisplayClaims.xui[0].xid, - type: "Xbox", - access_token_expires_in: mcLogin.expires_in + Math.floor(Date.now() / 1000), - demo: profile.error ? true : false - }, - profile: { - skins: profile.skins, - capes: profile.capes - } - } - } - - async getProfile(mcLogin: any) { - let profile = await nodeFetch("https://api.minecraftservices.com/minecraft/profile", { - method: "GET", - headers: { - 'Authorization': `Bearer ${mcLogin.access_token}` - } - }).then(res => res.json()).catch(err => { return { error: err } });; - if (profile.error) return profile - - let skins = profile.skins; - let capes = profile.capes; - - for (let skin of skins) { - skin.base64 = `data:image/png;base64,${await getBass64(skin.url)}` - } - for (let cape of capes) { - cape.base64 = `data:image/png;base64,${await getBass64(cape.url)}` - } - - return { - id: profile.id, - name: profile.name, - skins: profile.skins || [], - capes: profile.capes || [] - } - } +// Basic structure for a Minecraft profile, with optional base64 fields +export interface MinecraftSkin { + id?: string; + state?: string; + url?: string; + variant?: string; + alias?: string; + base64?: string; // We add base64 representation after fetching +} + +export interface MinecraftProfile { + id: string; + name: string; + skins?: MinecraftSkin[]; + capes?: MinecraftSkin[]; +} + +// Structure for errors returned by the different steps in authentication +export interface AuthError { + error: string; + errorType?: string; + [key: string]: any; +} + +// Main structure for successful authentication +export interface AuthResponse { + access_token: string; + client_token: string; + uuid: string; + name: string; + refresh_token: string; + user_properties: string; + meta: { + type: 'Xbox'; + access_token_expires_in: number; + demo: boolean; + }; + xboxAccount: { + xuid: string; + gamertag: string; + ageGroup: string; + }; + profile: { + skins?: MinecraftSkin[]; + capes?: MinecraftSkin[]; + }; +} + +// Utility function to fetch and convert an image to base64 +async function getBase64(url: string): Promise { + const response = await fetch(url); + if (response.ok) { + const arrayBuffer = await response.arrayBuffer(); + const buffer = Buffer.from(arrayBuffer); + return buffer.toString('base64'); + } else { + return ''; + } } -async function getBass64(url: string) { - let response = await nodeFetch(url); - let buffer = await response.buffer(); - return buffer.toString('base64'); +export default class Microsoft { + public client_id: string; + public type: MicrosoftClientType; + public redirect_uri: string; + + /** + * Creates a Microsoft auth instance. + * @param client_id Your Microsoft OAuth client ID (default: '00000000402b5328' if none provided). + */ + constructor(client_id: string, redirect_uri?: string) { + this.client_id = client_id || '00000000402b5328'; + this.redirect_uri = redirect_uri || 'https://login.live.com/oauth20_desktop.srf'; + + // Determine if we're running under Electron, NW.js, or just in a terminal + if (typeof process !== 'undefined' && process.versions && process.versions.electron) { + this.type = 'electron'; + } else if (typeof process !== 'undefined' && process.versions && process.versions.nw) { + this.type = 'nwjs'; + } else { + this.type = 'terminal'; + } + } + + /** + * Opens a GUI (Electron or NW.js) or uses terminal approach to fetch an OAuth2 code, + * and then retrieves user information from Microsoft if successful. + * + * @param type The environment to open the OAuth window. Defaults to the auto-detected type. + * @param url The full OAuth2 authorization URL. If not provided, a default is used. + * @returns An object with user data on success, or false if canceled. + */ + public async getAuth(type?: MicrosoftClientType, url?: string): Promise { + const finalType = type || this.type; + const finalUrl = url || `https://login.live.com/oauth20_authorize.srf?client_id=${this.client_id}&response_type=code&redirect_uri=${this.redirect_uri}&scope=XboxLive.signin%20offline_access&cobrandid=8058f65d-ce06-4c30-9559-473c9275a65d&prompt=select_account`; + + let userCode: string | 'cancel'; + switch (finalType) { + case 'electron': + userCode = await (require('./GUI/Electron.js'))(finalUrl, this.redirect_uri); + break; + case 'nwjs': + userCode = await (require('./GUI/NW.js'))(finalUrl, this.redirect_uri); + break; + case 'terminal': + userCode = await (require('./GUI/Terminal.js'))(finalUrl, this.redirect_uri); + break; + default: + return false; + } + + // Exchange the code for an OAuth2 token, then retrieve account data + if (userCode === 'cancel') return false; + return this.exchangeCodeForToken(userCode); + } + + /** + * Exchanges an OAuth2 authorization code for an access token, then retrieves account information. + * @param code The OAuth2 authorization code returned by Microsoft. + * @returns The authenticated user data or an error object. + */ + private async exchangeCodeForToken(code: string): Promise { + try { + const response = await fetch('https://login.live.com/oauth20_token.srf', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: `client_id=${this.client_id}&code=${code}&grant_type=authorization_code&redirect_uri=${this.redirect_uri}` + }); + const oauth2 = await response.json(); + + if (oauth2.error) { + return { error: oauth2.error, errorType: 'oauth2', ...oauth2 }; + } + return this.getAccount(oauth2); + } catch (err: any) { + return { error: err.message, errorType: 'network' }; + } + } + + /** + * Refreshes the user's session if the token has expired or is about to expire. + * Otherwise, simply fetches the user's profile. + * + * @param acc A previously obtained AuthResponse object. + * @returns Updated AuthResponse (with new token if needed) or an error object. + */ + public async refresh(acc: AuthResponse | any): Promise { + const timeStamp = Math.floor(Date.now()); + + // If the token is still valid for at least 2 more hours, just re-fetch the profile + if (timeStamp < (acc?.meta?.access_token_expires_in - 7200)) { + const updatedProfile = await this.getProfile({ access_token: acc.access_token }); + if ('error' in updatedProfile) { + // If there's an error, return it directly + return updatedProfile; + } + acc.profile = { + skins: updatedProfile.skins, + capes: updatedProfile.capes + }; + return acc; + } + + // Otherwise, refresh the token + try { + const response = await fetch('https://login.live.com/oauth20_token.srf', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: `grant_type=refresh_token&client_id=${this.client_id}&refresh_token=${acc.refresh_token}` + }); + const oauth2 = await response.json(); + + if (oauth2.error) { + return { error: oauth2.error, errorType: 'oauth2', ...oauth2 }; + } + // Retrieve account data with the new tokens + return this.getAccount(oauth2); + } catch (err: any) { + return { error: err.message, errorType: 'network' }; + } + } + + /** + * Retrieves and assembles the full account details (Xbox Live, XSTS, Minecraft). + * @param oauth2 The token object returned by the Microsoft OAuth endpoint. + * @returns A fully populated AuthResponse object or an error. + */ + private async getAccount(oauth2: any): Promise { + const authenticateResponse = await fetch('https://user.auth.xboxlive.com/user/authenticate', { + method: 'POST', + headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, + body: JSON.stringify({ + Properties: { + AuthMethod: 'RPS', + SiteName: 'user.auth.xboxlive.com', + RpsTicket: `d=${oauth2.access_token}`, + }, + RelyingParty: 'http://auth.xboxlive.com', + TokenType: 'JWT', + }), + }); + const xbl = await authenticateResponse.json(); + if (xbl.error) { + return { error: xbl.error, errorType: 'xbl', ...xbl, refresh_token: oauth2.refresh_token }; + } + + const authorizeResponse = await fetch('https://xsts.auth.xboxlive.com/xsts/authorize', { + method: 'POST', + headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, + body: JSON.stringify({ + Properties: { + SandboxId: 'RETAIL', + UserTokens: [xbl.Token], + }, + RelyingParty: 'rp://api.minecraftservices.com/', + TokenType: 'JWT', + }), + }); + const xsts = await authorizeResponse.json(); + if (xsts.error) { + return { error: xsts.error, errorType: 'xsts', ...xsts, refresh_token: oauth2.refresh_token }; + } + + const mcLoginResponse = await fetch('https://api.minecraftservices.com/authentication/login_with_xbox', { + method: 'POST', + headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, + body: JSON.stringify({ + identityToken: `XBL3.0 x=${xbl.DisplayClaims.xui[0].uhs};${xsts.Token}` + }), + }); + const mcLogin = await mcLoginResponse.json(); + if (mcLogin.error) { + return { error: mcLogin.error, errorType: 'mcLogin', ...mcLogin, refresh_token: oauth2.refresh_token }; + } + if (!mcLogin.username) { + return { error: 'NO_MINECRAFT_ACCOUNT', errorType: 'mcLogin', ...mcLogin, refresh_token: oauth2.refresh_token }; + } + + const mcstoreResponse = await fetch('https://api.minecraftservices.com/entitlements/mcstore', { + method: 'GET', + headers: { 'Authorization': `Bearer ${mcLogin.access_token}` }, + }); + const mcstore = await mcstoreResponse.json(); + if (mcstore.error) { + return { error: mcstore.error, errorType: 'mcStore', ...mcstore, refresh_token: oauth2.refresh_token }; + } + + if (!mcstore.items.some((item: { name: string }) => item.name === "game_minecraft" || item.name === "product_minecraft")) { + return { error: 'NO_MINECRAFT_ENTITLEMENTS', errorType: 'mcStore', ...mcstore, refresh_token: oauth2.refresh_token }; + } + + + const profile = await this.getProfile(mcLogin); + if ('error' in profile) { + return { error: profile.error, errorType: 'mcProfile', ...profile, refresh_token: oauth2.refresh_token }; + } + + const xboxAccountResponse = await fetch('https://xsts.auth.xboxlive.com/xsts/authorize', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + Properties: { + SandboxId: 'RETAIL', + UserTokens: [xbl.Token] + }, + RelyingParty: 'http://xboxlive.com', + TokenType: 'JWT' + }) + }); + const xboxAccount = await xboxAccountResponse.json(); + if (xboxAccount.error) { + return { error: xboxAccount.error, errorType: 'xboxAccount', ...xboxAccount, refresh_token: oauth2.refresh_token }; + } + + return { + access_token: mcLogin.access_token, + client_token: crypto.randomUUID(), + uuid: profile.id, + name: profile.name, + refresh_token: oauth2.refresh_token, + user_properties: "{}", + meta: { + type: 'Xbox', + access_token_expires_in: Date.now() + (mcLogin.expires_in * 1000), + demo: false + }, + xboxAccount: { + xuid: xboxAccount.DisplayClaims.xui[0].xid, + gamertag: xboxAccount.DisplayClaims.xui[0].gtg, + ageGroup: xboxAccount.DisplayClaims.xui[0].agg + }, + profile: { + skins: [...profile.skins], + capes: [...profile.capes] + } + }; + } + + public async getProfile(mcLogin: { access_token: string }): Promise { + try { + const response = await fetch('https://api.minecraftservices.com/minecraft/profile', { + method: 'GET', + headers: { + Authorization: `Bearer ${mcLogin.access_token}` + } + }); + const profile = await response.json(); + + if (profile.error) { + return { error: profile.error }; + } + + if (Array.isArray(profile.skins)) { + for (const skin of profile.skins) { + if (skin.url) { + skin.base64 = `data:image/png;base64,${await getBase64(skin.url)}`; + } + } + } + if (Array.isArray(profile.capes)) { + for (const cape of profile.capes) { + if (cape.url) { + cape.base64 = `data:image/png;base64,${await getBase64(cape.url)}`; + } + } + } + + return { + id: profile.id, + name: profile.name, + skins: profile.skins || [], + capes: profile.capes || [] + }; + } catch (err: any) { + return { error: err.message }; + } + } } \ No newline at end of file diff --git a/src/Authenticator/Mojang.ts b/src/Authenticator/Mojang.ts index 57d84cd2..f244f807 100755 --- a/src/Authenticator/Mojang.ts +++ b/src/Authenticator/Mojang.ts @@ -1,141 +1,140 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ import crypto from 'crypto'; -import nodeFetch from 'node-fetch'; let api_url = 'https://authserver.mojang.com'; async function login(username: string, password?: string) { - let UUID = crypto.randomBytes(16).toString('hex'); - if (!password) { - return { - access_token: UUID, - client_token: UUID, - uuid: UUID, - name: username, - user_properties: '{}', - meta: { - online: false, - type: 'Mojang' - } - } - } + let UUID = crypto.randomBytes(16).toString('hex'); + if (!password) { + return { + access_token: UUID, + client_token: UUID, + uuid: UUID, + name: username, + user_properties: '{}', + meta: { + online: false, + type: 'Mojang' + } + } + } - let message = await nodeFetch(`${api_url}/authenticate`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - agent: { - name: "Minecraft", - version: 1 - }, - username, - password, - clientToken: UUID, - requestUser: true - }) - }).then(res => res.json()); + let message = await fetch(`${api_url}/authenticate`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + agent: { + name: "Minecraft", + version: 1 + }, + username, + password, + clientToken: UUID, + requestUser: true + }) + }).then(res => res.json()); - if (message.error) { - return message; - }; - let user = { - access_token: message.accessToken, - client_token: message.clientToken, - uuid: message.selectedProfile.id, - name: message.selectedProfile.name, - user_properties: '{}', - meta: { - online: true, - type: 'Mojang' - } - } - return user; + if (message.error) { + return message; + }; + let user = { + access_token: message.accessToken, + client_token: message.clientToken, + uuid: message.selectedProfile.id, + name: message.selectedProfile.name, + user_properties: '{}', + meta: { + online: true, + type: 'Mojang' + } + } + return user; } async function refresh(acc: any) { - let message = await nodeFetch(`${api_url}/refresh`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - accessToken: acc.access_token, - clientToken: acc.client_token, - requestUser: true - }) - }).then(res => res.json()); + let message = await fetch(`${api_url}/refresh`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + accessToken: acc.access_token, + clientToken: acc.client_token, + requestUser: true + }) + }).then(res => res.json()); - if (message.error) { - return message; - }; + if (message.error) { + return message; + }; - let user = { - access_token: message.accessToken, - client_token: message.clientToken, - uuid: message.selectedProfile.id, - name: message.selectedProfile.name, - user_properties: '{}', - meta: { - online: true, - type: 'Mojang' - } - } - return user; + let user = { + access_token: message.accessToken, + client_token: message.clientToken, + uuid: message.selectedProfile.id, + name: message.selectedProfile.name, + user_properties: '{}', + meta: { + online: true, + type: 'Mojang' + } + } + return user; } async function validate(acc: any) { - let message = await nodeFetch(`${api_url}/validate`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - accessToken: acc.access_token, - clientToken: acc.client_token, - }) - }); + let message = await fetch(`${api_url}/validate`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + accessToken: acc.access_token, + clientToken: acc.client_token, + }) + }); - if (message.status == 204) { - return true; - } else { - return false; - } + if (message.status == 204) { + return true; + } else { + return false; + } } async function signout(acc: any) { - let message = await nodeFetch(`${api_url}/invalidate`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - accessToken: acc.access_token, - clientToken: acc.client_token, - }) - }).then(res => res.text()); + let message = await fetch(`${api_url}/invalidate`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + accessToken: acc.access_token, + clientToken: acc.client_token, + }) + }).then(res => res.text()); - if (message == "") { - return true; - } else { - return false; - } + if (message == "") { + return true; + } else { + return false; + } } function ChangeAuthApi(url: string) { - api_url = url + api_url = url } export { - login as login, - refresh as refresh, - validate as validate, - signout as signout, - ChangeAuthApi as ChangeAuthApi + login as login, + refresh as refresh, + validate as validate, + signout as signout, + ChangeAuthApi as ChangeAuthApi } \ No newline at end of file diff --git a/src/Index.ts b/src/Index.ts index cb838cf8..60babe3f 100755 --- a/src/Index.ts +++ b/src/Index.ts @@ -1,18 +1,20 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ + import AZauth from './Authenticator/AZauth.js'; import Launch from './Launch.js'; import Microsoft from './Authenticator/Microsoft.js'; import * as Mojang from './Authenticator/Mojang.js'; import Status from './StatusServer/status.js'; - +import Downloader from './utils/Downloader.js'; export { AZauth as AZauth, Launch as Launch, Microsoft as Microsoft, Mojang as Mojang, - Status as Status + Status as Status, + Downloader as Downloader }; \ No newline at end of file diff --git a/src/Launch.ts b/src/Launch.ts index 5c4d8848..d1663f31 100755 --- a/src/Launch.ts +++ b/src/Launch.ts @@ -1,6 +1,6 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ import { EventEmitter } from 'events'; @@ -9,182 +9,396 @@ import fs from 'fs'; import { spawn } from 'child_process'; import jsonMinecraft from './Minecraft/Minecraft-Json.js'; - import librariesMinecraft from './Minecraft/Minecraft-Libraries.js'; import assetsMinecraft from './Minecraft/Minecraft-Assets.js'; import loaderMinecraft from './Minecraft/Minecraft-Loader.js'; import javaMinecraft from './Minecraft/Minecraft-Java.js'; - import bundleMinecraft from './Minecraft/Minecraft-Bundle.js'; import argumentsMinecraft from './Minecraft/Minecraft-Arguments.js'; import { isold } from './utils/Index.js'; - import Downloader from './utils/Downloader.js'; +type loader = { + /** + * Path to loader directory. Relative to absolute path to Minecraft's root directory (config option `path`). + * + * If `undefined`, defaults to `.minecraft/loader/`. + * + * Example: `'fabricfiles'`. + */ + path?: string, + /** + * Loader type. + * + * Acceptable values: `'forge'`, `'neoforge'`, `'fabric'`, `'legacyfabric'`, `'quilt'`. + */ + type?: string, + /** + * Loader build (version). + * + * Acceptable values: `'latest'`, `'recommended'`, actual version. + * + * Example: `'0.16.3'` + */ + build?: string, + /** + * Should the launcher use a loader? + */ + enable?: boolean +} + +/** + * Screen options. + */ +type screen = { + width?: number, + height?: number, + /** + * Should Minecraft be started in fullscreen mode? + */ + fullscreen?: boolean +} -export default class Launch { - options: any; - on: any; - emit: any; - - constructor() { - this.on = EventEmitter.prototype.on; - this.emit = EventEmitter.prototype.emit; - } - - async Launch(opt: any) { - this.options = { - url: opt?.url || null, - authenticator: opt?.authenticator || null, - timeout: opt?.timeout || 10000, - path: path.resolve(opt?.path || '.Minecraft').replace(/\\/g, '/'), - version: opt?.version || 'latest_release', - instance: opt?.instance || null, - detached: opt?.detached || false, - downloadFileMultiple: opt?.downloadFileMultiple || 3, - - loader: { - type: opt?.loader?.type || null, - build: opt?.loader?.build || 'latest', - enable: opt?.loader?.enable || false, - }, - - verify: opt?.verify || false, - ignored: opt?.ignored || [], - JVM_ARGS: opt?.JVM_ARGS || [], - GAME_ARGS: opt?.GAME_ARGS || [], - - javaPath: opt?.javaPath || null, - - screen: { - width: opt?.screen?.width || null, - height: opt?.screen?.height || null, - fullscreen: opt?.screen?.fullscreen || false, - }, - - memory: { - min: opt?.memory?.min || '1G', - max: opt?.memory?.max || '2G' - } - } - - if (!this.options.authenticator) return this.emit("error", { error: "Authenticator not found" }); - if (this.options.downloadFileMultiple < 1) this.options.downloadFileMultiple = 1 - if (this.options.downloadFileMultiple > 20) this.options.downloadFileMultiple = 20 - if (!this.options.loader.enable) this.options.loader = false; - this.start(); - } - - async start() { - let data: any = await this.DownloadGame(); - if (data.error) return this.emit('error', data); - let { minecraftJson, minecraftLoader, minecraftVersion, minecraftJava } = data; - - let minecraftArguments: any = await new argumentsMinecraft(this.options).GetArguments(minecraftJson, minecraftLoader); - if (minecraftArguments.error) return this.emit('error', minecraftArguments); - - let loaderArguments: any = await new loaderMinecraft(this.options).GetArguments(minecraftLoader, minecraftVersion); - if (loaderArguments.error) return this.emit('error', loaderArguments); - - let Arguments: any = [ - ...minecraftArguments.jvm, - ...loaderArguments.jvm, - ...minecraftArguments.classpath, - ...loaderArguments.game, - ...minecraftArguments.game - ] - - let java: any = this.options.javaPath ? this.options.javaPath : minecraftJava.path; - let logs = this.options.instance ? `${this.options.path}/instances/${this.options.instance}` : this.options.path; - if (!fs.existsSync(logs)) fs.mkdirSync(logs, { recursive: true }); - - let minecraftDebug = spawn(java, Arguments, { cwd: logs, detached: this.options.detached }) - - this.emit('data', `Launching with arguments ${Arguments.join(' ')}`) - minecraftDebug.stdout.on('data', (data) => this.emit('data', data.toString('utf-8'))) - minecraftDebug.stderr.on('data', (data) => this.emit('data', data.toString('utf-8'))) - minecraftDebug.on('close', (code) => this.emit('close', 'Minecraft closed')) - } - - async DownloadGame() { - let InfoVersion = await new jsonMinecraft(this.options).GetInfoVersion(); - let loaderJson: any = null; - if (InfoVersion.error) return InfoVersion - let { json, version } = InfoVersion; - - let libraries = new librariesMinecraft(this.options) - - let gameLibraries: any = await libraries.Getlibraries(json); - let gameAssetsOther: any = await libraries.GetAssetsOthers(this.options.url); - let gameAssets: any = await new assetsMinecraft(this.options).GetAssets(json); - let gameJava: any = this.options.javaPath ? { files: [] } : await new javaMinecraft(this.options).GetJsonJava(json); - - let bundle: any = [...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files] - let filesList: any = await new bundleMinecraft(this.options).checkBundle(bundle); - - if (filesList.length > 0) { - let downloader = new Downloader(); - let totsize = await new bundleMinecraft(this.options).getTotalSize(filesList); - - downloader.on("progress", (DL: any, totDL: any, element: any) => { - this.emit("progress", DL, totDL, element); - }); - - downloader.on("speed", (speed: any) => { - this.emit("speed", speed); - }); - - downloader.on("estimated", (time: any) => { - this.emit("estimated", time); - }); - - downloader.on("error", (e: any) => { - this.emit("error", e); - }); - - await downloader.downloadFileMultiple(filesList, totsize, this.options.downloadFileMultiple, this.options.timeout); - } - - if (this.options.loader) { - let loaderInstall = new loaderMinecraft(this.options) - - loaderInstall.on('extract', (extract: any) => { - this.emit('extract', extract); - }); - - loaderInstall.on('progress', (progress: any, size: any, element: any) => { - this.emit('progress', progress, size, element); - }); - - loaderInstall.on('check', (progress: any, size: any, element: any) => { - this.emit('check', progress, size, element); - }); - - loaderInstall.on('patch', (patch: any) => { - this.emit('patch', patch); - }); - - let jsonLoader = await loaderInstall.GetLoader(version, this.options.javaPath ? this.options.javaPath : gameJava.path) - .then((data: any) => data) - .catch((err: any) => err); - if (jsonLoader.error) return jsonLoader; - loaderJson = jsonLoader; - } - - if (this.options.verify) await libraries.checkFiles(bundle); - - let natives = await libraries.natives(bundle); - if (natives.length === 0) json.nativesList = false; - else json.nativesList = true; - - if (isold(json)) new assetsMinecraft(this.options).copyAssets(json); - - return { - minecraftJson: json, - minecraftLoader: loaderJson, - minecraftVersion: version, - minecraftJava: gameJava - } - } +/** + * Memory limits + */ +type memory = { + /** + * Sets the `-Xms` JVM argument. This is the initial memory usage. + */ + min?: string, + /** + * Sets the `-Xmx` JVM argument. This is the limit of memory usage. + */ + max?: string +} + +/** + * Java download options + */ +type javaOPTS = { + /** + * Absolute path to Java binaries directory. + * + * If set, expects Java to be already downloaded. If `undefined`, downloads Java and sets it automatically. + * + * Example: `'C:\Program Files\Eclipse Adoptium\jdk-21.0.2.13-hotspot\bin'` + */ + path?: string, + /** + * Java version number. + * + * If set, fetched from https://api.adoptium.net. + * If `undefined`, fetched from [Mojang](https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json). + * + * Example: `21` + */ + version?: string, + /** + * Java image type. Acceptable values: `'jdk'`, `'jre'`, `'testimage'`, `'debugimage'`, `'staticlibs'`, `'sources'`, `'sbom'`. + * + * Using `jre` is recommended since it only has what's needed. + */ + type: string +} + +/** + * Launch options. + */ +export type LaunchOPTS = { + /** + * URL to the launcher backend. Refer to [Selvania Launcher Wiki](https://github.com/luuxis/Selvania-Launcher/blob/master/docs/wiki_EN-US.md) for setup instructions. + */ + url?: string | null, + /** + * Something to Authenticate the player. + * + * Refer to `Mojang`, `Microsoft` or `AZauth` classes. + * + * Example: `await Mojang.login('Luuxis')` + */ + authenticator: any, + /** + * Connection timeout in milliseconds. + */ + timeout?: number, + /** + * Absolute path to Minecraft's root directory. + * + * Example: `'%appdata%/.minecraft'` + */ + path: string, + /** + * Minecraft version. + * + * Example: `'1.20.4'` + */ + version: string, + /** + * Path to instance directory. Relative to absolute path to Minecraft's root directory (config option `path`). + * This separates game files (e.g. versions, libraries, assets) from game data (e.g. worlds, resourcepacks, options). + * + * Example: `'PokeMoonX'` + */ + instance?: string, + /** + * Should Minecraft process be independent of launcher? + */ + detached?: boolean, + /** + * How many concurrent downloads can be in progress at once. + */ + downloadFileMultiple?: number, + /** + * Should the launcher bypass offline mode? + * + * If `true`, the launcher will not check if the user is online. + */ + bypassOffline?: boolean, + intelEnabledMac?: boolean, + /** + * Loader config + */ + loader: loader, + /** + * MCPathcer directory. (idk actually luuxis please verify this) + * + * If `instance` if set, relative to it. + * If `instance` is `undefined`, relative to `path`. + */ + mcp: any, + /** + * Should game files be verified each launch? + */ + verify: boolean, + /** + * Files to ignore from instance. (idk actually luuxis please verify this) + */ + ignored: string[], + /** + * Custom JVM arguments. Read more on [wiki.vg](https://wiki.vg/Launching_the_game#JVM_Arguments) + */ + JVM_ARGS: string[], + /** + * Custom game arguments. Read more on [wiki.vg](https://wiki.vg/Launching_the_game#Game_Arguments) + */ + GAME_ARGS: string[], + /** + * Java options. + */ + java: javaOPTS, + /** + * Screen options. + */ + screen: screen, + /** + * Memory limit options. + */ + memory: memory +}; + +export default class Launch extends EventEmitter { + options: LaunchOPTS; + + async Launch(opt: LaunchOPTS) { + const defaultOptions: LaunchOPTS = { + url: null, + authenticator: null, + timeout: 10000, + path: '.Minecraft', + version: 'latest_release', + instance: null, + detached: false, + intelEnabledMac: false, + downloadFileMultiple: 5, + bypassOffline: false, + + loader: { + path: './loader', + type: null, + build: 'latest', + enable: false, + }, + + mcp: null, + + verify: false, + ignored: [], + JVM_ARGS: [], + GAME_ARGS: [], + + java: { + path: null, + version: null, + type: 'jre', + }, + + screen: { + width: null, + height: null, + fullscreen: false, + }, + + memory: { + min: '1G', + max: '2G' + }, + ...opt, + }; + + this.options = defaultOptions; + this.options.path = path.resolve(this.options.path).replace(/\\/g, '/'); + + if (this.options.mcp) { + if (this.options.instance) this.options.mcp = `${this.options.path}/instances/${this.options.instance}/${this.options.mcp}` + else this.options.mcp = path.resolve(`${this.options.path}/${this.options.mcp}`).replace(/\\/g, '/') + } + + if (this.options.loader.type) { + this.options.loader.type = this.options.loader.type.toLowerCase() + this.options.loader.build = this.options.loader.build.toLowerCase() + } + + if (!this.options.authenticator) return this.emit("error", { error: "Authenticator not found" }); + if (this.options.downloadFileMultiple < 1) this.options.downloadFileMultiple = 1 + if (this.options.downloadFileMultiple > 30) this.options.downloadFileMultiple = 30 + if (typeof this.options.loader.path !== 'string') this.options.loader.path = `./loader/${this.options.loader.type}`; + if (this.options.java.version && typeof this.options.java.type !== 'string') this.options.java.type = 'jre'; + this.start(); + } + + + async start() { + let data: any = await this.DownloadGame(); + if (data.error) return this.emit('error', data); + let { minecraftJson, minecraftLoader, minecraftVersion, minecraftJava } = data; + + let minecraftArguments: any = await new argumentsMinecraft(this.options).GetArguments(minecraftJson, minecraftLoader); + if (minecraftArguments.error) return this.emit('error', minecraftArguments); + + let loaderArguments: any = await new loaderMinecraft(this.options).GetArguments(minecraftLoader, minecraftVersion); + if (loaderArguments.error) return this.emit('error', loaderArguments); + + let Arguments: any = [ + ...minecraftArguments.jvm, + ...minecraftArguments.classpath, + ...loaderArguments.jvm, + minecraftArguments.mainClass, + ...minecraftArguments.game, + ...loaderArguments.game + ] + + let java: any = this.options.java.path ? this.options.java.path : minecraftJava.path; + let logs = this.options.instance ? `${this.options.path}/instances/${this.options.instance}` : this.options.path; + if (!fs.existsSync(logs)) fs.mkdirSync(logs, { recursive: true }); + + let argumentsLogs: string = Arguments.join(' ') + argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.access_token, '????????') + argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.client_token, '????????') + argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.uuid, '????????') + argumentsLogs = argumentsLogs.replaceAll(this.options.authenticator?.xboxAccount?.xuid, '????????') + argumentsLogs = argumentsLogs.replaceAll(`${this.options.path}/`, '') + this.emit('data', `Launching with arguments ${argumentsLogs}`); + + let minecraftDebug = spawn(java, Arguments, { cwd: logs, detached: this.options.detached }) + minecraftDebug.stdout.on('data', (data) => this.emit('data', data.toString('utf-8'))) + minecraftDebug.stderr.on('data', (data) => this.emit('data', data.toString('utf-8'))) + minecraftDebug.on('close', (code) => this.emit('close', 'Minecraft closed')) + } + + async DownloadGame() { + let InfoVersion = await new jsonMinecraft(this.options).GetInfoVersion(); + let loaderJson: any = null; + if ('error' in InfoVersion) { + return this.emit('error', InfoVersion); + } + let { json, version } = InfoVersion; + + let libraries = new librariesMinecraft(this.options) + let bundle = new bundleMinecraft(this.options) + let java = new javaMinecraft(this.options) + + java.on('progress', (progress: any, size: any, element: any) => { + this.emit('progress', progress, size, element) + }); + + java.on('extract', (progress: any) => { + this.emit('extract', progress) + }); + + let gameLibraries: any = await libraries.Getlibraries(json); + let gameAssetsOther: any = await libraries.GetAssetsOthers(this.options.url); + let gameAssets: any = await new assetsMinecraft(this.options).getAssets(json); + let gameJava: any = this.options.java.path ? { files: [] } : await java.getJavaFiles(json); + + + if (gameJava.error) return gameJava + + let filesList: any = await bundle.checkBundle([...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]); + + if (filesList.length > 0) { + let downloader = new Downloader(); + let totsize = await bundle.getTotalSize(filesList); + + downloader.on("progress", (DL: any, totDL: any, element: any) => { + this.emit("progress", DL, totDL, element); + }); + + downloader.on("speed", (speed: any) => { + this.emit("speed", speed); + }); + + downloader.on("estimated", (time: any) => { + this.emit("estimated", time); + }); + + downloader.on("error", (e: any) => { + this.emit("error", e); + }); + + await downloader.downloadFileMultiple(filesList, totsize, this.options.downloadFileMultiple, this.options.timeout); + } + + if (this.options.loader.enable === true) { + let loaderInstall = new loaderMinecraft(this.options) + + loaderInstall.on('extract', (extract: any) => { + this.emit('extract', extract); + }); + + loaderInstall.on('progress', (progress: any, size: any, element: any) => { + this.emit('progress', progress, size, element); + }); + + loaderInstall.on('check', (progress: any, size: any, element: any) => { + this.emit('check', progress, size, element); + }); + + loaderInstall.on('patch', (patch: any) => { + this.emit('patch', patch); + }); + + let jsonLoader = await loaderInstall.GetLoader(version, this.options.java.path ? this.options.java.path : gameJava.path) + .then((data: any) => data) + .catch((err: any) => err); + if (jsonLoader.error) return jsonLoader; + loaderJson = jsonLoader; + } + + if (this.options.verify) await bundle.checkFiles([...gameLibraries, ...gameAssetsOther, ...gameAssets, ...gameJava.files]); + + let natives = await libraries.natives(gameLibraries); + if (natives.length === 0) json.nativesList = false; + else json.nativesList = true; + + if (isold(json)) new assetsMinecraft(this.options).copyAssets(json); + + return { + minecraftJson: json, + minecraftLoader: loaderJson, + minecraftVersion: version, + minecraftJava: gameJava + } + } } \ No newline at end of file diff --git a/src/Minecraft-Loader/index.ts b/src/Minecraft-Loader/index.ts new file mode 100644 index 00000000..f2ad73fd --- /dev/null +++ b/src/Minecraft-Loader/index.ts @@ -0,0 +1,335 @@ +/** + * @author Luuxis + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) + */ + +import { EventEmitter } from 'events'; +import fs from 'fs'; +import path from 'path'; +import { loader as loaderFunction } from '../utils/Index.js'; + +// Loader sub-classes (Forge, NeoForge, etc.) +// Adjust the import paths based on your project's actual file structure. +import Forge from './loader/forge/forge.js'; +import NeoForge from './loader/neoForge/neoForge.js'; +import Fabric from './loader/fabric/fabric.js'; +import LegacyFabric from './loader/legacyfabric/legacyFabric.js'; +import Quilt from './loader/quilt/quilt.js'; + +/** + * Represents the user's selected loader type (Forge, Fabric, etc.). + * Extend or refine as your application requires. + */ +export type LoaderType = 'forge' | 'neoforge' | 'fabric' | 'legacyfabric' | 'quilt'; + +/** + * Configuration for the loader (build, version, etc.). + * For instance: { type: "forge", version: "1.19.2", build: "latest" } + */ +export interface LoaderConfig { + type: LoaderType; + version: string; // Minecraft version + build: string; // e.g., "latest", "recommended", or a specific numeric build + config: { + javaPath: string; + minecraftJar: string; + minecraftJson: string; + }; + // Feel free to add additional fields if needed +} + +/** + * The overall options passed to our Loader class, + * containing path information and loader configuration. + */ +export interface LoaderOptions { + path: string; // Base directory for storing version files, etc. + loader: LoaderConfig; + [key: string]: any; // Allow additional fields as necessary +} + +/** + * A generic type to represent the JSON objects returned by + * Forge, NeoForge, Fabric, etc., after an installation. + */ +export interface LoaderResult { + id?: string; // For example, "1.19.2-Forge" or "fabric-loader-1.14" + error?: string; // If an error occurs, we store a message here + [key: string]: any; // Additional fields depending on the loader +} + +/** + * The main Loader class that orchestrates installation of different + * Minecraft mod loaders (Forge, Fabric, LegacyFabric, Quilt, etc.). + * It extends EventEmitter to provide "check", "progress", "extract", "patch", and "error" events. + */ +export default class Loader extends EventEmitter { + private readonly options: LoaderOptions; + + constructor(options: LoaderOptions) { + super(); + this.options = options; + } + + /** + * Main entry point for installing the selected loader. + * Checks the loader type from `this.options.loader.type` and delegates to the appropriate method. + * Emits: + * - "error" if the loader is not found or if an installation step fails + * - "json" upon successful completion, returning the version JSON or loader info + */ + public async install(): Promise { + // Retrieve a loader definition from your `loaderFunction` + // (Presumably a function that returns metadata URLs, etc. based on the type.) + const LoaderData = loaderFunction(this.options.loader.type); + if (!LoaderData) { + this.emit('error', { error: `Loader ${this.options.loader.type} not found` }); + return; + } + + const loaderType = this.options.loader.type; + let result: LoaderResult | undefined; + + switch (loaderType) { + case 'forge': { + result = await this.forge(LoaderData); + break; + } + case 'neoforge': { + result = await this.neoForge(LoaderData); + break; + } + case 'fabric': { + result = await this.fabric(LoaderData); + break; + } + case 'legacyfabric': { + result = await this.legacyFabric(LoaderData); + break; + } + case 'quilt': { + result = await this.quilt(LoaderData); + break; + } + default: { + this.emit('error', { error: `Loader ${loaderType} not found` }); + return; + } + } + + // If there's an error property, emit it. Otherwise, emit the final JSON. + if (result && result.error) { + this.emit('error', result); + } else if (result) { + this.emit('json', result); + } + } + + /** + * Handles Forge installation by: + * 1. Downloading the installer + * 2. Depending on installer type, extracting an install profile or creating a merged Jar + * 3. Downloading required libraries + * 4. Patching Forge if necessary + * 5. Returns the final version JSON object or an error + */ + private async forge(LoaderData: any): Promise { + const forge = new Forge(this.options); + + // Forward Forge events + forge.on('check', (progress: number, size: number, element: string) => { + this.emit('check', progress, size, element); + }); + forge.on('progress', (progress: number, size: number, element: string) => { + this.emit('progress', progress, size, element); + }); + forge.on('extract', (element: string) => { + this.emit('extract', element); + }); + forge.on('patch', (patch: any) => { + this.emit('patch', patch); + }); + + // 1. Download installer + const installer: any = await forge.downloadInstaller(LoaderData); + if (installer.error) return installer; // e.g., { error: "..." } + + const profile: any = await forge.extractProfile(installer.filePath); + if (profile.error) return profile; + + // Write the version JSON to disk + if ("version" in profile && "id" in profile.version) { + const destination = path.resolve(this.options.path, 'versions', profile.version.id); + if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true }); + fs.writeFileSync(path.resolve(destination, `${profile.version.id}.json`), JSON.stringify(profile.version, null, 4)); + fs.cpSync(path.resolve(this.options.loader.config.minecraftJar), path.resolve(destination, `${profile.version.id}.jar`)); + } + + // 3. Extract universal jar if needed + const universal: any = await forge.extractUniversalJar(profile.install, installer.filePath); + if (universal.error) return universal; + + // 4. Download libraries + const libraries: any = await forge.downloadLibraries(profile, universal); + if (libraries.error) return libraries; + + // 5. Patch Forge if necessary + const patch: any = await forge.patchForge(profile.install); + if (patch.error) return patch; + + return profile.version; + } + + /** + * Manages installation flow for NeoForge: + * 1. Download the installer + * 2. Extract the install profile + * 3. Extract the universal jar + * 4. Download libraries + * 5. Patch if needed + */ + private async neoForge(LoaderData: any): Promise { + const neoForge = new NeoForge(this.options); + + // Forward events + neoForge.on('check', (progress: number, size: number, element: string) => { + this.emit('check', progress, size, element); + }); + neoForge.on('progress', (progress: number, size: number, element: string) => { + this.emit('progress', progress, size, element); + }); + neoForge.on('extract', (element: string) => { + this.emit('extract', element); + }); + neoForge.on('patch', (patch: any) => { + this.emit('patch', patch); + }); + + const installer = await neoForge.downloadInstaller(LoaderData); + if (installer.error) return installer; + + // Extract the main profile + const profile: any = await neoForge.extractProfile(installer.filePath); + if (profile.error) return profile; + + // Write version JSON + if ("version" in profile && "id" in profile.version) { + const destination = path.resolve(this.options.path, 'versions', profile.version.id); + if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true }); + fs.writeFileSync(path.resolve(destination, `${profile.version.id}.json`), JSON.stringify(profile.version, null, 4)); + fs.cpSync(path.resolve(this.options.loader.config.minecraftJar), path.resolve(destination, `${profile.version.id}.jar`)); + } + // Extract universal jar + const universal: any = await neoForge.extractUniversalJar(profile.install, installer.filePath, installer.oldAPI); + if (universal.error) return universal; + + // Download libraries + const libraries: any = await neoForge.downloadLibraries(profile, universal); + if (libraries.error) return libraries; + + // Patch if needed + const patch: any = await neoForge.patchneoForge(profile.install, installer.oldAPI); + if (patch.error) return patch; + + if ("version" in profile) return profile.version; + } + + /** + * Installs Fabric: + * 1. Download the loader JSON + * 2. Save it as a version .json + * 3. Download required libraries + */ + private async fabric(LoaderData: any): Promise { + const fabric = new Fabric(this.options); + + // Forward events + fabric.on('check', (progress: number, size: number, element: string) => { + this.emit('check', progress, size, element); + }); + fabric.on('progress', (progress: number, size: number, element: string) => { + this.emit('progress', progress, size, element); + }); + + const json = await fabric.downloadJson(LoaderData); + if (json.error) return json; + + if ("id" in json) { + const destination = path.resolve(this.options.path, 'versions', json.id); + if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true }); + fs.writeFileSync(path.resolve(destination, `${json.id}.json`), JSON.stringify(json, null, 4)); + fs.cpSync(path.resolve(this.options.loader.config.minecraftJar), path.resolve(destination, `${json.id}.jar`)); + } + + if ("libraries" in json) { + await fabric.downloadLibraries(json); + } + + return json; + } + + /** + * Installs Legacy Fabric: + * 1. Download JSON + * 2. Save version .json + * 3. Download libraries + */ + private async legacyFabric(LoaderData: any): Promise { + const legacyFabric = new LegacyFabric(this.options); + + // Forward events + legacyFabric.on('check', (progress: number, size: number, element: string) => { + this.emit('check', progress, size, element); + }); + legacyFabric.on('progress', (progress: number, size: number, element: string) => { + this.emit('progress', progress, size, element); + }); + + const json = await legacyFabric.downloadJson(LoaderData); + if (json.error) return json; + + if ("id" in json) { + const destination = path.resolve(this.options.path, 'versions', json.id); + if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true }); + fs.writeFileSync(path.resolve(destination, `${json.id}.json`), JSON.stringify(json, null, 4)); + fs.cpSync(path.resolve(this.options.loader.config.minecraftJar), path.resolve(destination, `${json.id}.jar`)); + } + if ("libraries" in json) { + await legacyFabric.downloadLibraries(json); + } + return json; + } + + /** + * Installs Quilt: + * 1. Download the loader JSON + * 2. Write to a version file + * 3. Download required libraries + */ + private async quilt(LoaderData: any): Promise { + const quilt = new Quilt(this.options); + + // Forward events + quilt.on('check', (progress: number, size: number, element: string) => { + this.emit('check', progress, size, element); + }); + quilt.on('progress', (progress: number, size: number, element: string) => { + this.emit('progress', progress, size, element); + }); + + const json = await quilt.downloadJson(LoaderData); + if (json.error) return json; + + if ("id" in json) { + const destination = path.resolve(this.options.path, 'versions', json.id); + if (!fs.existsSync(destination)) fs.mkdirSync(destination, { recursive: true }); + fs.writeFileSync(path.resolve(destination, `${json.id}.json`), JSON.stringify(json, null, 4)); + fs.cpSync(path.resolve(this.options.loader.config.minecraftJar), path.resolve(destination, `${json.id}.jar`)); + } + if ("libraries" in json) { + await quilt.downloadLibraries(json); + } + + return json; + } +} diff --git a/src/Minecraft-Loader/loader/fabric/fabric.ts b/src/Minecraft-Loader/loader/fabric/fabric.ts new file mode 100644 index 00000000..e092d49a --- /dev/null +++ b/src/Minecraft-Loader/loader/fabric/fabric.ts @@ -0,0 +1,204 @@ +/** + * @author Luuxis + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) + */ + +import { EventEmitter } from 'events'; +import fs from 'fs'; +import path from 'path'; + +import { getPathLibraries } from '../../../utils/Index.js'; +import Downloader from '../../../utils/Downloader.js'; + +/** + * Represents the options needed by the FabricMC class. + * You can expand this if your code requires more specific fields. + */ +interface FabricOptions { + path: string; // Base path to your game or library folder + downloadFileMultiple?: number; // Max simultaneous downloads (if supported by Downloader) + loader: { + version: string; // Minecraft version + build: string; // Fabric build (e.g. "latest", "recommended", or a specific version) + }; +} + +/** + * Represents the Loader object that holds metadata URLs and JSON paths. + * For instance, it might look like: + * { + * metaData: 'https://meta.fabricmc.net/v2/versions', + * json: 'https://meta.fabricmc.net/v2/versions/loader/${version}/${build}/profile/json' + * } + */ +interface LoaderObject { + metaData: string; + json: string; // Template string with placeholders like ${version} and ${build} +} + +/** + * Represents the structure of your metadata, including + * game versions and loader builds. Adapt as needed. + */ +interface MetaData { + game: Array<{ + version: string; + stable: boolean; + }>; + loader: Array<{ + version: string; + stable: boolean; + }>; +} + +/** + * Structure of a library entry in the Fabric JSON manifest. + * Extend this interface if you have additional fields like "rules", etc. + */ +interface FabricLibrary { + name: string; + url: string; + rules?: Array; +} + +/** + * The JSON object returned by Fabric metadata endpoints. + */ +interface FabricJSON { + libraries: FabricLibrary[]; + [key: string]: any; +} + +/** + * This class handles downloading Fabric loader JSON metadata, + * resolving the correct build, and downloading the required libraries. + */ +export default class FabricMC extends EventEmitter { + private readonly options: FabricOptions; + + constructor(options: FabricOptions) { + super(); + this.options = options; + } + + /** + * Fetches the Fabric loader metadata to find the correct build for the given + * Minecraft version. If the specified build is "latest" or "recommended", + * it uses the first (most recent) entry. Otherwise, it looks up a specific build. + * + * @param Loader A LoaderObject describing metadata and json URL templates. + * @returns A JSON object representing the Fabric loader profile, or an error object. + */ + public async downloadJson(Loader: LoaderObject): Promise { + let buildInfo: { version: string; stable: boolean } | undefined; + + // Fetch the metadata + let response = await fetch(Loader.metaData); + let metaData: MetaData = await response.json(); + + // Check if the Minecraft version is supported + const version = metaData.game.find(v => v.version === this.options.loader.version); + if (!version) { + return { error: `FabricMC doesn't support Minecraft ${this.options.loader.version}` }; + } + + // Determine the loader build + const availableBuilds = metaData.loader.map(b => b.version); + if (this.options.loader.build === 'latest' || this.options.loader.build === 'recommended') { + buildInfo = metaData.loader[0]; // The first entry is presumably the latest + } else { + buildInfo = metaData.loader.find(l => l.version === this.options.loader.build); + } + + if (!buildInfo) { + return { + error: `Fabric Loader ${this.options.loader.build} not found, Available builds: ${availableBuilds.join(', ')}` + }; + } + + // Build the URL for the Fabric JSON using placeholders + const url = Loader.json + .replace('${build}', buildInfo.version) + .replace('${version}', this.options.loader.version); + + // Fetch the Fabric loader JSON + try { + const result = await fetch(url); + const fabricJson: FabricJSON = await result.json(); + return fabricJson; + } catch (err: any) { + return { error: err.message || 'An error occurred while fetching Fabric JSON' }; + } + } + + /** + * Downloads any missing libraries defined in the Fabric JSON manifest, + * skipping those that already exist locally (or that have rules preventing download). + * + * @param fabricJson The Fabric JSON object with a `libraries` array. + * @returns The same `libraries` array after downloading as needed. + */ + public async downloadLibraries(fabricJson: FabricJSON): Promise { + const { libraries } = fabricJson; + const downloader = new Downloader(); + const downloadQueue: Array<{ + url: string; + folder: string; + path: string; + name: string; + size: number; + }> = []; + + let checkedLibraries = 0; + let totalSize = 0; + + // Identify which libraries need downloading + for (const lib of libraries) { + // Skip if there are any rules that prevent downloading + if (lib.rules) { + this.emit('check', checkedLibraries++, libraries.length, 'libraries'); + continue; + } + + // Parse out the library path + const libInfo = getPathLibraries(lib.name); + const libFolderPath = path.resolve(this.options.path, 'libraries', libInfo.path); + const libFilePath = path.resolve(libFolderPath, libInfo.name); + + // If the file doesn't exist locally, we prepare a download item + if (!fs.existsSync(libFilePath)) { + const libUrl = `${lib.url}${libInfo.path}/${libInfo.name}`; + + let sizeFile = 0; + // Check if the file is accessible and retrieve its size + const res = await downloader.checkURL(libUrl); + if (res && typeof res === 'object' && 'status' in res && res.status === 200) { + sizeFile = res.size; + totalSize += res.size; + } + + downloadQueue.push({ + url: libUrl, + folder: libFolderPath, + path: libFilePath, + name: libInfo.name, + size: sizeFile + }); + } + + // Emit a "check" event for progress tracking + this.emit('check', checkedLibraries++, libraries.length, 'libraries'); + } + + // If there are files to download, do so now + if (downloadQueue.length > 0) { + downloader.on('progress', (downloaded: number, total: number) => { + this.emit('progress', downloaded, total, 'libraries'); + }); + + await downloader.downloadFileMultiple(downloadQueue, totalSize, this.options.downloadFileMultiple); + } + + return libraries; + } +} diff --git a/src/Minecraft-Loader/loader/forge/forge.ts b/src/Minecraft-Loader/loader/forge/forge.ts new file mode 100644 index 00000000..61f56b91 --- /dev/null +++ b/src/Minecraft-Loader/loader/forge/forge.ts @@ -0,0 +1,462 @@ +/** + * @author Luuxis + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) + */ + + +import fs from 'fs'; +import path from 'path'; +import { EventEmitter } from 'events'; + +import { + getPathLibraries, + getFileHash, + mirrors, + getFileFromArchive, + skipLibrary +} from '../../../utils/Index.js'; + +import Downloader from '../../../utils/Downloader.js'; +import ForgePatcher, { Profile } from '../../patcher.js'; + +/** + * Maps Node.js process.platform values to Mojang library naming conventions. + * Used for choosing the right native library. + */ +const Lib: Record = { + win32: 'windows', + darwin: 'osx', + linux: 'linux' +}; + +/** + * Represents the loader configuration. You may need to expand or adjust + * this interface if your real code has more properties. + */ +interface LoaderConfig { + version: string; // Minecraft version for Forge (e.g., "1.19.2") + build: string; // Forge build (e.g., "latest", "recommended", or a numeric version) + config: { + javaPath: string; // Path to Java for patching + minecraftJar: string; // Path to the vanilla Minecraft JAR + minecraftJson: string; // Path to the corresponding .json version file + }; +} + +/** + * Options passed to ForgeMC. Adjust as needed. + */ +interface ForgeOptions { + path: string; // Base path where files will be placed or read from + loader: { + version: string; // Minecraft version (e.g. "1.19.2") + build: string; // Build type ("latest", "recommended", or a numeric version) + config: { + javaPath: string; // Path to the Java executable for patching + minecraftJar: string; // Path to the vanilla Minecraft .jar + minecraftJson: string; // Path to the corresponding .json version file + }; + type: string; // Type of loader + }; + downloadFileMultiple?: number; // Number of concurrent downloads + [key: string]: any; // Allow extra fields as necessary +} + +/** + * Represents information about the Forge installer file after download: + * - If successful, contains filePath, metaData, ext, and an id (e.g. "forge-") + * - If an error occurs, returns an object with `error` describing the issue. + */ +type DownloadInstallerResult = + | { + filePath: string; + metaData: string; + ext: string; + id: string; + } + | { + error: string; + }; + +/** + * Describes the structure of an install_profile.json (Forge Installer) after extraction. + */ +interface ForgeProfile extends Profile { + install?: { + libraries?: any[]; + [key: string]: any; + }; + version?: { + libraries?: any[]; + [key: string]: any; + }; + filePath?: string; + path?: string; + [key: string]: any; +} + +/** + * The main class for handling Forge installations, including: + * - Downloading the appropriate Forge installer + * - Extracting relevant files from the installer + * - Patching Forge when necessary + * - Creating a merged jar for older Forge versions + */ +export default class ForgeMC extends EventEmitter { + private readonly options: ForgeOptions; + + constructor(options: ForgeOptions) { + super(); + this.options = options; + } + + /** + * Downloads the Forge installer (or client/universal) for the specified version/build. + * Verifies the downloaded file's MD5 hash. Returns file details or an error. + * + * @param Loader An object containing URLs for metadata and Forge files. + */ + public async downloadInstaller(Loader: any): Promise { + // Fetch metadata for the given Forge version + let metaDataList: any = await fetch(Loader.metaData); + + if (!metaDataList.ok) { + metaDataList = fs.readFileSync(path.resolve(__dirname, '../../../../assets/forge', 'forge-metadata.json'), 'utf-8'); + metaDataList = JSON.parse(metaDataList); + } else { + metaDataList = await metaDataList.json(); + } + + metaDataList = metaDataList[this.options.loader.version]; + + if (!metaDataList) { + return { error: `Forge ${this.options.loader.version} not supported` }; + } + + const allBuilds = metaDataList; + let build: string | undefined; + + // Handle "latest" or "recommended" builds by checking promotions + if (this.options.loader.build === 'latest') { + let promotions = await fetch(Loader.promotions).then(res => res.json()); + const promoKey = `${this.options.loader.version}-latest`; + const promoBuild = promotions.promos[promoKey]; + build = metaDataList.find(b => b.includes(promoBuild)); + } else if (this.options.loader.build === 'recommended') { + let promotions = await fetch(Loader.promotions).then(res => res.json()); + let promoKey = `${this.options.loader.version}-recommended`; + let promoBuild = promotions.promos[promoKey] || promotions.promos[`${this.options.loader.version}-latest`]; + build = metaDataList.find(b => b.includes(promoBuild)); + } else { + // Else, look for a specific numeric build if provided + build = this.options.loader.build; + } + + const chosenBuild = metaDataList.find(b => b === build); + if (!chosenBuild) { + return { + error: `Build ${build} not found, Available builds: ${allBuilds.join(', ')}` + }; + } + + // Fetch info about the chosen build from the meta URL + const meta = await fetch(Loader.meta.replace(/\${build}/g, chosenBuild)).then(res => res.json()); + + // Determine which classifier to use (installer, client, or universal) + const hasInstaller = meta.classifiers.installer; + const hasClient = meta.classifiers.client; + const hasUniversal = meta.classifiers.universal; + + let forgeURL: string = ''; + let ext: string = ''; + let hashFileOrigin: string = ''; + + if (hasInstaller) { + forgeURL = Loader.install.replace(/\${version}/g, chosenBuild); + ext = Object.keys(meta.classifiers.installer)[0]; + hashFileOrigin = meta.classifiers.installer[ext]; + } else if (hasClient) { + forgeURL = Loader.client.replace(/\${version}/g, chosenBuild); + ext = Object.keys(meta.classifiers.client)[0]; + hashFileOrigin = meta.classifiers.client[ext]; + } else if (hasUniversal) { + forgeURL = Loader.universal.replace(/\${version}/g, chosenBuild); + ext = Object.keys(meta.classifiers.universal)[0]; + hashFileOrigin = meta.classifiers.universal[ext]; + } else { + return { error: 'Invalid forge installer' }; + } + + const forgeFolder = path.resolve(this.options.path, 'libraries/net/minecraftforge/installer'); + const fileName = `${forgeURL}.${ext}`.split('/').pop()!; + const installerPath = path.resolve(forgeFolder, fileName); + + // Download if not already present + if (!fs.existsSync(installerPath)) { + if (!fs.existsSync(forgeFolder)) { + fs.mkdirSync(forgeFolder, { recursive: true }); + } + const dl = new Downloader(); + dl.on('progress', (downloaded: number, size: number) => { + this.emit('progress', downloaded, size, fileName); + }); + + await dl.downloadFile(`${forgeURL}.${ext}`, forgeFolder, fileName); + } + + // Verify the MD5 hash + const hashFileDownload = await getFileHash(installerPath, 'md5'); + if (hashFileDownload !== hashFileOrigin) { + fs.rmSync(installerPath); + return { error: 'Invalid hash' }; + } + + return { + filePath: installerPath, + metaData: chosenBuild, + ext, + id: `forge-${build}` + }; + } + + /** + * Extracts the main Forge profile from the installer's archive (install_profile.json), + * plus an additional JSON if specified in that profile. Returns an object containing + * both "install" and "version" data for further processing. + * + * @param pathInstaller Path to the downloaded Forge installer file. + */ + public async extractProfile(pathInstaller: string): Promise<{ error?: any; install?: any; version?: any }> { + const fileContent = await getFileFromArchive(pathInstaller, 'install_profile.json'); + if (!fileContent) { + return { error: { message: 'Invalid forge installer' } }; + } + + const forgeJsonOrigin = JSON.parse(fileContent.toString()); + if (!forgeJsonOrigin) { + return { error: { message: 'Invalid forge installer' } }; + } + + const result: any = {}; + + // Distinguish between older and newer Forge installers + if (forgeJsonOrigin.install) { + result.install = forgeJsonOrigin.install; + result.version = forgeJsonOrigin.versionInfo; + } else { + result.install = forgeJsonOrigin; + const extraFile = await getFileFromArchive(pathInstaller, path.basename(result.install.json)); + if (!extraFile) { + return { error: { message: 'Invalid additional JSON in forge installer' } }; + } + result.version = JSON.parse(extraFile.toString()); + } + + return result; + } + + /** + * Extracts the "universal" Forge jar (or other relevant data) from the installer, + * placing it in your local "libraries" folder. Also extracts client data if required. + * + * @param profile The Forge profile object containing file paths to extract. + * @param pathInstaller The path to the Forge installer file. + * @returns A boolean (skipForgeFilter) that indicates whether to filter out certain Forge libs + */ + public async extractUniversalJar(profile: ForgeProfile, pathInstaller: string): Promise { + let skipForgeFilter = true; + + // If there's a direct file path, extract just that file + if (profile.filePath) { + const fileInfo = getPathLibraries(profile.path); + this.emit('extract', `Extracting ${fileInfo.name}...`); + + const destFolder = path.resolve(this.options.path, 'libraries', fileInfo.path); + if (!fs.existsSync(destFolder)) { + fs.mkdirSync(destFolder, { recursive: true }); + } + + const archiveContent = await getFileFromArchive(pathInstaller, profile.filePath); + if (archiveContent) { + fs.writeFileSync(path.join(destFolder, fileInfo.name), archiveContent, { mode: 0o777 }); + } + } + // Otherwise, if there's a path referencing "maven/" + else if (profile.path) { + const fileInfo = getPathLibraries(profile.path); + const filesInArchive: string[] = await getFileFromArchive(pathInstaller, null, `maven/${fileInfo.path}`); + for (const file of filesInArchive) { + const fileName = path.basename(file); + this.emit('extract', `Extracting ${fileName}...`); + const fileContent = await getFileFromArchive(pathInstaller, file); + if (!fileContent) { + continue; + } + + const destFolder = path.resolve(this.options.path, 'libraries', fileInfo.path); + if (!fs.existsSync(destFolder)) { + fs.mkdirSync(destFolder, { recursive: true }); + } + + fs.writeFileSync(path.join(destFolder, fileName), fileContent, { mode: 0o777 }); + } + } else { + // If we do not find filePath or path in profile, skip the Forge filter + skipForgeFilter = false; + } + + // If there are processors, we likely have a "client.lzma" to store + if (profile.processors?.length) { + const universalPath = profile.libraries?.find((v: any) => (v.name || '').startsWith('net.minecraftforge:forge')); + const clientData = await getFileFromArchive(pathInstaller, 'data/client.lzma'); + if (clientData) { + const fileInfo = getPathLibraries(profile.path || universalPath.name, '-clientdata', '.lzma'); + const destFolder = path.resolve(this.options.path, 'libraries', fileInfo.path); + if (!fs.existsSync(destFolder)) { + fs.mkdirSync(destFolder, { recursive: true }); + } + fs.writeFileSync(path.join(destFolder, fileInfo.name), clientData, { mode: 0o777 }); + this.emit('extract', `Extracting ${fileInfo.name}...`); + } + } + + return skipForgeFilter; + } + + /** + * Downloads all the libraries needed by the Forge profile, skipping duplicates + * and any library that is already present. Also applies optional skip logic + * for certain Forge libraries if skipForgeFilter is true. + * + * @param profile The parsed Forge profile. + * @param skipForgeFilter Whether to filter out "net.minecraftforge:forge" or "minecraftforge" + * @returns An array of the final libraries (including newly downloaded ones). + */ + public async downloadLibraries(profile: ForgeProfile, skipForgeFilter: boolean): Promise { + let libraries = profile.version?.libraries || []; + const dl = new Downloader(); + let checkCount = 0; + const downloadList: Array<{ + url: string; + folder: string; + path: string; + name: string; + size: number; + }> = []; + let totalSize = 0; + + // Combine with any "install.libraries" + if (profile.install?.libraries) { + libraries = libraries.concat(profile.install.libraries); + } + + // Remove duplicates by name + libraries = libraries.filter( + (library: any, index: number, self: any[]) => index === self.findIndex(t => t.name === library.name) + ); + + // Certain Forge libs may be skipped if skipForgeFilter is true + const skipForge = ['net.minecraftforge:forge:', 'net.minecraftforge:minecraftforge:']; + + for (const lib of libraries) { + // If skipForgeFilter is true, skip the core Forge libs + if (skipForgeFilter && skipForge.some(forgePrefix => lib.name.includes(forgePrefix))) { + // If the artifact URL is empty, we skip it + if (!lib.downloads?.artifact?.url) { + this.emit('check', checkCount++, libraries.length, 'libraries'); + continue; + } + } + + // Some libraries might need skipping altogether (e.g., OS-specific constraints) + if (skipLibrary(lib)) { + this.emit('check', checkCount++, libraries.length, 'libraries'); + continue; + } + + // Check if the library includes "natives" for the current OS + let nativesSuffix: string | undefined; + if (lib.natives) { + nativesSuffix = lib.natives[Lib[process.platform]]; + } + + const libInfo = getPathLibraries(lib.name, nativesSuffix ? `-${nativesSuffix}` : ''); + const libFolder = path.resolve(this.options.path, 'libraries', libInfo.path); + const libFilePath = path.resolve(libFolder, libInfo.name); + + // If not present locally, schedule it for download + if (!fs.existsSync(libFilePath)) { + let url: string | null = null; + let fileSize = 0; + + // First, try checking a mirror + const baseURL = nativesSuffix ? `${libInfo.path}/` : `${libInfo.path}/${libInfo.name}`; + const mirrorResp: any = await dl.checkMirror(baseURL, mirrors); + + if (mirrorResp?.status === 200) { + fileSize = mirrorResp.size; + totalSize += fileSize; + url = mirrorResp.url; + } else if (lib.downloads?.artifact) { + url = lib.downloads.artifact.url; + fileSize = lib.downloads.artifact.size; + totalSize += fileSize; + } + + if (!url) { + this.emit('check', checkCount++, libraries.length, 'libraries'); + this.emit('error', `Library ${libInfo.name} not found`); + continue; + } + + downloadList.push({ + url, + folder: libFolder, + path: libFilePath, + name: libInfo.name, + size: fileSize + }); + } + + this.emit('check', checkCount++, libraries.length, 'libraries'); + } + + // Perform the downloads if any are needed + if (downloadList.length > 0) { + dl.on('progress', (DL: number, totDL: number) => { + this.emit('progress', DL, totDL, 'libraries'); + }); + await dl.downloadFileMultiple(downloadList, totalSize, this.options.downloadFileMultiple); + } + + return libraries; + } + + /** + * Applies any necessary patches to Forge using the `forgePatcher` class. + * If the patcher determines it's already patched, it skips. + * + * @param profile The Forge profile containing processor information + * @returns True if successful or if no patching was required + */ + public async patchForge(profile: ForgeProfile): Promise { + if (profile?.processors?.length) { + const patcher = new ForgePatcher(this.options); + + // Forward patcher events + patcher.on('patch', (data: string) => this.emit('patch', data)); + patcher.on('error', (data: string) => this.emit('error', data)); + + // If the patch is not valid yet, run the patch process + if (!patcher.check(profile)) { + const config = { + java: this.options.loader.config.javaPath, + minecraft: this.options.loader.config.minecraftJar, + minecraftJson: this.options.loader.config.minecraftJson + }; + await patcher.patcher(profile, config); + } + } + return true; + } +} diff --git a/src/Minecraft-Loader/loader/legacyfabric/legacyFabric.ts b/src/Minecraft-Loader/loader/legacyfabric/legacyFabric.ts new file mode 100644 index 00000000..dbca8cf1 --- /dev/null +++ b/src/Minecraft-Loader/loader/legacyfabric/legacyFabric.ts @@ -0,0 +1,197 @@ +/** + * @author Luuxis + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) + */ + +import fs from 'fs'; +import path from 'path'; +import { EventEmitter } from 'events'; + +import { getPathLibraries } from '../../../utils/Index.js'; +import Downloader from '../../../utils/Downloader.js'; + +/** + * Represents the "loader" part of the user's options, containing version info for Minecraft and Fabric. + */ +interface FabricLoaderConfig { + version: string; // e.g., "1.19.2" + build: string; // e.g., "latest", "recommended" or a specific build like "0.14.8" +} + +/** + * Overall options passed to FabricMC. + * Adjust or extend according to your project needs. + */ +interface FabricOptions { + path: string; // Base path where libraries and files should be placed + loader: FabricLoaderConfig; // Configuration for the Fabric loader + downloadFileMultiple?: number; // Number of concurrent downloads (if your Downloader supports it) + [key: string]: any; // Allow extra fields as needed +} + +/** + * This object typically references the metadata and JSON URLs for the Fabric API, + * for example: + * { + * metaData: 'https://meta.fabricmc.net/v2/versions', + * json: 'https://meta.fabricmc.net/v2/versions/loader/${version}/${build}/profile/json' + * } + */ +interface LoaderObject { + metaData: string; // URL to fetch general Fabric metadata + json: string; // Template URL to fetch the final Fabric loader JSON +} + +/** + * Represents one library entry in the Fabric loader JSON. + */ +interface FabricLibrary { + name: string; + url: string; + rules?: Array; +} + +/** + * Represents the final JSON object fetched for the Fabric loader, + * containing an array of libraries. + */ +interface FabricJSON { + libraries: FabricLibrary[]; + [key: string]: any; // Extend or adapt based on actual structure +} + +/** + * A class that handles downloading the Fabric loader JSON metadata + * and the libraries needed to launch Fabric. + */ +export default class FabricMC extends EventEmitter { + private readonly options: FabricOptions; + + constructor(options: FabricOptions = { path: '', loader: { version: '', build: '' } }) { + super(); + this.options = options; + } + + /** + * Fetches metadata from the Fabric API to identify the correct build for the given version. + * If the build is "latest" or "recommended", it picks the first entry from the loader array. + * Otherwise, it tries to match the specific build requested by the user. + * + * @param Loader A LoaderObject with metaData and json URLs for Fabric. + * @returns A FabricJSON object on success, or an error object. + */ + public async downloadJson(Loader: LoaderObject): Promise { + let selectedBuild: { version: string } | undefined; + + // Fetch overall metadata + const metaResponse = await fetch(Loader.metaData); + const metaData = await metaResponse.json(); + + // Check if the requested Minecraft version is supported + const versionExists = metaData.game.find((ver: any) => ver.version === this.options.loader.version); + if (!versionExists) { + return { error: `FabricMC doesn't support Minecraft ${this.options.loader.version}` }; + } + + // Extract all possible loader builds + const availableBuilds = metaData.loader.map((b: any) => b.version); + + // If user wants the "latest" or "recommended" build, use the first in the array + if (this.options.loader.build === 'latest' || this.options.loader.build === 'recommended') { + selectedBuild = metaData.loader[0]; + } else { + // Otherwise, search for a matching build + selectedBuild = metaData.loader.find((loaderBuild: any) => loaderBuild.version === this.options.loader.build); + } + + if (!selectedBuild) { + return { + error: `Fabric Loader ${this.options.loader.build} not found, Available builds: ${availableBuilds.join(', ')}` + }; + } + + // Construct the final URL for fetching the Fabric JSON + const url = Loader.json + .replace('${build}', selectedBuild.version) + .replace('${version}', this.options.loader.version); + + // Fetch and parse the JSON + try { + const response = await fetch(url); + const fabricJson: FabricJSON = await response.json(); + return fabricJson; + } catch (err: any) { + return { error: err.message || 'Failed to fetch or parse Fabric loader JSON' }; + } + } + + /** + * Iterates over the libraries in the Fabric JSON, checks if they exist locally, + * and if not, downloads them. Skips libraries that have "rules" (usually platform-specific). + * + * @param json The Fabric loader JSON object with a "libraries" array. + * @returns The same libraries array after downloads, or an error object if something fails. + */ + public async downloadLibraries(json: FabricJSON): Promise { + const { libraries } = json; + const downloader = new Downloader(); + let pendingDownloads: Array<{ + url: string; + folder: string; + path: string; + name: string; + size: number; + }> = []; + + let checkedCount = 0; + let totalSize = 0; + + // Evaluate each library for possible download + for (const lib of libraries) { + // Skip if library has rules that might disqualify it for this platform + if (lib.rules) { + this.emit('check', checkedCount++, libraries.length, 'libraries'); + continue; + } + + // Build the local file path + const libInfo = getPathLibraries(lib.name); + const libFolder = path.resolve(this.options.path, 'libraries', libInfo.path); + const libFilePath = path.resolve(libFolder, libInfo.name); + + // If it doesn't exist, prepare to download + if (!fs.existsSync(libFilePath)) { + const libUrl = `${lib.url}${libInfo.path}/${libInfo.name}`; + + let fileSize = 0; + // Check if the file is available and get its size + const checkRes = await downloader.checkURL(libUrl); + if (checkRes && typeof checkRes === 'object' && 'status' in checkRes && checkRes.status === 200) { + fileSize = checkRes.size; + totalSize += fileSize; + } + + pendingDownloads.push({ + url: libUrl, + folder: libFolder, + path: libFilePath, + name: libInfo.name, + size: fileSize + }); + } + + this.emit('check', checkedCount++, libraries.length, 'libraries'); + } + + // Download all missing libraries in bulk + if (pendingDownloads.length > 0) { + downloader.on('progress', (downloaded: number, total: number) => { + this.emit('progress', downloaded, total, 'libraries'); + }); + + await downloader.downloadFileMultiple(pendingDownloads, totalSize, this.options.downloadFileMultiple); + } + + return libraries; + } +} diff --git a/src/Minecraft-Loader/loader/neoForge/neoForge.ts b/src/Minecraft-Loader/loader/neoForge/neoForge.ts new file mode 100644 index 00000000..6baf73f0 --- /dev/null +++ b/src/Minecraft-Loader/loader/neoForge/neoForge.ts @@ -0,0 +1,405 @@ +/** + * @author Luuxis + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) + */ + +import fs from 'fs'; +import path from 'path'; +import { EventEmitter } from 'events'; + +import { getPathLibraries, mirrors, getFileFromArchive } from '../../../utils/Index.js'; +import Downloader from '../../../utils/Downloader.js'; +import NeoForgePatcher, { Profile } from '../../patcher.js'; + +/** + * Options passed to NeoForgeMC, including paths, loader configs, etc. + * Adjust according to your application's specifics. + */ +interface NeoForgeOptions { + path: string; // Base path where files will be placed or read from + loader: { + version: string; // Minecraft version (e.g. "1.19.2") + build: string; // Build type ("latest", "recommended", or a numeric version) + config: { + javaPath: string; // Path to the Java executable for patching + minecraftJar: string; // Path to the vanilla Minecraft .jar + minecraftJson: string; // Path to the corresponding .json version file + }; + type: string; // Type of loader + }; + downloadFileMultiple?: number; // Number of concurrent downloads + [key: string]: any; // Allow extra fields as necessary +} + +/** + * A structure to describe the loader object with metadata, legacy vs. new API, etc. + * For example: + * { + * legacyMetaData: 'https://.../legacyMetadata.json', + * metaData: 'https://.../metadata.json', + * legacyInstall: 'https://.../NeoForge-${version}.jar', + * install: 'https://.../NeoForge-${version}.jar' + * } + */ +interface LoaderObject { + legacyMetaData: string; + metaData: string; + legacyInstall: string; + install: string; +} + +/** + * Represents the result of downloading the NeoForge installer, or an error. + */ +interface DownloadInstallerResult { + filePath?: string; // Path to the downloaded jar + oldAPI?: boolean; // Indicates whether the legacy API was used + error?: string; // Error message if something went wrong +} + +/** + * Represents the structure of a NeoForge install_profile.json + * after extraction from the installer jar. + */ +interface NeoForgeProfile extends Profile { + install?: { + libraries?: any[]; + [key: string]: any; + }; + version?: { + libraries?: any[]; + [key: string]: any; + }; + filePath?: string; + path?: string; + [key: string]: any; +} + +/** + * This class handles downloading and installing NeoForge (formerly Forge) for Minecraft, + * including picking the correct build, extracting libraries, and running patchers if needed. + */ +export default class NeoForgeMC extends EventEmitter { + private readonly options: NeoForgeOptions; + + constructor(options: NeoForgeOptions) { + super(); + this.options = options; + } + + /** + * Downloads the NeoForge installer jar for the specified version and build, + * either using a legacy API or the newer metaData approach. If "latest" or "recommended" + * is specified, it picks the newest build from the filtered list. + * + * @param Loader An object containing URLs and patterns for legacy and new metadata/installers. + * @returns An object with filePath and oldAPI fields, or an error. + */ + public async downloadInstaller(Loader: LoaderObject): Promise { + let build: string | undefined; + let neoForgeURL: string; + let oldAPI = true; + + // Fetch versions from the legacy API + const legacyMetaData = await fetch(Loader.legacyMetaData).then(res => res.json()); + const metaData = await fetch(Loader.metaData).then(res => res.json()); + + // Filter versions for the specified Minecraft version + let versions: string[] = legacyMetaData.versions.filter((v: string) => + v.includes(`${this.options.loader.version}-`) + ); + + // If none found, fallback to the new API approach + if (!versions.length) { + const splitted = this.options.loader.version.split('.'); + const shortVersion = `${splitted[1]}.${splitted[2] || 0}.`; + versions = metaData.versions.filter((v: string) => v.startsWith(shortVersion)); + oldAPI = false; + } + + // If still no versions found, return an error + if (!versions.length) { + return { error: `NeoForge doesn't support Minecraft ${this.options.loader.version}` }; + } + + // Determine which build to use + if (this.options.loader.build === 'latest' || this.options.loader.build === 'recommended') { + build = versions[versions.length - 1]; // The most recent build + } else { + build = versions.find(v => v === this.options.loader.build); + } + + if (!build) { + return { + error: `NeoForge Loader ${this.options.loader.build} not found, Available builds: ${versions.join(', ')}` + }; + } + + // Build the installer URL, depending on whether we use the legacy or new API + if (oldAPI) { + neoForgeURL = Loader.legacyInstall.replaceAll(/\${version}/g, build); + } else { + neoForgeURL = Loader.install.replaceAll(/\${version}/g, build); + } + + // Create a local folder for "neoForge" if it doesn't exist + const neoForgeFolder = path.resolve(this.options.path, 'libraries/net/neoforged/installer'); + const installerFilePath = path.resolve(neoForgeFolder, `neoForge-${build}-installer.jar`); + + if (!fs.existsSync(installerFilePath)) { + if (!fs.existsSync(neoForgeFolder)) { + fs.mkdirSync(neoForgeFolder, { recursive: true }); + } + const downloader = new Downloader(); + downloader.on('progress', (downloaded: number, size: number) => { + this.emit('progress', downloaded, size, `neoForge-${build}-installer.jar`); + }); + + await downloader.downloadFile(neoForgeURL, neoForgeFolder, `neoForge-${build}-installer.jar`); + } + + return { filePath: installerFilePath, oldAPI }; + } + + /** + * Extracts the main JSON profile (install_profile.json) from the NeoForge installer. + * If the JSON references an additional file, it also extracts and parses that, returning + * a unified object with `install` and `version` keys. + * + * @param pathInstaller Full path to the downloaded NeoForge installer jar. + * @returns A NeoForgeProfile object, or an error if invalid. + */ + public async extractProfile(pathInstaller: string): Promise { + const fileContent = await getFileFromArchive(pathInstaller, 'install_profile.json'); + if (!fileContent) { + return { error: { message: 'Invalid neoForge installer' } }; + } + + const neoForgeJsonOrigin = JSON.parse(fileContent.toString()); + if (!neoForgeJsonOrigin) { + return { error: { message: 'Invalid neoForge installer' } }; + } + + const result: NeoForgeProfile = { data: {} }; + if (neoForgeJsonOrigin.install) { + result.install = neoForgeJsonOrigin.install; + result.version = neoForgeJsonOrigin.versionInfo; + } else { + result.install = neoForgeJsonOrigin; + const extraFile = await getFileFromArchive(pathInstaller, path.basename(result.install.json)); + if (extraFile) { + result.version = JSON.parse(extraFile.toString()); + } else { + return { error: { message: 'Unable to read additional JSON from neoForge installer' } }; + } + } + + return result; + } + + /** + * Extracts the universal jar or associated files for NeoForge into the local "libraries" directory. + * Also handles client.lzma if processors are present. Returns a boolean indicating whether we skip + * certain neoforge libraries in subsequent steps. + * + * @param profile The extracted NeoForge profile with file path references + * @param pathInstaller Path to the NeoForge installer + * @param oldAPI Whether we are dealing with the old or new NeoForge API (affects library naming) + * @returns A boolean indicating if we should filter out certain libraries afterwards + */ + public async extractUniversalJar(profile: NeoForgeProfile, pathInstaller: string, oldAPI: boolean): Promise { + let skipNeoForgeFilter = true; + + if (profile.filePath) { + const fileInfo = getPathLibraries(profile.path); + this.emit('extract', `Extracting ${fileInfo.name}...`); + + const destFolder = path.resolve(this.options.path, 'libraries', fileInfo.path); + if (!fs.existsSync(destFolder)) { + fs.mkdirSync(destFolder, { recursive: true }); + } + + const archiveContent = await getFileFromArchive(pathInstaller, profile.filePath); + if (archiveContent) { + fs.writeFileSync(path.join(destFolder, fileInfo.name), archiveContent, { mode: 0o777 }); + } + } else if (profile.path) { + const fileInfo = getPathLibraries(profile.path); + const filesInArchive = await getFileFromArchive(pathInstaller, null, `maven/${fileInfo.path}`); + if (filesInArchive && Array.isArray(filesInArchive)) { + for (const file of filesInArchive) { + const fileName = path.basename(file); + this.emit('extract', `Extracting ${fileName}...`); + + const content = await getFileFromArchive(pathInstaller, file); + if (!content) continue; + + const destFolder = path.resolve(this.options.path, 'libraries', fileInfo.path); + if (!fs.existsSync(destFolder)) { + fs.mkdirSync(destFolder, { recursive: true }); + } + fs.writeFileSync(path.join(destFolder, fileName), content, { mode: 0o777 }); + } + } + } else { + // If no direct reference, do not skip the library filtering + skipNeoForgeFilter = false; + } + + // If processors exist, we likely need to store client.lzma + if (profile.processors?.length) { + const universalPath = profile.libraries?.find(lib => + (lib.name || '').startsWith(oldAPI ? 'net.neoforged:forge' : 'net.neoforged:neoforge') + ); + + const clientData = await getFileFromArchive(pathInstaller, 'data/client.lzma'); + if (clientData) { + const fileInfo = getPathLibraries(profile.path || universalPath.name, '-clientdata', '.lzma'); + const destFolder = path.resolve(this.options.path, 'libraries', fileInfo.path); + + if (!fs.existsSync(destFolder)) { + fs.mkdirSync(destFolder, { recursive: true }); + } + fs.writeFileSync(path.join(destFolder, fileInfo.name), clientData, { mode: 0o777 }); + this.emit('extract', `Extracting ${fileInfo.name}...`); + } + } + + return skipNeoForgeFilter; + } + + /** + * Downloads all libraries referenced in the NeoForge profile. If skipNeoForgeFilter is true, + * certain core libraries are excluded. Checks for duplicates and local existence before downloading. + * + * @param profile The NeoForge profile containing version/install libraries + * @param skipNeoForgeFilter Whether we skip specific "net.minecraftforge:neoforged" libs + * @returns An array of library objects after download, or an error object if something fails + */ + public async downloadLibraries(profile: NeoForgeProfile, skipNeoForgeFilter: boolean): Promise { + let libraries = profile.version?.libraries || []; + const dl = new Downloader(); + let checkCount = 0; + const pendingFiles: Array<{ + url: string; + folder: string; + path: string; + name: string; + size: number; + }> = []; + let totalSize = 0; + + // Combine install.libraries with version.libraries + if (profile.install?.libraries) { + libraries = libraries.concat(profile.install.libraries); + } + + // Remove duplicates by 'name' + libraries = libraries.filter( + (lib, index, self) => index === self.findIndex(item => item.name === lib.name) + ); + + // If skipping certain neoforge libs + const skipNeoForge = ['net.minecraftforge:neoforged:', 'net.minecraftforge:minecraftforge:']; + + // Evaluate each library + for (const lib of libraries) { + if (skipNeoForgeFilter && skipNeoForge.some(str => lib.name.includes(str))) { + // If there's no valid artifact URL, skip it + if (!lib.downloads?.artifact?.url) { + this.emit('check', checkCount++, libraries.length, 'libraries'); + continue; + } + } + + // If the library has rules, skip automatically + if (lib.rules) { + this.emit('check', checkCount++, libraries.length, 'libraries'); + continue; + } + + // Construct the local path to the library + const libInfo = getPathLibraries(lib.name); + const libFolder = path.resolve(this.options.path, 'libraries', libInfo.path); + const libFilePath = path.resolve(libFolder, libInfo.name); + + // If it doesn't exist locally, schedule for download + if (!fs.existsSync(libFilePath)) { + let finalURL: string | null = null; + let fileSize = 0; + + // Attempt to resolve via mirror first + const baseURL = `${libInfo.path}/${libInfo.name}`; + const mirrorCheck = await dl.checkMirror(baseURL, mirrors); + if (mirrorCheck && typeof mirrorCheck === 'object' && 'status' in mirrorCheck && mirrorCheck.status === 200) { + finalURL = mirrorCheck.url; + fileSize = mirrorCheck.size; + totalSize += fileSize; + } else if (lib.downloads?.artifact) { + finalURL = lib.downloads.artifact.url; + fileSize = lib.downloads.artifact.size; + totalSize += fileSize; + } + + if (!finalURL) { + return { error: `Impossible to download ${libInfo.name}` }; + } + + pendingFiles.push({ + url: finalURL, + folder: libFolder, + path: libFilePath, + name: libInfo.name, + size: fileSize + }); + } + + this.emit('check', checkCount++, libraries.length, 'libraries'); + } + + // Download all pending files + if (pendingFiles.length > 0) { + dl.on('progress', (downloaded: number, totDL: number) => { + this.emit('progress', downloaded, totDL, 'libraries'); + }); + + await dl.downloadFileMultiple(pendingFiles, totalSize, this.options.downloadFileMultiple); + } + + return libraries; + } + + /** + * Runs the NeoForge patch process, if any processors exist. Checks if patching is needed, + * then uses the `NeoForgePatcher` class. If the patch is already applied, it skips. + * + * @param profile The NeoForge profile, which may include processors. + * @param oldAPI Whether we are dealing with the old or new API (passed to the patcher). + * @returns True on success or if no patch was needed. + */ + public async patchneoForge(profile: NeoForgeProfile, oldAPI: boolean): Promise { + if (profile?.processors?.length) { + const patcher = new NeoForgePatcher(this.options); + + // Relay events + patcher.on('patch', (data: string) => { + this.emit('patch', data); + }); + patcher.on('error', (error: string) => { + this.emit('error', error); + }); + + // If not already patched, run the patcher + if (!patcher.check(profile)) { + const config = { + java: this.options.loader.config.javaPath, + minecraft: this.options.loader.config.minecraftJar, + minecraftJson: this.options.loader.config.minecraftJson + }; + + await patcher.patcher(profile, config, oldAPI); + } + } + return true; + } +} diff --git a/src/Minecraft-Loader/loader/quilt/quilt.ts b/src/Minecraft-Loader/loader/quilt/quilt.ts new file mode 100644 index 00000000..1ca069cb --- /dev/null +++ b/src/Minecraft-Loader/loader/quilt/quilt.ts @@ -0,0 +1,207 @@ +/** + * @author Luuxis + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) + */ + +import fs from 'fs'; +import path from 'path'; +import { EventEmitter } from 'events'; + +import { getPathLibraries } from '../../../utils/Index.js'; +import Downloader from '../../../utils/Downloader.js'; + +/** + * Represents the Quilt loader configuration within the user's options. + */ +interface QuiltLoaderConfig { + version: string; // e.g., "1.19.2" + build: string; // e.g., "latest", "recommended", or a specific build ID +} + +/** + * The main options object passed to the Quilt class. + * You can extend this as needed by your application. + */ +interface QuiltOptions { + path: string; // Base path for storing downloaded libraries, etc. + loader: QuiltLoaderConfig; // Loader configuration for Quilt + downloadFileMultiple?: number; // Number of concurrent downloads + [key: string]: any; // Allow additional fields as needed +} + +/** + * Describes the data needed for fetching Quilt metadata and loader JSON. + * For example: + * { + * metaData: "https://meta.quiltmc.org/v3/versions", + * json: "https://meta.quiltmc.org/v3/versions/loader/${version}/${build}/profile/json" + * } + */ +interface LoaderObject { + metaData: string; + json: string; // URL pattern with placeholders like ${version} and ${build} +} + +/** + * A structure for one library entry in the Quilt loader JSON. + */ +interface QuiltLibrary { + name: string; + url: string; + rules?: Array; +} + +/** + * The JSON object typically returned by the Quilt API, + * containing an array of libraries and possibly other fields. + */ +interface QuiltJSON { + libraries: QuiltLibrary[]; + [key: string]: any; +} + +/** + * This class handles fetching the Quilt loader metadata, + * identifying the appropriate build for a given Minecraft version, + * and downloading required libraries. + */ +export default class Quilt extends EventEmitter { + private readonly options: QuiltOptions; + private versionMinecraft: string | undefined; + + constructor(options: QuiltOptions = { path: '', loader: { version: '', build: '' } }) { + super(); + this.options = options; + } + + /** + * Fetches the Quilt loader metadata to identify the correct build for the specified + * Minecraft version. If "latest" or "recommended" is requested, picks the most + * recent or stable build accordingly. + * + * @param Loader An object describing where to fetch Quilt metadata and JSON. + * @returns A QuiltJSON object on success, or an error object if something fails. + */ + public async downloadJson(Loader: LoaderObject): Promise { + let selectedBuild: any; + + // Fetch the metadata + const metaResponse = await fetch(Loader.metaData); + const metaData = await metaResponse.json(); + + // Check if the requested Minecraft version is supported + const mcVersionExists = metaData.game.find((ver: any) => ver.version === this.options.loader.version); + if (!mcVersionExists) { + return { error: `QuiltMC doesn't support Minecraft ${this.options.loader.version}` }; + } + + // Gather all available builds for this version + const availableBuilds = metaData.loader.map((b: any) => b.version); + + // Determine which build to use + if (this.options.loader.build === 'latest') { + selectedBuild = metaData.loader[0]; + } else if (this.options.loader.build === 'recommended') { + // Attempt to find a build that isn't labeled "beta" + selectedBuild = metaData.loader.find((b: any) => !b.version.includes('beta')); + } else { + // Otherwise, match a specific build + selectedBuild = metaData.loader.find( + (loaderItem: any) => loaderItem.version === this.options.loader.build + ); + } + + if (!selectedBuild) { + return { + error: `QuiltMC Loader ${this.options.loader.build} not found, Available builds: ${availableBuilds.join(', ')}` + }; + } + + // Build the URL for the Quilt loader profile JSON + const url = Loader.json + .replace('${build}', selectedBuild.version) + .replace('${version}', this.options.loader.version); + + // Fetch the JSON profile + try { + const response = await fetch(url); + const quiltJson: QuiltJSON = await response.json(); + return quiltJson; + } catch (err: any) { + return { error: err.message || 'Failed to fetch or parse Quilt loader JSON' }; + } + } + + /** + * Parses the Quilt JSON to determine which libraries need downloading, skipping + * any that already exist or that are disqualified by "rules". Downloads them + * in bulk using the Downloader utility. + * + * @param quiltJson A QuiltJSON object containing a list of libraries. + * @returns The final list of libraries, or an error if something fails. + */ + public async downloadLibraries(quiltJson: QuiltJSON): Promise { + const { libraries } = quiltJson; + const downloader = new Downloader(); + + let filesToDownload: Array<{ + url: string; + folder: string; + path: string; + name: string; + size: number; + }> = []; + + let checkedLibraries = 0; + let totalSize = 0; + + for (const lib of libraries) { + // If rules exist, skip it (likely platform-specific logic) + if (lib.rules) { + this.emit('check', checkedLibraries++, libraries.length, 'libraries'); + continue; + } + + // Construct the local path where this library should reside + const libInfo = getPathLibraries(lib.name); + const libFolder = path.resolve(this.options.path, 'libraries', libInfo.path); + const libFilePath = path.resolve(libFolder, libInfo.name); + + // If the library doesn't exist locally, prepare to download + if (!fs.existsSync(libFilePath)) { + const libUrl = `${lib.url}${libInfo.path}/${libInfo.name}`; + + let fileSize = 0; + const checkResult = await downloader.checkURL(libUrl); + + if (checkResult && checkResult.status === 200) { + fileSize = checkResult.size; + totalSize += fileSize; + } + + filesToDownload.push({ + url: libUrl, + folder: libFolder, + path: libFilePath, + name: libInfo.name, + size: fileSize + }); + } + + + // Emit a "check" event for each library + this.emit('check', checkedLibraries++, libraries.length, 'libraries'); + } + + // If there are libraries to download, proceed with the bulk download + if (filesToDownload.length > 0) { + downloader.on('progress', (downloaded: number, total: number) => { + this.emit('progress', downloaded, total, 'libraries'); + }); + + await downloader.downloadFileMultiple(filesToDownload, totalSize, this.options.downloadFileMultiple); + } + + return libraries; + } +} diff --git a/src/Minecraft-Loader/patcher.ts b/src/Minecraft-Loader/patcher.ts new file mode 100644 index 00000000..249d6cbf --- /dev/null +++ b/src/Minecraft-Loader/patcher.ts @@ -0,0 +1,174 @@ +/** + * @author Luuxis + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) + */ + +import { spawn } from 'child_process'; +import fs from 'fs'; +import path from 'path'; +import { EventEmitter } from 'events'; +import { getPathLibraries, getFileFromArchive } from '../utils/Index.js'; + +interface ForgePatcherOptions { + path: string; + loader: { + type: string; + }; +} + +interface Config { + java: string; + minecraft: string; + minecraftJson: string; +} + +interface ProfileData { + client: string; + [key: string]: any; +} + +interface Processor { + jar: string; + args: string[]; + classpath: string[]; + sides?: string[]; +} + +export interface Profile { + data: Record; + processors?: any[]; + libraries?: Array<{ name?: string }>; // The universal jar/libraries reference + path?: string; +} + +export default class ForgePatcher extends EventEmitter { + private readonly options: ForgePatcherOptions; + + constructor(options: ForgePatcherOptions) { + super(); + this.options = options; + } + + public async patcher(profile: Profile, config: Config, neoForgeOld: boolean = true): Promise { + const { processors } = profile; + + for (const [_, processor] of Object.entries(processors)) { + if (processor.sides && !processor.sides.includes('client')) continue; + + const jarInfo = getPathLibraries(processor.jar); + const jarPath = path.resolve(this.options.path, 'libraries', jarInfo.path, jarInfo.name); + + const args = processor.args + .map(arg => this.setArgument(arg, profile, config, neoForgeOld)) + .map(arg => this.computePath(arg)); + + const classPaths = processor.classpath.map(cp => { + const cpInfo = getPathLibraries(cp); + return `"${path.join(this.options.path, 'libraries', cpInfo.path, cpInfo.name)}"`; + }); + + const mainClass = await this.readJarManifest(jarPath); + if (!mainClass) { + this.emit('error', `Impossible de déterminer la classe principale dans le JAR: ${jarPath}`); + continue; + } + + await new Promise((resolve) => { + const spawned = spawn( + `"${path.resolve(config.java)}"`, + [ + '-classpath', + [`"${jarPath}"`, ...classPaths].join(path.delimiter), + mainClass, + ...args + ], + { shell: true } + ); + + spawned.stdout.on('data', data => { + this.emit('patch', data.toString('utf-8')); + }); + + spawned.stderr.on('data', data => { + this.emit('patch', data.toString('utf-8')); + }); + + spawned.on('close', code => { + if (code !== 0) { + this.emit('error', `Le patcher Forge s'est terminé avec le code ${code}`); + } + resolve(); + }); + }); + } + } + + public check(profile: Profile): boolean { + const { processors } = profile; + let files: string[] = []; + + for (const processor of Object.values(processors)) { + if (processor.sides && !processor.sides.includes('client')) continue; + + processor.args.forEach(arg => { + const finalArg = arg.replace('{', '').replace('}', ''); + if (profile.data[finalArg]) { + if (finalArg === 'BINPATCH') return; + files.push(profile.data[finalArg].client); + } + }); + } + + files = Array.from(new Set(files)); + + for (const file of files) { + const lib = getPathLibraries(file.replace('[', '').replace(']', '')); + const filePath = path.resolve(this.options.path, 'libraries', lib.path, lib.name); + if (!fs.existsSync(filePath)) return false; + } + return true; + } + + private setArgument(arg: string, profile: Profile, config: Config, neoForgeOld: boolean): string { + const finalArg = arg.replace('{', '').replace('}', ''); + + const universalLib = profile.libraries.find(lib => { + if (this.options.loader.type === 'forge') return lib.name.startsWith('net.minecraftforge:forge'); + else return lib.name.startsWith(neoForgeOld ? 'net.neoforged:forge' : 'net.neoforged:neoforge'); + }); + + if (profile.data[finalArg]) { + if (finalArg === 'BINPATCH') { + const jarInfo = getPathLibraries(profile.path || (universalLib?.name ?? '')); + return `"${path.join(this.options.path, 'libraries', jarInfo.path, jarInfo.name).replace('.jar', '-clientdata.lzma')}"`; + } + return profile.data[finalArg].client; + } + + return arg + .replace('{SIDE}', 'client') + .replace('{ROOT}', `"${path.dirname(path.resolve(this.options.path, 'forge'))}"`) + .replace('{MINECRAFT_JAR}', `"${config.minecraft}"`) + .replace('{MINECRAFT_VERSION}', `"${config.minecraftJson}"`) + .replace('{INSTALLER}', `"${path.join(this.options.path, 'libraries')}"`) + .replace('{LIBRARY_DIR}', `"${path.join(this.options.path, 'libraries')}"`); + } + + private computePath(arg: string): string { + if (arg.startsWith('[')) { + const libInfo = getPathLibraries(arg.replace('[', '').replace(']', '')); + return `"${path.join(this.options.path, 'libraries', libInfo.path, libInfo.name)}"`; + } + return arg; + } + + private async readJarManifest(jarPath: string): Promise { + const manifestContent = await getFileFromArchive(jarPath, 'META-INF/MANIFEST.MF'); + if (!manifestContent) return null; + + const content = manifestContent.toString(); + const mainClassLine = content.split('Main-Class: ')[1]; + if (!mainClassLine) return null; + return mainClassLine.split('\r\n')[0]; + } +} diff --git a/src/Minecraft/Minecraft-Arguments.ts b/src/Minecraft/Minecraft-Arguments.ts index 36a41e67..1fdce0c2 100755 --- a/src/Minecraft/Minecraft-Arguments.ts +++ b/src/Minecraft/Minecraft-Arguments.ts @@ -1,140 +1,376 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ +import fs from 'fs'; +import os from 'os'; +import semver from 'semver'; import { getPathLibraries, isold } from '../utils/Index.js'; -let MojangLib = { win32: "windows", darwin: "osx", linux: "linux" }; +/** + * Maps the Node.js process.platform values to Mojang's library folders. + */ +const MOJANG_LIBRARY_MAP: Record = { + win32: 'windows', + darwin: 'osx', + linux: 'linux' +}; + +/** + * Represents options for memory usage, screen size, extra args, etc. + * Adapt or expand as needed for your use case. + */ +export interface LaunchOptions { + path: string; // Base path to Minecraft data folder + instance?: string; // Instance name (if using multi-instance approach) + authenticator: any; // Auth object containing tokens, user info, etc. + version?: string; // Minecraft version + bypassOffline?: boolean; // Bypass offline mode for multiplayer + memory: { + min?: string; // Minimum memory (e.g. "512M", "1G") + max?: string; // Maximum memory (e.g. "4G", "8G") + }; + screen?: { + width?: number; + height?: number; + }; + GAME_ARGS: Array; // Additional arguments passed to the game + JVM_ARGS: Array; // Additional arguments passed to the JVM + mcp?: string; // MCP config path (for modded usage) +} + +/** + * Represents the data structure of a Minecraft version JSON file (simplified). + * Adapt this interface if your JSON includes more properties. + */ +export interface VersionJSON { + id: string; + type: string; + assetIndex: { + id: string; + }; + assets?: string; // Name of the assets index + mainClass?: string; + minecraftArguments?: string; // Legacy format for older MC versions + arguments?: { + game?: Array; + jvm?: Array; + }; + libraries?: Array; // List of library dependencies + nativesList?: Array; +} + +export interface Library { + name: string; + loader?: string; + natives?: Record; + rules?: { os?: { name?: string } }[]; +} + +/** + * Represents a loader JSON structure (e.g. Forge or Fabric). + * Again, adapt as your loader's actual structure requires. + */ +export interface LoaderJSON { + id?: string; + mainClass?: string; + libraries?: Array; + minecraftArguments?: string; + isOldForge?: boolean; + jarPath?: string; +} + +/** + * Data structure returned by the class, detailing arguments + * for launching Minecraft (game args, JVM args, classpath, etc.). + */ +export interface LaunchArguments { + game: Array; + jvm: Array; + classpath: Array; + mainClass?: string; +} +/** + * Builds and organizes JVM and game arguments required to launch Minecraft, + * including optional loader (e.g., Forge) arguments. + */ export default class MinecraftArguments { - options: any; - authenticator: any; - constructor(options: any) { - this.options = options; - this.authenticator = options.authenticator; - } - - async GetArguments(json: any, loaderJson: any) { - let game = await this.GetGameArguments(json, loaderJson); - let jvm = await this.GetJVMArguments(json); - let classpath = await this.GetClassPath(json, loaderJson); - - return { - game: game, - jvm: jvm, - classpath: classpath - } - } - - async GetGameArguments(json: any, loaderJson: any) { - let game = json.minecraftArguments ? json.minecraftArguments.split(' ') : json.arguments.game; - if (loaderJson) { - let gameLoader = loaderJson.minecraftArguments ? loaderJson.minecraftArguments.split(' ') : []; - game = game.concat(gameLoader); - game = game.filter((item: any, index: any, self: any) => index === self.findIndex((res: any) => res == item)) - } - - let table = { - '${auth_access_token}': this.authenticator.access_token, - '${auth_session}': this.authenticator.access_token, - '${auth_player_name}': this.authenticator.name, - '${auth_uuid}': this.authenticator.uuid, - '${auth_xuid}': this.authenticator.meta.xuid || this.authenticator.access_token, - '${user_properties}': this.authenticator.user_properties, - '${user_type}': this.authenticator.meta.type, - '${version_name}': json.id, - '${assets_index_name}': json.assetIndex.id, - '${game_directory}': this.options.instance ? `${this.options.path}/instances/${this.options.instance}` : this.options.path, - '${assets_root}': isold(json) ? `${this.options.path}/resources` : `${this.options.path}/assets`, - '${game_assets}': isold(json) ? `${this.options.path}/resources` : `${this.options.path}/assets`, - '${version_type}': json.type, - '${clientid}': this.authenticator.clientId || (this.authenticator.client_token || this.authenticator.access_token) - } - - for (let i in game) { - if (typeof game[i] == 'object') game.splice(i, 2) - if (Object.keys(table).includes(game[i])) game[i] = table[game[i]] - } - - if (this.options.screen) { - if (this.options.screen.width !== null && this.options.screen.height !== null) { - game.push('--width') - game.push(this.options.screen.width) - game.push('--height') - game.push(this.options.screen.height) - } - } - - game.push(...this.options.GAME_ARGS) - - return game.filter((item: any) => typeof item !== 'object') - } - - async GetJVMArguments(json: any) { - let opts = { - win32: '-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump', - darwin: '-XstartOnFirstThread', - linux: '-Xss1M' - } - let jvm = [ - `-Xms${this.options.memory.min}`, - `-Xmx${this.options.memory.max}`, - '-XX:+UnlockExperimentalVMOptions', - '-XX:G1NewSizePercent=20', - '-XX:G1ReservePercent=20', - '-XX:MaxGCPauseMillis=50', - '-XX:G1HeapRegionSize=32M', - '-Dfml.ignoreInvalidMinecraftCertificates=true' - ] - - if (process.platform == 'darwin') { - if (!json.minecraftArguments) { - jvm.push(opts[process.platform]) - } - } - - if (json.nativesList) { - jvm.push(`-Djava.library.path=${this.options.path}/versions/${json.id}/natives`) - } - - jvm.push(...this.options.JVM_ARGS) - - return jvm; - } - - async GetClassPath(json: any, loaderJson: any) { - let classPath: any = [] - let libraries: any = json.libraries; - - if (loaderJson?.libraries) libraries = loaderJson.libraries.concat(libraries); - libraries = libraries.filter((library: any, index: any, self: any) => index === self.findIndex((res: any) => res.name === library.name)) - - for (let lib of libraries) { - if (lib.natives) { - let native = lib.natives[MojangLib[process.platform]]; - if (!native) native = lib.natives[process.platform]; - if (!native) continue; - } else { - if (lib.rules && lib.rules[0].os) { - if (lib.rules[0].os.name !== MojangLib[process.platform]) continue; - } - } - - - let path = getPathLibraries(lib.name) - if (lib.loader) { - classPath.push(`${lib.loader}/libraries/${path.path}/${path.name}`) - } else { - classPath.push(`${this.options.path}/libraries/${path.path}/${path.name}`) - } - } - classPath.push(`${this.options.path}/versions/${json.id}/${json.id}.jar`) - - return [ - `-cp`, - classPath.join(process.platform === 'win32' ? ';' : ':'), - loaderJson ? loaderJson.mainClass : json.mainClass - ] - } + private options: LaunchOptions; + private authenticator: any; + + constructor(options: LaunchOptions) { + this.options = options; + this.authenticator = options.authenticator; + } + + /** + * Gathers all arguments (game, JVM, classpath) and returns them for launching. + * @param versionJson The Minecraft version JSON. + * @param loaderJson An optional loader JSON (Forge, Fabric, etc.). + */ + public async GetArguments(versionJson: VersionJSON, loaderJson?: LoaderJSON): Promise { + const gameArguments = await this.GetGameArguments(versionJson, loaderJson); + const jvmArguments = await this.GetJVMArguments(versionJson); + const classpathData = await this.GetClassPath(versionJson, loaderJson); + + return { + game: gameArguments, + jvm: jvmArguments, + classpath: classpathData.classpath, + mainClass: classpathData.mainClass + }; + } + + /** + * Builds the Minecraft game arguments, injecting authentication tokens, + * user info, and any loader arguments if present. + * @param versionJson The Minecraft version JSON. + * @param loaderJson The loader JSON (e.g., Forge) if applicable. + */ + public async GetGameArguments(versionJson: VersionJSON, loaderJson?: LoaderJSON): Promise> { + // For older MC versions, arguments may be in `minecraftArguments` instead of `arguments.game` + let gameArgs = versionJson.minecraftArguments + ? versionJson.minecraftArguments.split(' ') + : versionJson.arguments?.game ?? []; + + // Merge loader's Minecraft arguments if provided + if (loaderJson) { + const loaderGameArgs = loaderJson.minecraftArguments ? loaderJson.minecraftArguments.split(' ') : []; + gameArgs = gameArgs.concat(loaderGameArgs); + // Remove duplicate arguments + gameArgs = gameArgs.filter( + (item, index, self) => index === self.findIndex(arg => arg === item) + ); + } + + // Determine user type (e.g. 'msa' or 'Xbox') depending on version and authenticator + let userType = 'msa'; + if (versionJson.id.startsWith('1.16')) { + userType = 'Xbox'; + } else { + userType = this.authenticator.meta.type === 'Xbox' ? 'msa' : this.authenticator.meta.type; + } + + // Map of placeholders to actual values + const placeholderMap: Record = { + '${auth_access_token}': this.authenticator.access_token, + '${auth_session}': this.authenticator.access_token, + '${auth_player_name}': this.authenticator.name, + '${auth_uuid}': this.authenticator.uuid, + '${auth_xuid}': this.authenticator?.xboxAccount?.xuid || this.authenticator.access_token, + '${user_properties}': this.authenticator.user_properties, + '${user_type}': userType, + '${version_name}': loaderJson ? loaderJson.id || versionJson.id : versionJson.id, + '${assets_index_name}': versionJson.assetIndex.id, + '${game_directory}': this.options.instance + ? `${this.options.path}/instances/${this.options.instance}` + : this.options.path, + '${assets_root}': isold(versionJson) + ? `${this.options.path}/resources` + : `${this.options.path}/assets`, + '${game_assets}': isold(versionJson) + ? `${this.options.path}/resources` + : `${this.options.path}/assets`, + '${version_type}': versionJson.type, + '${clientid}': this.authenticator.clientId + || this.authenticator.client_token + || this.authenticator.access_token + }; + + // Replace placeholders in the game arguments + for (let i = 0; i < gameArgs.length; i++) { + if (typeof gameArgs[i] === 'object') { + // If it's an unexpected object, remove it + gameArgs.splice(i, 1); + i--; + continue; + } + if (placeholderMap[gameArgs[i]]) { + gameArgs[i] = placeholderMap[gameArgs[i]]; + } + } + + // If screen options are provided, add them + if (this.options.screen) { + const { width, height } = this.options.screen; + if (width && height) { + gameArgs.push('--width', String(width), '--height', String(height)); + } + } + + // Add any extra game arguments from user config + gameArgs.push(...this.options.GAME_ARGS); + + // Filter out any remaining unexpected objects + return gameArgs.filter(item => typeof item === 'string'); + } + + /** + * Builds the JVM arguments needed by Minecraft. This includes memory settings, + * OS-specific options, and any additional arguments supplied by the user. + * @param versionJson The Minecraft version JSON. + */ + public async GetJVMArguments(versionJson: VersionJSON): Promise> { + // Some OS-specific defaults + const osSpecificOpts: Record = { + win32: '-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump', + darwin: '-XstartOnFirstThread', + linux: '-Xss1M' + }; + + // Core JVM arguments + const jvmArgs: Array = [ + `-Xms${this.options.memory.min}`, + `-Xmx${this.options.memory.max}`, + '-XX:+UnlockExperimentalVMOptions', + '-XX:G1NewSizePercent=20', + '-XX:G1ReservePercent=20', + '-XX:MaxGCPauseMillis=50', + '-XX:G1HeapRegionSize=32M', + '-Dfml.ignoreInvalidMinecraftCertificates=true', + `-Djna.tmpdir=${this.options.path}/versions/${versionJson.id}/natives`, + `-Dorg.lwjgl.system.SharedLibraryExtractPath=${this.options.path}/versions/${versionJson.id}/natives`, + `-Dio.netty.native.workdir=${this.options.path}/versions/${versionJson.id}/natives` + ]; + + // For newer MC versions that use "arguments.game" instead of "minecraftArguments", + // we add OS-specific arguments (e.g., Mac uses -XstartOnFirstThread). + if (!versionJson.minecraftArguments) { + const opt = osSpecificOpts[process.platform]; + if (opt) { + jvmArgs.push(opt); + } + } + + // bypass offline mode multiplayer + if (this.options?.bypassOffline) { + jvmArgs.push('-Dminecraft.api.auth.host=https://nope.invalid/'); + jvmArgs.push('-Dminecraft.api.account.host=https://nope.invalid/'); + jvmArgs.push('-Dminecraft.api.session.host=https://nope.invalid/'); + jvmArgs.push('-Dminecraft.api.services.host=https://nope.invalid/'); + } + + // If natives are specified, add the native library path + if (versionJson.nativesList) { + jvmArgs.push(`-Djava.library.path=${this.options.path}/versions/${versionJson.id}/natives`); + } + + // Special handling for macOS (setting dock icon) + if (os.platform() === 'darwin') { + const assetsPath = `${this.options.path}/assets/indexes/${versionJson.assets}.json`; + const assetsContent = fs.readFileSync(assetsPath, 'utf-8'); + const assetsJson = JSON.parse(assetsContent); + + // Retrieve the hash of the minecraft.icns file + const iconHash = assetsJson.objects['icons/minecraft.icns']?.hash; + if (iconHash) { + jvmArgs.push('-Xdock:name=Minecraft'); + jvmArgs.push(`-Xdock:icon=${this.options.path}/assets/objects/${iconHash.substring(0, 2)}/${iconHash}`); + } + } + + // Append any user-supplied JVM arguments + jvmArgs.push(...this.options.JVM_ARGS); + + return jvmArgs; + } + + /** + * Constructs the classpath (including libraries) that Minecraft requires + * to launch, and identifies the main class. Optionally merges loader libraries. + * @param versionJson The Minecraft version JSON. + * @param loaderJson The loader JSON (e.g., Forge, Fabric) if applicable. + */ + public async GetClassPath(versionJson: VersionJSON, loaderJson?: LoaderJSON): Promise<{ + classpath: Array; + mainClass: string | undefined; + }> { + let combinedLibraries = versionJson.libraries ?? []; + + // If a loader JSON is provided, merge its libraries with the base MC version + if (loaderJson?.libraries) { + combinedLibraries = loaderJson.libraries.concat(combinedLibraries); + } + + const map = new Map(); + + for (const dep of combinedLibraries) { + const parts = getPathLibraries(dep.name); + const version = semver.valid(semver.coerce(parts.version)); + if (!version) continue; + + const pathParts = parts.path.split('/'); + const basePath = pathParts.slice(0, -1).join('/'); + + const key = `${basePath}/${parts.name.replace(`-${parts.version}`, '')}`; + const current = map.get(key); + + const isSupportedVersion = semver.satisfies(semver.valid(semver.coerce(this.options.version)), '1.14.4 - 1.18.2'); + const isWindows = process.platform === 'win32'; + + if (!current || semver.gt(version, current.version) && (isSupportedVersion && isWindows)) { + map.set(key, { ...dep, version }); + } + } + + const latest: Record = Object.fromEntries( + Array.from(map.entries()).map(([key, value]) => [key, value as Library]) + ); + + // Prepare to accumulate all library paths + const librariesList: string[] = []; + for (const lib of Object.values(latest)) { + // Skip certain logging libraries if flagged (e.g., in Forge's "loader" property) + if (lib.loader && lib.name.startsWith('org.apache.logging.log4j:log4j-slf4j2-impl')) continue; + + + // Check if the library has native bindings + if (lib.natives) { + const nativeName = lib.natives[MOJANG_LIBRARY_MAP[process.platform]] || lib.natives[process.platform]; + if (!nativeName) continue; + } else if (lib.rules && lib.rules[0].os) { + // Some libraries only apply to specific OS platforms + if (lib.rules[0].os.name !== MOJANG_LIBRARY_MAP[process.platform]) continue; + } + + // Build the path for this library + const libPath = getPathLibraries(lib.name); + if (lib.loader) { + // If the loader uses a specific library path + librariesList.push(`${lib.loader}/libraries/${libPath.path}/${libPath.name}`); + } else { + librariesList.push(`${this.options.path}/libraries/${libPath.path}/${libPath.name}`); + } + } + + // Add the main Minecraft JAR (or special jar if using old Forge or MCP) + if (loaderJson?.isOldForge && loaderJson.jarPath) { + librariesList.push(loaderJson.jarPath); + } else if (this.options.mcp) { + librariesList.push(this.options.mcp); + } else { + librariesList.push(`${this.options.path}/versions/${versionJson.id}/${versionJson.id}.jar`); + } + + // Filter out duplicates in the final library paths + const uniquePaths: string[] = []; + for (const libPath of librariesList) { + // We only check if we've already used the exact file name + const fileName = libPath.split('/').pop(); + if (fileName && !uniquePaths.includes(fileName)) { + uniquePaths.push(libPath); + } + } + + // The final classpath argument is OS-dependent (':' on Unix, ';' on Windows) + const cpSeparator = process.platform === 'win32' ? ';' : ':'; + const cpArgument = uniquePaths.length > 0 ? uniquePaths.join(cpSeparator) : ''; + + return { + classpath: ['-cp', cpArgument], + mainClass: loaderJson ? loaderJson.mainClass : versionJson.mainClass + }; + } } diff --git a/src/Minecraft/Minecraft-Assets.ts b/src/Minecraft/Minecraft-Assets.ts index 7d47d8ed..382a8327 100755 --- a/src/Minecraft/Minecraft-Assets.ts +++ b/src/Minecraft/Minecraft-Assets.ts @@ -1,65 +1,152 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ - -import nodeFetch from 'node-fetch'; import fs from 'fs'; +/** + * Represents the general structure of the options passed to MinecraftAssets. + * You can expand or modify these fields as necessary for your specific use case. + */ +export interface MinecraftAssetsOptions { + path: string; // Base path to the Minecraft data folder + instance?: string; // Instance name (if using multi-instance setup) +} + +/** + * Represents a simplified version of the Minecraft version JSON structure. + */ +export interface VersionJSON { + assetIndex?: { + id: string; // e.g. "1.19" + url: string; // URL where the asset index JSON can be fetched + }; + assets?: string; // e.g. "1.19" +} + +/** + * Represents a single asset object in the final array returned by getAssets(). + */ +export interface AssetItem { + type: 'CFILE' | 'Assets'; + path: string; + content?: string; // Used if type = "CFILE" + sha1?: string; // Used if type = "Assets" + size?: number; // Used if type = "Assets" + url?: string; // Used if type = "Assets" +} + +/** + * Class responsible for handling Minecraft asset index fetching + * and optionally copying legacy assets to the correct directory. + */ export default class MinecraftAssets { - assetIndex: any; - options: any; - constructor(options: any) { - this.options = options; - } - - async GetAssets(json: any) { - this.assetIndex = json.assetIndex; - - let assets = []; - let data = await nodeFetch(this.assetIndex.url).then(res => res.json()); - - assets.push({ - type: "CFILE", - path: `assets/indexes/${this.assetIndex.id}.json`, - content: JSON.stringify(data) - }); - - data = Object.values(data.objects); - - for (let asset of data) { - assets.push({ - sha1: asset.hash, - size: asset.size, - type: "Assets", - path: `assets/objects/${asset.hash.substring(0, 2)}/${asset.hash}`, - url: `https://resources.download.minecraft.net/${asset.hash.substring(0, 2)}/${asset.hash}` - }); - } - return assets - } - - copyAssets(json: any) { - let legacyDirectory = `${this.options.path}/resources`; - let pathAssets = `${this.options.path}/assets/indexes/${json.assets}.json`; - if (!fs.existsSync(pathAssets)) return; - let assets = JSON.parse(fs.readFileSync(pathAssets, 'utf-8')); - assets = Object.entries(assets.objects); - - for (let [file, hash] of assets) { - let Hash = hash.hash; - let Subhash = Hash.substring(0, 2) - let SubAsset = `${this.options.path}/assets/objects/${Subhash}` - let legacyAsset = file.split('/') - legacyAsset.pop() - - if (!fs.existsSync(`${legacyDirectory}/${legacyAsset.join('/')}`)) { - fs.mkdirSync(`${legacyDirectory}/${legacyAsset.join('/')}`, { recursive: true }) - } - - if (!fs.existsSync(`${legacyDirectory}/${file}`)) { - fs.copyFileSync(`${SubAsset}/${Hash}`, `${legacyDirectory}/${file}`) - } - } - } -} \ No newline at end of file + private assetIndex: { id: string; url: string } | undefined; + private readonly options: MinecraftAssetsOptions; + + constructor(options: MinecraftAssetsOptions) { + this.options = options; + } + + /** + * Fetches the asset index from the provided JSON object, then constructs + * and returns an array of asset download objects. These can be processed + * by a downloader to ensure all assets are present locally. + * + * @param versionJson A JSON object containing an "assetIndex" field. + * @returns An array of AssetItem objects with download info. + */ + public async getAssets(versionJson: VersionJSON): Promise { + this.assetIndex = versionJson.assetIndex; + if (!this.assetIndex) { + // If there's no assetIndex, there's nothing to download. + return []; + } + + // Fetch the asset index JSON from the remote URL + let data; + try { + const response = await fetch(this.assetIndex.url); + data = await response.json(); + } catch (err: any) { + throw new Error(`Failed to fetch asset index: ${err.message}`); + } + + // First item is the index file itself, which we'll store locally + const assetsArray: AssetItem[] = [ + { + type: 'CFILE', + path: `assets/indexes/${this.assetIndex.id}.json`, + content: JSON.stringify(data) + } + ]; + + // Convert the "objects" property into a list of individual assets + const objects = Object.values(data.objects || {}); + for (const obj of objects as Array<{ hash: string; size: number }>) { + assetsArray.push({ + type: 'Assets', + sha1: obj.hash, + size: obj.size, + path: `assets/objects/${obj.hash.substring(0, 2)}/${obj.hash}`, + url: `https://resources.download.minecraft.net/${obj.hash.substring(0, 2)}/${obj.hash}` + }); + } + + return assetsArray; + } + + /** + * Copies legacy assets (when using older versions of Minecraft) from + * the main "objects" folder to a "resources" folder, preserving the + * directory structure. + * + * @param versionJson A JSON object that has an "assets" property for the index name. + */ + public copyAssets(versionJson: VersionJSON): void { + // Determine the legacy directory where resources should go + let legacyDirectory = `${this.options.path}/resources`; + if (this.options.instance) { + legacyDirectory = `${this.options.path}/instances/${this.options.instance}/resources`; + } + + // The path to the local asset index JSON + const pathAssets = `${this.options.path}/assets/indexes/${versionJson.assets}.json`; + if (!fs.existsSync(pathAssets)) { + return; // Nothing to copy if the file doesn't exist + } + + // Parse the asset index JSON + let assetsData; + try { + assetsData = JSON.parse(fs.readFileSync(pathAssets, 'utf-8')); + } catch (err: any) { + throw new Error(`Failed to read assets index file: ${err.message}`); + } + + // Each entry is [filePath, { hash, size }] + const assetsEntries = Object.entries(assetsData.objects || {}); + for (const [filePath, hashData] of assetsEntries) { + const hashObj = hashData as { hash: string; size: number }; + const fullHash = hashObj.hash; + const subHash = fullHash.substring(0, 2); + + // Directory where the hashed file is stored + const subAssetDir = `${this.options.path}/assets/objects/${subHash}`; + + // If needed, create the corresponding directories in the legacy folder + const pathSegments = filePath.split('/'); + pathSegments.pop(); // Remove the last segment (the filename itself) + if (!fs.existsSync(`${legacyDirectory}/${pathSegments.join('/')}`)) { + fs.mkdirSync(`${legacyDirectory}/${pathSegments.join('/')}`, { recursive: true }); + } + + // Copy the file if it doesn't already exist in the legacy location + const sourceFile = `${subAssetDir}/${fullHash}`; + const targetFile = `${legacyDirectory}/${filePath}`; + if (!fs.existsSync(targetFile)) { + fs.copyFileSync(sourceFile, targetFile); + } + } + } +} diff --git a/src/Minecraft/Minecraft-Bundle.ts b/src/Minecraft/Minecraft-Bundle.ts index ad047eb3..08aa00e1 100755 --- a/src/Minecraft/Minecraft-Bundle.ts +++ b/src/Minecraft/Minecraft-Bundle.ts @@ -1,51 +1,221 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ import fs from 'fs'; import path from 'path'; -import crypto from 'crypto'; +import { getFileHash } from '../utils/Index.js'; +/** + * Represents a single file or object that may need to be downloaded or checked. + */ +export interface BundleItem { + type?: 'CFILE' | 'Assets' | string; // e.g., "CFILE" for direct content files + path: string; // Local path where file is or should be stored + folder?: string; // Directory path (derived from 'path') + content?: string; // File content if type === "CFILE" + sha1?: string; // Expected SHA-1 hash for the file + size?: number; // Size in bytes if relevant + url?: string; // Download URL if relevant +} + +/** + * Options for the MinecraftBundle class, indicating paths and ignored files. + */ +export interface MinecraftBundleOptions { + path: string; // The main Minecraft directory or root path + instance?: string; // Instance name, if working with multiple instances + ignored: string[]; // Files or directories to ignore when cleaning +} + +/** + * This class manages checking, downloading, and cleaning up Minecraft files. + * It compares local files with a provided bundle, identifies missing or + * outdated files, and can remove extraneous files. + */ export default class MinecraftBundle { - options: any; - constructor(options: any) { - this.options = options; - } - - async checkBundle(bundle: any) { - let todownload = []; - - for (let file of bundle) { - if (!file.path) continue; - file.path = path.resolve(this.options.path, file.path).replace(/\\/g, "/"); - file.folder = file.path.split("/").slice(0, -1).join("/"); - - if (file.type == "CFILE") { - if (!fs.existsSync(file.folder)) fs.mkdirSync(file.folder, { recursive: true, mode: 0o777 }); - fs.writeFileSync(file.path, file.content, { encoding: "utf8", mode: 0o755 }); - continue; - } - - if (fs.existsSync(file.path)) { - if (this.options.ignored.find(ignored => ignored == file.path.split("/").slice(-1)[0])) continue - if (file.sha1) if (!(await this.checkSHA1(file.path, file.sha1))) todownload.push(file); - } else todownload.push(file); - } - return todownload; - } - - async checkSHA1(file: string, sha1: string) { - const hex = crypto.createHash('sha1').update(fs.readFileSync(file)).digest('hex') - if (hex == sha1) return true; - return false; - } - - async getTotalSize(bundle: any) { - let todownload = 0; - for (let file of bundle) { - todownload += file.size; - } - return todownload; - } -} \ No newline at end of file + private options: MinecraftBundleOptions; + + constructor(options: MinecraftBundleOptions) { + this.options = options; + } + + /** + * Checks each item in the provided bundle to see if it needs to be + * downloaded or updated (e.g., if hashes don't match). + * + * @param bundle Array of file items describing what needs to be on disk. + * @returns Array of BundleItem objects that require downloading. + */ + public async checkBundle(bundle: BundleItem[]): Promise { + const toDownload: BundleItem[] = []; + + for (const file of bundle) { + if (!file.path) continue; + + // Convert path to absolute, consistent format + file.path = path.resolve(this.options.path, file.path).replace(/\\/g, '/'); + file.folder = file.path.split('/').slice(0, -1).join('/'); + + // If it's a direct content file (CFILE), we create/write the content immediately + if (file.type === 'CFILE') { + if (!fs.existsSync(file.folder)) { + fs.mkdirSync(file.folder, { recursive: true, mode: 0o777 }); + } + fs.writeFileSync(file.path, file.content ?? '', { encoding: 'utf8', mode: 0o755 }); + continue; + } + + // If the file is supposed to have a certain hash, check it. + if (fs.existsSync(file.path)) { + // Build the instance path prefix for ignoring checks + let replaceName = `${this.options.path}/`; + if (this.options.instance) { + replaceName = `${this.options.path}/instances/${this.options.instance}/`; + } + + // If file is in "ignored" list, skip checks + const relativePath = file.path.replace(replaceName, ''); + if (this.options.ignored.includes(relativePath)) { + continue; + } + + // If the file has a hash and doesn't match, mark it for download + if (file.sha1) { + const localHash = await getFileHash(file.path); + if (localHash !== file.sha1) { + toDownload.push(file); + } + } + } else { + // The file doesn't exist at all, mark it for download + toDownload.push(file); + } + } + + return toDownload; + } + + /** + * Calculates the total download size of all files in the bundle. + * + * @param bundle Array of items in the bundle (with a 'size' field). + * @returns Sum of all file sizes in bytes. + */ + public async getTotalSize(bundle: BundleItem[]): Promise { + let totalSize = 0; + for (const file of bundle) { + if (file.size) { + totalSize += file.size; + } + } + return totalSize; + } + + /** + * Removes files or directories that should not be present, i.e., those + * not listed in the bundle and not in the "ignored" list. + * If the file is a directory, it's removed recursively. + * + * @param bundle Array of BundleItems representing valid files. + */ + public async checkFiles(bundle: BundleItem[]): Promise { + // If using instances, ensure the 'instances' directory exists + let instancePath = ''; + if (this.options.instance) { + if (!fs.existsSync(`${this.options.path}/instances`)) { + fs.mkdirSync(`${this.options.path}/instances`, { recursive: true }); + } + instancePath = `/instances/${this.options.instance}`; + } + + // Gather all existing files in the relevant directory + const allFiles = this.options.instance + ? this.getFiles(`${this.options.path}${instancePath}`) + : this.getFiles(this.options.path); + + // Also gather files from "loader" and "runtime" directories to ignore + const ignoredFiles = [ + ...this.getFiles(`${this.options.path}/loader`), + ...this.getFiles(`${this.options.path}/runtime`) + ]; + + // Convert custom ignored paths to actual file paths + for (let ignoredPath of this.options.ignored) { + ignoredPath = `${this.options.path}${instancePath}/${ignoredPath}`; + if (fs.existsSync(ignoredPath)) { + if (fs.statSync(ignoredPath).isDirectory()) { + // If it's a directory, add all files within it + ignoredFiles.push(...this.getFiles(ignoredPath)); + } else { + // If it's a single file, just add that file + ignoredFiles.push(ignoredPath); + } + } + } + + // Mark bundle paths as ignored (so we don't delete them) + bundle.forEach(file => { + ignoredFiles.push(file.path); + }); + + // Filter out all ignored files from the main file list + const filesToDelete = allFiles.filter(file => !ignoredFiles.includes(file)); + + // Remove each file or directory + for (const filePath of filesToDelete) { + try { + const stats = fs.statSync(filePath); + if (stats.isDirectory()) { + fs.rmSync(filePath, { recursive: true }); + } else { + fs.unlinkSync(filePath); + + // Clean up empty folders going upward until we hit the main path + let currentDir = path.dirname(filePath); + while (true) { + if (currentDir === this.options.path) break; + const dirContents = fs.readdirSync(currentDir); + if (dirContents.length === 0) { + fs.rmSync(currentDir); + } + currentDir = path.dirname(currentDir); + } + } + } catch { + // If an error occurs (e.g. file locked or non-existent), skip it + continue; + } + } + } + + /** + * Recursively gathers all files in a given directory path. + * If a directory is empty, it is also added to the returned array. + * + * @param dirPath The starting directory path to walk. + * @param collectedFiles Used internally to store file paths. + * @returns The array of all file paths (and empty directories) under dirPath. + */ + private getFiles(dirPath: string, collectedFiles: string[] = []): string[] { + if (fs.existsSync(dirPath)) { + const entries = fs.readdirSync(dirPath); + // If the directory is empty, store it as a "file" so it can be processed + if (entries.length === 0) { + collectedFiles.push(dirPath); + } + // Explore each child entry + for (const entry of entries) { + const fullPath = `${dirPath}/${entry}`; + const stats = fs.statSync(fullPath); + if (stats.isDirectory()) { + this.getFiles(fullPath, collectedFiles); + } else { + collectedFiles.push(fullPath); + } + } + } + return collectedFiles; + } +} diff --git a/src/Minecraft/Minecraft-Java.ts b/src/Minecraft/Minecraft-Java.ts index 8af5e865..6957c452 100755 --- a/src/Minecraft/Minecraft-Java.ts +++ b/src/Minecraft/Minecraft-Java.ts @@ -1,58 +1,290 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ import os from 'os'; -import nodeFetch from 'node-fetch'; import path from 'path'; +import fs from 'fs'; +import EventEmitter from 'events'; -export default class java { - options: any; - constructor(options: any) { - this.options = options; - } - - async GetJsonJava(jsonversion: any) { - let version: any; - let files: any = []; - let javaVersionsJson = await nodeFetch("https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json").then(res => res.json()) - - if (!jsonversion.javaVersion) jsonversion = "jre-legacy" - else jsonversion = jsonversion.javaVersion.component - - if (os.platform() == "win32") { - let arch = { x64: "windows-x64", ia32: "windows-x86" } - version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].version.name}` - javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].manifest.url).then(res => res.json())).files) - } else if (os.platform() == "darwin") { - let arch = { x64: "mac-os", arm64: "mac-os-arm64" } - version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].version.name}` - javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].manifest.url).then(res => res.json())).files) - } else if (os.platform() == "linux") { - let arch = { x64: "linux", ia32: "linux-i386" } - version = `jre-${javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].version.name}` - javaVersionsJson = Object.entries((await nodeFetch(javaVersionsJson[`${arch[os.arch()]}`][jsonversion][0].manifest.url).then(res => res.json())).files) - } else return console.log("OS not supported"); - - let java = javaVersionsJson.find(file => file[0].endsWith(process.platform == "win32" ? "bin/javaw.exe" : "bin/java"))[0]; - let toDelete = java.replace(process.platform == "win32" ? "bin/javaw.exe" : "bin/java", ""); - - for (let [path, info] of javaVersionsJson) { - if (info.type == "directory") continue; - if (!info.downloads) continue; - let file: any = {}; - file.path = `runtime/${version}/${path.replace(toDelete, "")}`; - file.executable = info.executable; - file.sha1 = info.downloads.raw.sha1; - file.size = info.downloads.raw.size; - file.url = info.downloads.raw.url; - file.type = "Java"; - files.push(file); - } - return { - files: files, - path: path.resolve(this.options.path, `runtime/${version}/bin/java${process.platform == "win32" ? ".exe" : ""}`).replace(/\\/g, "/"), - }; - } -} \ No newline at end of file +import { getFileFromArchive } from '../utils/Index.js'; +import Downloader from '../utils/Downloader.js'; + +/** + * Represents the Java-specific options a user might pass to the downloader. + */ +export interface JavaDownloaderOptions { + path: string; // Base path to store the downloaded Java runtime + java: { + version?: string; // Force a specific Java version (e.g., "17") + type: string; // Image type for Adoptium (e.g., "jdk" or "jre") + }; + intelEnabledMac?: boolean; // If `true`, allows using Intel-based Java on Apple Silicon +} + +/** + * A generic JSON structure for the Minecraft version, which may include + * a javaVersion property. Adjust as needed to fit your actual data. + */ +export interface MinecraftVersionJSON { + javaVersion?: { + component?: string; // e.g., "jre-legacy" or "java-runtime-alpha" + majorVersion?: number; // e.g., 8, 17, 19 + }; +} + +/** + * Structure returned by getJavaFiles() and getJavaOther(). + */ +export interface JavaDownloadResult { + files: JavaFileItem[]; + path: string; // Local path to the java executable + error?: boolean; // Indicate an error if any + message?: string; // Error message if error is true +} + +/** + * Represents a single Java file entry that might need downloading. + */ +export interface JavaFileItem { + path: string; // Relative path to store the file under the runtime directory + executable?: boolean; + sha1?: string; + size?: number; + url?: string; + type?: string; // "Java" or other type +} + +/** + * Manages the download and extraction of the correct Java runtime for Minecraft. + * It supports both Mojang's curated list of Java runtimes and the Adoptium fallback. + */ +export default class JavaDownloader extends EventEmitter { + private options: JavaDownloaderOptions; + + constructor(options: JavaDownloaderOptions) { + super(); + this.options = options; + } + + /** + * Retrieves Java files from Mojang's runtime metadata if possible, + * otherwise falls back to getJavaOther(). + * + * @param jsonversion A JSON object describing the Minecraft version (with optional javaVersion). + * @returns An object containing a list of JavaFileItems and the final path to "java". + */ + public async getJavaFiles(jsonversion: MinecraftVersionJSON): Promise { + // If a specific version is forced, delegate to getJavaOther() immediately + if (this.options.java.version) { + return this.getJavaOther(jsonversion, this.options.java.version); + } + + // OS-to-architecture mapping for Mojang's curated Java. + const archMapping: Record> = { + win32: { x64: 'windows-x64', ia32: 'windows-x86', arm64: 'windows-arm64' }, + darwin: { x64: 'mac-os', arm64: this.options.intelEnabledMac ? 'mac-os' : 'mac-os-arm64' }, + linux: { x64: 'linux', ia32: 'linux-i386' } + }; + + const osPlatform = os.platform(); // "win32", "darwin", "linux", ... + const arch = os.arch(); // "x64", "arm64", "ia32", ... + + const javaVersionName = jsonversion.javaVersion?.component || 'jre-legacy'; + const osArchMapping = archMapping[osPlatform]; + const files: JavaFileItem[] = []; + + // If we don't have a valid mapping for the current OS, fallback to Adoptium + if (!osArchMapping) { + return this.getJavaOther(jsonversion); + } + + // Determine the OS-specific identifier + const archOs = osArchMapping[arch]; + if (!archOs) { + // If we can't match the arch in the sub-object, fallback + return this.getJavaOther(jsonversion); + } + + // Fetch Mojang's Java runtime metadata + const url = 'https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json'; + const javaVersionsJson = await fetch(url).then(res => res.json()); + + const versionName = javaVersionsJson[archOs]?.[javaVersionName]?.[0]?.version?.name; + if (!versionName) { + return this.getJavaOther(jsonversion); + } + + // Fetch the runtime manifest which lists individual files + const manifestUrl = javaVersionsJson[archOs][javaVersionName][0]?.manifest?.url; + const manifest = await fetch(manifestUrl).then(res => res.json()); + const manifestEntries: Array<[string, any]> = Object.entries(manifest.files); + + // Identify the Java executable in the manifest + const javaExeKey = process.platform === 'win32' ? 'bin/javaw.exe' : 'bin/java'; + const javaEntry = manifestEntries.find(([relPath]) => relPath.endsWith(javaExeKey)); + if (!javaEntry) { + // If we can't find the executable, fallback + return this.getJavaOther(jsonversion); + } + + const toDelete = javaEntry[0].replace(javaExeKey, ''); + for (const [relPath, info] of manifestEntries) { + if (info.type === 'directory') continue; + if (!info.downloads) continue; + + files.push({ + path: `runtime/jre-${versionName}-${archOs}/${relPath.replace(toDelete, '')}`, + executable: info.executable, + sha1: info.downloads.raw.sha1, + size: info.downloads.raw.size, + url: info.downloads.raw.url, + type: 'Java' + }); + } + + return { + files, + path: path.resolve( + this.options.path, + `runtime/jre-${versionName}-${archOs}`, + 'bin', + process.platform === 'win32' ? 'javaw.exe' : 'java' + ) + }; + } + + /** + * Fallback method to download Java from Adoptium if Mojang's metadata is unavailable + * or doesn't have the appropriate runtime for the user's platform/arch. + * + * @param jsonversion A Minecraft version JSON (with optional javaVersion). + * @param versionDownload A forced Java version (string) if provided by the user. + */ + public async getJavaOther(jsonversion: MinecraftVersionJSON, versionDownload?: string): Promise { + const { platform, arch } = this.getPlatformArch(); + const majorVersion = versionDownload || jsonversion.javaVersion?.majorVersion || 8; + const pathFolder = path.resolve(this.options.path, `runtime/jre-${majorVersion}`); + + // Build the API query to fetch the Java version + const queryParams = new URLSearchParams({ + java_version: majorVersion.toString(), + os: platform, + arch: arch, + archive_type: 'zip', + java_package_type: this.options.java.type + }); + const javaVersionURL = `https://api.azul.com/metadata/v1/zulu/packages/?${queryParams.toString()}`; + let javaVersions = await fetch(javaVersionURL).then(res => res.json()); + if (!Array.isArray(javaVersions) || javaVersions.length === 0) { + return { files: [], path: '', error: true, message: 'No Java versions found for the specified parameters.' }; + } + javaVersions = javaVersions[0]; + + let javaExePath = path.join(pathFolder, javaVersions.name.replace('.zip', ''), 'bin', 'java'); + if (platform === 'macos') { + try { + const pathBin = fs.readFileSync(path.join(pathFolder, javaVersions.name.replace('.zip', ''), "bin"), 'utf8').toString(); + javaExePath = path.join(pathFolder, javaVersions.name.replace('.zip', ''), pathBin, 'java'); + } catch (_) { + } + } + + if (!fs.existsSync(javaExePath)) { + await this.verifyAndDownloadFile({ + filePath: path.join(pathFolder, javaVersions.name), + pathFolder: pathFolder, + fileName: javaVersions.name, + url: javaVersions.download_url + }) + + const entries = await getFileFromArchive(path.join(pathFolder, javaVersions.name), null, null, true); + + for (const entry of entries) { + if (entry.name.startsWith('META-INF')) continue; + + if (entry.isDirectory) { + fs.mkdirSync(`${pathFolder}/${entry.name}`, { recursive: true, mode: 0o777 }); + continue; + } + fs.writeFileSync(`${pathFolder}/${entry.name}`, entry.data, { mode: 0o777 }); + } + + if (platform === 'macos') { + try { + const pathBin = fs.readFileSync(path.join(pathFolder, javaVersions.name.replace('.zip', ''), "bin"), 'utf8').toString(); + javaExePath = path.join(pathFolder, javaVersions.name.replace('.zip', ''), pathBin, 'java'); + } catch (_) { + } + } + } + + return { files: [], path: javaExePath }; + } + + /** + * Maps the Node `os.platform()` and `os.arch()` to Adoptium's expected format. + * Apple Silicon can optionally download x64 if `intelEnabledMac` is true. + */ + private getPlatformArch(): { platform: string; arch: string } { + const platformMap: Record = { + win32: 'windows', + darwin: 'macos', + linux: 'linux' + }; + const archMap: Record = { + x64: 'x64', + ia32: 'x32', + arm64: 'aarch64', + arm: 'arm' + }; + + const mappedPlatform = platformMap[os.platform()] || os.platform(); + let mappedArch = archMap[os.arch()] || os.arch(); + + // Force x64 if Apple Silicon but user wants to use Intel-based Java + if (os.platform() === 'darwin' && os.arch() === 'arm64' && this.options.intelEnabledMac) { + mappedArch = 'x64'; + } + + return { platform: mappedPlatform, arch: mappedArch }; + } + + /** + * Verifies if the Java archive already exists and matches the expected checksum. + * If it doesn't exist or fails the hash check, it downloads from the given URL. + * + * @param params.filePath The local file path + * @param params.pathFolder The folder to place the file in + * @param params.fileName The name of the file + * @param params.url The remote download URL + * @param params.checksum Expected SHA-256 hash + */ + private async verifyAndDownloadFile({ + filePath, + pathFolder, + fileName, + url + }: { + filePath: string; + pathFolder: string; + fileName: string; + url: string; + }): Promise { + + // If not found or failed checksum, download anew + if (!fs.existsSync(filePath)) { + fs.mkdirSync(pathFolder, { recursive: true }); + const download = new Downloader(); + + // Relay progress events + download.on('progress', (downloaded: number, size: number) => { + this.emit('progress', downloaded, size, fileName); + }); + + // Start download + await download.downloadFile(url, pathFolder, fileName); + } + } +} diff --git a/src/Minecraft/Minecraft-Json.ts b/src/Minecraft/Minecraft-Json.ts index 4a72d381..340f01d8 100755 --- a/src/Minecraft/Minecraft-Json.ts +++ b/src/Minecraft/Minecraft-Json.ts @@ -1,40 +1,115 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ -import nodeFetch from 'node-fetch'; +import os from 'os'; +import MinecraftNativeLinuxARM from './Minecraft-Lwjgl-Native.js'; +/** + * Basic structure for options passed to the Json class. + * Modify or expand based on your actual usage. + */ +export interface JsonOptions { + version: string; // The targeted Minecraft version (e.g. "1.19", "latest_release", etc.) + [key: string]: any; // Include any additional fields needed by your code +} + +/** + * Represents a single version entry from Mojang's version manifest. + */ +export interface VersionEntry { + id: string; + type: string; + url: string; + time: string; + releaseTime: string; +} + +/** + * Structure of the Mojang version manifest (simplified). + */ +export interface MojangVersionManifest { + latest: { + release: string; + snapshot: string; + }; + versions: VersionEntry[]; +} + +/** + * Structure returned by the getInfoVersion method on success. + */ +export interface GetInfoVersionResult { + InfoVersion: VersionEntry; + json: any; // The specific version JSON fetched from Mojang + version: string; // The final resolved version (e.g., "1.19" if "latest_release" was given) +} + +/** + * Structure returned by getInfoVersion if an error occurs (version not found). + */ +export interface GetInfoVersionError { + error: true; + message: string; +} + +/** + * This class retrieves Minecraft version information from Mojang's + * version manifest, and optionally processes the JSON for ARM-based Linux. + */ export default class Json { - options: any; - - constructor(options: any) { - this.options = options; - } - - async GetInfoVersion() { - let version: string = this.options.version; - let data: any = await nodeFetch(`https://launchermeta.mojang.com/mc/game/version_manifest_v2.json?_t=${new Date().toISOString()}`); - data = await data.json(); - - if (version == 'latest_release' || version == 'r' || version == 'lr') { - version = data.latest.release; - } - else if (version == 'latest_snapshot' || version == 's' || version == 'ls') { - version = data.latest.snapshot; - } - - data = data.versions.find(v => v.id === version); - - if (!data) return { - error: true, - message: `Minecraft ${version} is not found.` - }; - - return { - InfoVersion: data, - json: await nodeFetch(data.url).then(res => res.json()), - version: version - }; - } -} \ No newline at end of file + private readonly options: JsonOptions; + + constructor(options: JsonOptions) { + this.options = options; + } + + /** + * Fetches the Mojang version manifest, resolves the intended version (release, snapshot, etc.), + * and returns the associated JSON object for that version. + * If the system is Linux ARM, it will run additional processing on the JSON. + * + * @returns An object containing { InfoVersion, json, version }, or an error object. + */ + public async GetInfoVersion(): Promise { + let { version } = this.options; + + // Fetch the version manifest + const response = await fetch( + `https://launchermeta.mojang.com/mc/game/version_manifest_v2.json?_t=${new Date().toISOString()}` + ); + const manifest: MojangVersionManifest = await response.json(); + + // Resolve "latest_release"/"latest_snapshot" shorthands + if (version === 'latest_release' || version === 'r' || version === 'lr') { + version = manifest.latest.release; + } else if (version === 'latest_snapshot' || version === 's' || version === 'ls') { + version = manifest.latest.snapshot; + } + + // Find the matching version info from the manifest + const matchedVersion = manifest.versions.find((v) => v.id === version); + if (!matchedVersion) { + return { + error: true, + message: `Minecraft ${version} is not found.` + }; + } + + // Fetch the detailed version JSON from Mojang + const jsonResponse = await fetch(matchedVersion.url); + let versionJson = await jsonResponse.json(); + + // If on Linux ARM, run additional processing + if (os.platform() === 'linux' && os.arch().startsWith('arm')) { + versionJson = await new MinecraftNativeLinuxARM(this.options).ProcessJson(versionJson); + } + + return { + InfoVersion: matchedVersion, + json: versionJson, + version + }; + } +} diff --git a/src/Minecraft/Minecraft-Libraries.ts b/src/Minecraft/Minecraft-Libraries.ts index 5ca38b0f..df21c512 100755 --- a/src/Minecraft/Minecraft-Libraries.ts +++ b/src/Minecraft/Minecraft-Libraries.ts @@ -1,171 +1,265 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ import os from 'os'; import fs from 'fs'; -import AdmZip from 'adm-zip'; -import nodeFetch from 'node-fetch'; +import { getFileFromArchive } from '../utils/Index.js'; -let MojangLib = { win32: "windows", darwin: "osx", linux: "linux" }; -let Arch = { x32: "32", x64: "64", arm: "32", arm64: "64" }; +/** + * Maps Node.js platforms to Mojang's naming scheme for OS in library natives. + */ +const MojangLib: Record = { + win32: 'windows', + darwin: 'osx', + linux: 'linux' +}; + +/** + * Maps Node.js architecture strings to Mojang's arch replacements (e.g., "${arch}" => 64). + */ +const Arch: Record = { + x32: '32', + x64: '64', + arm: '32', + arm64: '64' +}; + +/** + * Represents a single library entry in the version JSON. + * Adjust or extend this interface based on your actual JSON structure. + */ +interface MinecraftLibrary { + name?: string; + rules?: Array<{ + os?: { name: string }; + action?: string; + }>; + natives?: Record; + downloads: { + artifact?: { + sha1: string; + size: number; + path: string; + url: string; + }; + classifiers?: Record< + string, + { + sha1: string; + size: number; + path: string; + url: string; + } + >; + }; +} + +/** + * Represents a Minecraft version JSON structure. + * Extend this interface to reflect any additional fields you use. + */ +interface MinecraftVersionJSON { + id: string; + libraries: MinecraftLibrary[]; + downloads: { + client: { + sha1: string; + size: number; + url: string; + }; + }; + [key: string]: any; +} +/** + * Represents an item in the optional "asset" array fetched from a custom URL. + */ +interface CustomAssetItem { + path: string; + hash: string; + size: number; + url: string; +} + +/** + * Represents the user-provided options for the Libraries class. + * Adjust as needed for your codebase. + */ +interface LibrariesOptions { + path: string; // Base path to the Minecraft folder + instance?: string; // Instance name if using multi-instances + [key: string]: any; // Other fields your code might need +} + +/** + * Represents a file or library entry that needs to be downloaded and stored. + */ +interface LibraryDownload { + sha1?: string; + size?: number; + path: string; + type: string; + url?: string; + content?: string; // For CFILE entries (JSON content) +} + +/** + * This class is responsible for: + * - Gathering library download info from the version JSON + * - Handling custom asset entries if provided + * - Extracting native libraries for the current OS into the appropriate folder + */ export default class Libraries { - json: any; - options: any; - constructor(options: any) { - this.options = options; - } - - async Getlibraries(json: any) { - this.json = json; - let libraries = []; - - for (let lib of this.json.libraries) { - let artifact: any; - let type = "Libraries"; - - if (lib.natives) { - let classifiers = lib.downloads.classifiers; - let native = lib.natives[MojangLib[process.platform]]; - if (!native) native = lib.natives[process.platform]; - type = "Native"; - if (native) artifact = classifiers[native.replace("${arch}", Arch[os.arch()])]; - else continue; - } else { - if (lib.rules && lib.rules[0].os) { - if (lib.rules[0].os.name !== MojangLib[process.platform]) continue; - } - artifact = lib.downloads.artifact; - } - if (!artifact) continue; - libraries.push({ - sha1: artifact.sha1, - size: artifact.size, - path: `libraries/${artifact.path}`, - type: type, - url: artifact.url - }); - } - - let clientjar = this.json.downloads.client; - libraries.push({ - sha1: clientjar.sha1, - size: clientjar.size, - path: `versions/${this.json.id}/${this.json.id}.jar`, - type: "Libraries", - url: clientjar.url - }); - - libraries.push({ - path: `versions/${this.json.id}/${this.json.id}.json`, - type: "CFILE", - content: JSON.stringify(this.json) - }); - return libraries; - } - - async GetAssetsOthers(url: any) { - if (!url) return []; - let data = await nodeFetch(url).then(res => res.json()); - - let assets = []; - for (let asset of data) { - if (!asset.path) continue - let path = asset.path; - assets.push({ - sha1: asset.hash, - size: asset.size, - type: path.split("/")[0], - path: this.options.instance ? `${this.options.path}/instances/${this.options.instance}/${path}` : path, - url: asset.url - }); - } - return assets - } - - async natives(bundle: any) { - let natives = bundle.filter(mod => mod.type === "Native").map(mod => `${mod.path}`); - if (natives.length === 0) return natives; - let nativeFolder = (`${this.options.path}/versions/${this.json.id}/natives`).replace(/\\/g, "/"); - if (!fs.existsSync(nativeFolder)) fs.mkdirSync(nativeFolder, { recursive: true, mode: 0o777 }); - - for (let native of natives) { - let zip = new AdmZip(native); - let entries = zip.getEntries(); - for (let entry of entries) { - if (entry.entryName.startsWith("META-INF")) continue; - if (entry.isDirectory) { - fs.mkdirSync(`${nativeFolder}/${entry.entryName}`, { recursive: true, mode: 0o777 }); - continue - } - fs.writeFile(`${nativeFolder}/${entry.entryName}`, zip.readFile(entry), { encoding: "utf8", mode: 0o777 }, () => { }); - } - } - return natives; - } - - async checkFiles(bundle: any) { - let instancePath = '' - let instanceFolder = [] - if (this.options.instance) { - if (!fs.existsSync(`${this.options.path}/instances`)) fs.mkdirSync(`${this.options.path}/instances`, { recursive: true }); - instancePath = `/instances/${this.options.instance}` - instanceFolder = fs.readdirSync(`${this.options.path}/instances`).filter(dir => dir != this.options.instance) - } - let files = this.getFiles(this.options.path); - let ignoredfiles = [...this.getFiles(`${this.options.path}/loader`)] - - for (let instances of instanceFolder) { - ignoredfiles.push(...this.getFiles(`${this.options.path}/instances/${instances}`)); - } - - for (let file of this.options.ignored) { - file = (`${this.options.path}${instancePath}/${file}`) - if (fs.existsSync(file)) { - if (fs.statSync(file).isDirectory()) { - ignoredfiles.push(...this.getFiles(file)); - } else if (fs.statSync(file).isFile()) { - ignoredfiles.push(file); - } - } - } - - ignoredfiles.forEach(file => this.options.ignored.push((file))); - bundle.forEach(file => ignoredfiles.push((file.path))); - files = files.filter(file => ignoredfiles.indexOf(file) < 0); - - for (let file of files) { - try { - if (fs.statSync(file).isDirectory()) { - fs.rmdirSync(file); - } else { - fs.unlinkSync(file); - let folder = file.split("/").slice(0, -1).join("/"); - while (true) { - if (folder == this.options.path) break; - let content = fs.readdirSync(folder); - if (content.length == 0) fs.rmdirSync(folder); - folder = folder.split("/").slice(0, -1).join("/"); - } - } - } catch (e) { - continue; - } - } - } - - getFiles(path: any, file = []) { - if (fs.existsSync(path)) { - let files = fs.readdirSync(path); - if (files.length == 0) file.push(path); - for (let i in files) { - let name = `${path}/${files[i]}`; - if (fs.statSync(name).isDirectory()) this.getFiles(name, file); - else file.push(name); - } - } - return file; - } -} \ No newline at end of file + private json!: MinecraftVersionJSON; + private readonly options: LibrariesOptions; + + constructor(options: LibrariesOptions) { + this.options = options; + } + + /** + * Processes the provided Minecraft version JSON to build a list of libraries + * that need to be downloaded (including the main client jar and the version JSON itself). + * + * @param json A MinecraftVersionJSON object (containing libraries, downloads, etc.) + * @returns An array of LibraryDownload items describing each file. + */ + public async Getlibraries(json: MinecraftVersionJSON): Promise { + this.json = json; + const libraries: LibraryDownload[] = []; + + for (const lib of this.json.libraries) { + let artifact: { sha1: string; size: number; path: string; url: string } | undefined; + let type = 'Libraries'; + + if (lib.natives) { + // If this library has OS natives, pick the correct classifier + const classifiers = lib.downloads.classifiers; + let native = lib.natives[MojangLib[os.platform()]] || lib.natives[os.platform()]; + type = 'Native'; + if (native) { + // Replace "${arch}" if present, e.g. "natives-windows-${arch}" + const archReplaced = native.replace('${arch}', Arch[os.arch()] || ''); + artifact = classifiers ? classifiers[archReplaced] : undefined; + } else { + // No valid native for the current platform + continue; + } + } else { + // If there are rules restricting OS, skip if not matching + if (lib.rules && lib.rules[0]?.os?.name) { + if (lib.rules[0].os.name !== MojangLib[os.platform()]) { + continue; + } + } + artifact = lib.downloads.artifact; + } + + if (!artifact) continue; + + libraries.push({ + sha1: artifact.sha1, + size: artifact.size, + path: `libraries/${artifact.path}`, + type: type, + url: artifact.url + }); + } + + // Add the main Minecraft client JAR to the list + libraries.push({ + sha1: this.json.downloads.client.sha1, + size: this.json.downloads.client.size, + path: `versions/${this.json.id}/${this.json.id}.jar`, + type: 'Libraries', + url: this.json.downloads.client.url + }); + + // Add the JSON file for this version as a "CFILE" + libraries.push({ + path: `versions/${this.json.id}/${this.json.id}.json`, + type: 'CFILE', + content: JSON.stringify(this.json) + }); + + return libraries; + } + + /** + * Fetches custom assets or libraries from a remote URL if provided. + * This method expects the response to be an array of objects with + * "path", "hash", "size", and "url". + * + * @param url The remote URL that returns a JSON array of CustomAssetItem + * @returns An array of LibraryDownload entries describing each item + */ + public async GetAssetsOthers(url: string | null): Promise { + if (!url) return []; + + const response = await fetch(url); + const data: CustomAssetItem[] = await response.json(); + + const assets: LibraryDownload[] = []; + for (const asset of data) { + if (!asset.path) continue; + + // The 'type' is deduced from the first part of the path + const fileType = asset.path.split('/')[0]; + assets.push({ + sha1: asset.hash, + size: asset.size, + type: fileType, + path: this.options.instance + ? `instances/${this.options.instance}/${asset.path}` + : asset.path, + url: asset.url + }); + } + return assets; + } + + /** + * Extracts native libraries from the downloaded jars (those marked type="Native") + * and places them into the "natives" folder under "versions//natives". + * + * @param bundle An array of library entries (some of which may be natives) + * @returns The paths of the native files that were extracted + */ + public async natives(bundle: LibraryDownload[]): Promise { + // Gather only the native library files + const natives = bundle + .filter((item) => item.type === 'Native') + .map((item) => `${item.path}`); + + if (natives.length === 0) { + return []; + } + + // Create the natives folder if it doesn't already exist + const nativesFolder = `${this.options.path}/versions/${this.json.id}/natives`.replace(/\\/g, '/'); + if (!fs.existsSync(nativesFolder)) { + fs.mkdirSync(nativesFolder, { recursive: true, mode: 0o777 }); + } + + // For each native jar, extract its contents (excluding META-INF) + for (const native of natives) { + const entries = await getFileFromArchive(native, null, null, true); + + + for (const entry of entries) { + if (entry.name.startsWith('META-INF')) continue; + + if (entry.isDirectory) { + fs.mkdirSync(`${nativesFolder}/${entry.name}`, { recursive: true, mode: 0o777 }); + continue; + } + + // Write the file to the natives folder + fs.writeFileSync(`${nativesFolder}/${entry.name}`, entry.data, { mode: 0o777 }); + } + } + return natives; + } +} diff --git a/src/Minecraft/Minecraft-Loader.ts b/src/Minecraft/Minecraft-Loader.ts index 4141872c..84e4a3a8 100755 --- a/src/Minecraft/Minecraft-Loader.ts +++ b/src/Minecraft/Minecraft-Loader.ts @@ -1,97 +1,179 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ import { EventEmitter } from 'events'; -const loaderDownloader = require('minecraft-loader'); - - -export default class MinecraftLoader { - options: any; - on: any; - emit: any; - constructor(options: any) { - this.options = options; - this.on = EventEmitter.prototype.on; - this.emit = EventEmitter.prototype.emit; - } - - async GetLoader(version: any, javaPath: any) { - let loader = new loaderDownloader({ - path: `${this.options.path}/loader/${this.options.loader.type}`, - timeout: this.options.timeout, - downloadFileMultiple: this.options.downloadFileMultiple, - autoClean: true, - loader: { - type: this.options.loader.type, - version: version, - build: this.options.loader.build, - config: { - javaPath: javaPath, - minecraftJar: `${this.options.path}/versions/${version}/${version}.jar`, - minecraftJson: `${this.options.path}/versions/${version}/${version}.json` - } - } - }); - return await new Promise((resolve, reject) => { - loader.install(); - - loader.on('json', (json: any) => { - let loaderJson = json; - loaderJson.libraries = loaderJson.libraries.map((lib: any) => { - lib.loader = `${this.options.path}/loader/${this.options.loader.type}`; - return lib; - }); - - resolve(loaderJson); - }); - - loader.on('extract', (extract: any) => { - this.emit('extract', extract); - }); - - loader.on('progress', (progress: any, size: any, element: any) => { - this.emit('progress', progress, size, element); - }); - - loader.on('check', (progress: any, size: any, element: any) => { - this.emit('check', progress, size, element); - }); - - loader.on('patch', (patch: any) => { - this.emit('patch', patch); - }); - - loader.on('error', (err: any) => { - reject(err); - }); - }) - } - - async GetArguments(json: any, version: any) { - if (json === null) { - return { - game: [], - jvm: [] - } - } - - let moddeArguments = json.arguments; - if (!moddeArguments) return { game: [], jvm: [] }; - let Arguments: any = {} - if (moddeArguments.game) Arguments.game = moddeArguments.game; - if (moddeArguments.jvm) Arguments.jvm = moddeArguments.jvm.map(jvm => { - return jvm - .replace(/\${version_name}/g, version) - .replace(/\${library_directory}/g, `${this.options.path}/loader/${this.options.loader.type}/libraries`) - .replace(/\${classpath_separator}/g, process.platform === 'win32' ? ';' : ':'); - }) - - return { - game: Arguments.game || [], - jvm: Arguments.jvm || [], - mainClass: json.mainClass - }; - } -} \ No newline at end of file +import path from 'path'; +// Note: Adjust the import path according to your actual TypeScript setup. +import LoaderDownloader, { LoaderType } from '../Minecraft-Loader/index.js'; + +/** + * Describes the loader options, including a path and other configurations. + * You can expand this interface if your real code requires more fields. + */ +interface LoaderOptions { + path: string; // Base path for the Minecraft data or installation + loader: { + path?: string; // Path to store loader files (e.g. Forge, Fabric) + type?: string; // Type of loader (forge, fabric, etc.) + build?: string; // Build number if applicable (e.g., for Forge) + }; + downloadFileMultiple?: number; // If your downloader can handle multiple files +} + +/** + * Represents the MinecraftLoader class options, merging LoaderOptions + * with any additional fields your code might require. + */ +interface MinecraftLoaderOptions extends LoaderOptions { + // Additional fields that might be needed by your application + [key: string]: any; +} + +/** + * A simple interface describing the JSON structure returned by loader installation. + * Adjust to reflect the actual fields from your loader JSON. + */ +interface LoaderJSON { + libraries: Array<{ + loader?: string; + name?: string; // Or any other required fields + }>; + arguments?: { + game?: string[]; + jvm?: string[]; + }; + mainClass?: string; + [key: string]: any; +} + +/** + * This class manages the installation and argument-building for a Minecraft + * mod loader (e.g. Forge, Fabric). It wraps a `loaderDownloader` and emits + * the same events for progress, extraction, patching, etc. + */ +export default class MinecraftLoader extends EventEmitter { + private options: MinecraftLoaderOptions; + private loaderPath: string; + + constructor(options: MinecraftLoaderOptions) { + super(); + this.options = options; + this.loaderPath = path.join(this.options.path, this.options.loader.path); + } + + /** + * Installs the loader for a given Minecraft version using a LoaderDownloader, + * returning the loader's JSON on completion. This function emits several events + * for progress reporting and patch notifications. + * + * @param version The Minecraft version (e.g. "1.19.2") + * @param javaPath Path to the Java executable used by the loader for patching + * @returns A Promise that resolves to the loader's JSON configuration + */ + public async GetLoader(version: string, javaPath: string): Promise { + const loader = new LoaderDownloader({ + path: this.loaderPath, + downloadFileMultiple: this.options.downloadFileMultiple, + loader: { + type: this.options.loader.type as LoaderType, + version: version, + build: this.options.loader.build, + config: { + javaPath, + minecraftJar: `${this.options.path}/versions/${version}/${version}.jar`, + minecraftJson: `${this.options.path}/versions/${version}/${version}.json` + } + } + }); + + return new Promise((resolve, reject) => { + loader.install(); + + loader.on('json', (json: LoaderJSON) => { + // Inject the loader path into each library if needed + const modifiedJson = json; + modifiedJson.libraries = modifiedJson.libraries.map(lib => { + lib.loader = this.loaderPath; + return lib; + }); + resolve(modifiedJson); + }); + + loader.on('extract', (extract: any) => { + // Forward the "extract" event + this.emit('extract', extract); + }); + + loader.on('progress', (progress: any, size: any, element: any) => { + // Forward the "progress" event + this.emit('progress', progress, size, element); + }); + + loader.on('check', (progress: any, size: any, element: any) => { + // Forward the "check" event + this.emit('check', progress, size, element); + }); + + loader.on('patch', (patch: any) => { + // Forward the "patch" event + this.emit('patch', patch); + }); + + loader.on('error', (err: any) => { + reject(err); + }); + }); + } + + /** + * Builds the game and JVM arguments based on the loader's JSON data. + * This may involve placeholder replacements for the main class, library directories, etc. + * + * @param json The loader JSON previously returned by GetLoader (or null) + * @param version The targeted Minecraft version (used for placeholder substitution) + * @returns An object with `game`, `jvm`, and an optional `mainClass` property + */ + public async GetArguments(json: LoaderJSON | null, version: string): Promise<{ + game: string[]; + jvm: string[]; + mainClass?: string; + }> { + // If no loader JSON is provided, return empty arrays + if (json === null) { + return { game: [], jvm: [] }; + } + + const moddedArgs = json.arguments; + // If no arguments field is present, return empty arrays + if (!moddedArgs) return { game: [], jvm: [] }; + + const args: { + game?: string[]; + jvm?: string[]; + mainClass?: string; + } = {}; + + if (moddedArgs.game) { + args.game = moddedArgs.game; + } + + if (moddedArgs.jvm) { + // Replace placeholders in the JVM arguments + args.jvm = moddedArgs.jvm.map((jvmArg) => + jvmArg + .replace(/\${version_name}/g, version) + .replace(/\${library_directory}/g, `${this.loaderPath}/libraries`) + .replace(/\${classpath_separator}/g, process.platform === 'win32' ? ';' : ':') + ); + } + + args.mainClass = json.mainClass; + return { + game: args.game || [], + jvm: args.jvm || [], + mainClass: args.mainClass + }; + } +} diff --git a/src/Minecraft/Minecraft-Lwjgl-Native.ts b/src/Minecraft/Minecraft-Lwjgl-Native.ts new file mode 100644 index 00000000..1aeb5f16 --- /dev/null +++ b/src/Minecraft/Minecraft-Lwjgl-Native.ts @@ -0,0 +1,109 @@ +/** + * @author Luuxis + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) + */ + +import path from 'path'; +import fs from 'fs'; +import os from 'os'; + +/** + * Minimal interface describing a single library entry in the version JSON. + * Adjust as needed to reflect your actual library data structure. + */ +interface MinecraftLibrary { + name: string; + // You may include other fields like 'downloads', 'natives', etc. if needed +} + +/** + * Represents the structure of a Minecraft version JSON. + * You can expand this interface based on your actual usage. + */ +interface MinecraftVersion { + libraries: MinecraftLibrary[]; + // Additional fields like 'id', 'mainClass', etc. can go here +} + +/** + * Options for constructing the MinecraftLoader, if needed. + * Extend or remove fields to match your actual requirements. + */ +interface LoaderOptions { + // Add any relevant configuration fields if needed + [key: string]: unknown; +} + +/** + * This class modifies the version JSON for ARM-based Linux systems, + * specifically handling LWJGL library replacements for versions 2.9.x or custom LWJGL versions. + */ +export default class MinecraftLoader { + private options: LoaderOptions; + + constructor(options: LoaderOptions) { + this.options = options; + } + + /** + * Processes a Minecraft version JSON, removing default JInput and LWJGL entries + * if needed, then injecting ARM-compatible LWJGL libraries from local JSON files. + * + * @param version A MinecraftVersion object containing a list of libraries + * @returns The same version object, but with updated libraries for ARM-based Linux + */ + public async ProcessJson(version: MinecraftVersion): Promise { + // Maps Node's arm architecture to the expected LWJGL naming + const archMapping: Record = { + arm64: 'aarch64', + arm: 'aarch' + }; + const currentArch = os.arch(); + const mappedArch = archMapping[currentArch]; + + // If running on a non-ARM environment, or if the mapping doesn't exist, no changes are needed + if (!mappedArch) { + return version; + } + + // Path to the directory containing LWJGL JSON files for ARM + const pathLWJGL = path.join(__dirname, '../../assets/LWJGL', mappedArch); + + // Identify the version strings for JInput and LWJGL from the existing libraries + const versionJinput = version.libraries.find(lib => + lib.name.startsWith('net.java.jinput:jinput-platform:') || + lib.name.startsWith('net.java.jinput:jinput:') + )?.name.split(':').pop(); + + const versionLWJGL = version.libraries.find(lib => + lib.name.startsWith('org.lwjgl:lwjgl:') || + lib.name.startsWith('org.lwjgl.lwjgl:lwjgl:') + )?.name.split(':').pop(); + + // Remove all JInput-related libraries if a JInput version is found + if (versionJinput) { + version.libraries = version.libraries.filter(lib => !lib.name.includes('jinput')); + } + + // Remove all LWJGL-related libraries if an LWJGL version is found + if (versionLWJGL) { + version.libraries = version.libraries.filter(lib => !lib.name.includes('lwjgl')); + + // Inject ARM-compatible LWJGL libraries + let lwjglJsonFile = versionLWJGL.includes('2.9') + ? '2.9.4.json' + : `${versionLWJGL}.json`; + + const lwjglPath = path.join(pathLWJGL, lwjglJsonFile); + + // Read the appropriate LWJGL JSON (e.g., "2.9.4.json" or ".json") + const lwjglNativesContent = fs.readFileSync(lwjglPath, 'utf-8'); + const lwjglNatives = JSON.parse(lwjglNativesContent) as MinecraftVersion; + + // Append the ARM-compatible libraries + version.libraries.push(...lwjglNatives.libraries); + } + + return version; + } +} diff --git a/src/StatusServer/buffer.ts b/src/StatusServer/buffer.ts index c99aaa21..f7d250f5 100644 --- a/src/StatusServer/buffer.ts +++ b/src/StatusServer/buffer.ts @@ -1,3 +1,8 @@ +/** + * @author Luuxis + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) + */ + function CustomBuffer(existingBuffer: any = Buffer.alloc(48)) { let buffer = existingBuffer; let offset = 0; diff --git a/src/StatusServer/status.ts b/src/StatusServer/status.ts index d7dadf3b..a0080975 100755 --- a/src/StatusServer/status.ts +++ b/src/StatusServer/status.ts @@ -1,6 +1,6 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ import net from 'net' diff --git a/src/utils/Downloader.ts b/src/utils/Downloader.ts index 0f352fe1..57a784e4 100755 --- a/src/utils/Downloader.ts +++ b/src/utils/Downloader.ts @@ -1,95 +1,244 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ import fs from 'fs'; -import nodeFetch from 'node-fetch'; import { EventEmitter } from 'events'; +import { fromAnyReadable } from './Index.js'; -interface downloadOptions { - url: string, - path: string, - length: number, - folder: string +/** + * Describes a single file to be downloaded by the Downloader class. + */ +export interface DownloadOptions { + /** The URL to download from */ + url: string; + /** Local path (including filename) where the file will be saved */ + path: string; + /** The total length of the file (in bytes), if known */ + length?: number; + /** Local folder in which the file's path resides */ + folder: string; + /** Optional type descriptor, used when emitting 'progress' events */ + type?: string; } -export default class download { - on: any; - emit: any; - - constructor() { - this.on = EventEmitter.prototype.on; - this.emit = EventEmitter.prototype.emit; - } - - async downloadFileMultiple(files: downloadOptions, size: number, limit: number = 1, timeout: number = 10000) { - if (limit > files.length) limit = files.length; - let completed = 0; - let downloaded = 0; - let queued = 0; - - let start = new Date().getTime(); - let before = 0; - let speeds = []; - - let estimated = setInterval(() => { - let duration = (new Date().getTime() - start) / 1000; - let loaded = (downloaded - before) * 8; - if (speeds.length >= 5) speeds = speeds.slice(1); - speeds.push((loaded / duration) / 8); - let speed = 0; - for (let s of speeds) speed += s; - speed /= speeds.length; - this.emit("speed", speed); - let time = (size - downloaded) / (speed); - this.emit("estimated", time); - start = new Date().getTime(); - before = downloaded; - }, 500); - - const downloadNext = async () => { - if (queued < files.length) { - let file = files[queued]; - queued++; - - if (!fs.existsSync(file.foler)) fs.mkdirSync(file.folder, { recursive: true, mode: 0o777 }); - const writer: any = fs.createWriteStream(file.path, { flags: 'w', mode: 0o777 }); - - try { - const response = await nodeFetch(file.url, { timeout: timeout }); - - response.body.on('data', (chunk: any) => { - downloaded += chunk.length; - this.emit('progress', downloaded, size, file.type); - writer.write(chunk); - }); - - response.body.on('end', () => { - writer.end(); - completed++; - downloadNext(); - }); - - } catch (e) { - writer.end(); - completed++; - downloadNext(); - this.emit('error', e); - } - } - }; - - while (queued < limit) downloadNext(); - - return new Promise((resolve: any) => { - const interval = setInterval(() => { - if (completed === files.length) { - clearInterval(estimated); - clearInterval(interval); - resolve(); - } - }, 100); - }); - } -} \ No newline at end of file +/** + * A class responsible for downloading single or multiple files, + * emitting events for progress, speed, estimated time, and errors. + */ +export default class Downloader extends EventEmitter { + /** + * Downloads a single file from the given URL to the specified local path. + * Emits "progress" events with the number of bytes downloaded and total size. + * + * @param url - The remote URL to download from + * @param dirPath - Local folder path where the file is saved + * @param fileName - Name of the file (e.g., "mod.jar") + */ + public async downloadFile(url: string, dirPath: string, fileName: string): Promise { + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { recursive: true }); + } + + const writer = fs.createWriteStream(`${dirPath}/${fileName}`); + const response = await fetch(url); + + const contentLength = response.headers.get('content-length'); + const totalSize = contentLength ? parseInt(contentLength, 10) : 0; + + let downloaded = 0; + + return new Promise((resolve, reject) => { + const body = fromAnyReadable(response.body as any); + + body.on('data', (chunk: Buffer) => { + downloaded += chunk.length; + // Emit progress with the current number of bytes vs. total size + this.emit('progress', downloaded, totalSize); + writer.write(chunk); + }); + + body.on('end', () => { + writer.end(); + resolve(); + }); + + body.on('error', (err: Error) => { + writer.destroy(); + this.emit('error', err); + reject(err); + }); + }); + } + + /** + * Downloads multiple files concurrently (up to the specified limit). + * Emits "progress" events with cumulative bytes downloaded vs. total size, + * as well as "speed" and "estimated" events for speed and ETA calculations. + * + * @param files - An array of DownloadOptions describing each file + * @param size - The total size (in bytes) of all files to be downloaded + * @param limit - The maximum number of simultaneous downloads + * @param timeout - A timeout in milliseconds for each fetch request + */ + public async downloadFileMultiple( + files: DownloadOptions[], + size: number, + limit: number = 1, + timeout: number = 10000 + ): Promise { + if (limit > files.length) limit = files.length; + + let completed = 0; // Number of downloads completed + let downloaded = 0; // Cumulative bytes downloaded + let queued = 0; // Index of the next file to download + + let start = Date.now(); + let before = 0; + const speeds: number[] = []; + + const estimated = setInterval(() => { + const duration = (Date.now() - start) / 1000; + const chunkDownloaded = downloaded - before; + if (speeds.length >= 5) speeds.shift(); + speeds.push(chunkDownloaded / duration); + + const avgSpeed = speeds.reduce((a, b) => a + b, 0) / speeds.length; + this.emit('speed', avgSpeed); + + const timeRemaining = (size - downloaded) / avgSpeed; + this.emit('estimated', timeRemaining); + + start = Date.now(); + before = downloaded; + }, 500); + + const downloadNext = async (): Promise => { + if (queued >= files.length) return; + + const file = files[queued++]; + if (!fs.existsSync(file.folder)) { + fs.mkdirSync(file.folder, { recursive: true, mode: 0o777 }); + } + + const writer = fs.createWriteStream(file.path, { flags: 'w', mode: 0o777 }); + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeout); + + try { + const response = await fetch(file.url, { signal: controller.signal }); + + clearTimeout(timeoutId); + + const stream = fromAnyReadable(response.body as any); + + stream.on('data', (chunk: Buffer) => { + downloaded += chunk.length; + this.emit('progress', downloaded, size, file.type); + writer.write(chunk); + }); + + stream.on('end', () => { + writer.end(); + completed++; + downloadNext(); + }); + + stream.on('error', (err) => { + writer.destroy(); + this.emit('error', err); + completed++; + downloadNext(); + }); + } catch (e) { + clearTimeout(timeoutId); + writer.destroy(); + this.emit('error', e); + completed++; + downloadNext(); + } + }; + + // Start "limit" concurrent downloads + for (let i = 0; i < limit; i++) { + downloadNext(); + } + + // Wait until all downloads complete + return new Promise((resolve) => { + const interval = setInterval(() => { + if (completed === files.length) { + clearInterval(estimated); + clearInterval(interval); + resolve(); + } + }, 100); + }); + } + + /** + * Performs a HEAD request on the given URL to check if it is valid (status=200) + * and retrieves the "content-length" if available. + * + * @param url The URL to check + * @param timeout Time in ms before the request times out + * @returns An object containing { size, status } or rejects with false + */ + public async checkURL( + url: string, + timeout: number = 10000 + ): Promise<{ size: number; status: number } | false> { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeout); + + try { + const res = await fetch(url, { + method: 'HEAD', + signal: controller.signal + }); + + clearTimeout(timeoutId); + + if (res.status === 200) { + const contentLength = res.headers.get('content-length'); + const size = contentLength ? parseInt(contentLength, 10) : 0; + return { size, status: 200 }; + } + return false; + } catch (e: any) { + clearTimeout(timeoutId); + return false; + } + } + + + + /** + * Tries each mirror in turn, constructing an URL (mirror + baseURL). If a valid + * response is found (status=200), it returns the final URL and size. Otherwise, returns false. + * + * @param baseURL The relative path (e.g. "group/id/artifact.jar") + * @param mirrors An array of possible mirror base URLs + * @returns An object { url, size, status } if found, or false if all mirrors fail + */ + public async checkMirror( + baseURL: string, + mirrors: string[] + ): Promise<{ url: string; size: number; status: number } | false> { + + for (const mirror of mirrors) { + const testURL = `${mirror}/${baseURL}`; + const res = await this.checkURL(testURL); + + if (res !== false && res.status === 200) { + return { + url: testURL, + size: res.size, + status: 200 + }; + } + } + return false; + } +} diff --git a/src/utils/Index.ts b/src/utils/Index.ts index aa299dc2..f92d3589 100755 --- a/src/utils/Index.ts +++ b/src/utils/Index.ts @@ -1,21 +1,288 @@ /** * @author Luuxis - * @license CC-BY-NC 4.0 - https://creativecommons.org/licenses/by-nc/4.0/ + * Luuxis License v1.0 (voir fichier LICENSE pour les détails en FR/EN) */ -function getPathLibraries(main: any, nativeString?: any, forceExt?: any) { - let libSplit = main.split(':') - let fileName = libSplit[3] ? `${libSplit[2]}-${libSplit[3]}` : libSplit[2]; - let finalFileName = fileName.includes('@') ? fileName.replace('@', '.') : `${fileName}${nativeString || ''}${forceExt || '.jar'}`; - let pathLib = `${libSplit[0].replace(/\./g, '/')}/${libSplit[1]}/${libSplit[2].split('@')[0]}` - return { - path: pathLib, - name: `${libSplit[1]}-${finalFileName}` - }; +import crypto from 'crypto'; +import fs from 'fs'; +import { Readable } from 'node:stream'; +import Unzipper from './unzipper.js'; + +// This interface defines the structure of a Minecraft library rule. +interface LibraryRule { + action: 'allow' | 'disallow'; + os?: { + name?: string; + }; + features?: any; // Adjust or remove if not used in your code +} + +/** + * Represents a Library object, possibly containing rules or additional fields. + * Adjust according to your actual library structure. + */ +interface MinecraftLibrary { + name: string; + rules?: LibraryRule[]; + downloads?: { + artifact?: { + url?: string; + size?: number; + }; + }; + natives?: Record; + [key: string]: any; // Extend if needed +} + +/** + * Represents a minimal version JSON structure to check if it's considered "old" (pre-1.6 or legacy). + */ +interface MinecraftVersionJSON { + assets?: string; // "legacy" or "pre-1.6" indicates older assets + [key: string]: any; +} + +/** + * Parses a Gradle/Maven identifier string (like "net.minecraftforge:forge:1.19-41.0.63") + * into a local file path (group/artifact/version) and final filename (artifact-version.jar). + * Optionally allows specifying a native string suffix or forcing an extension. + * + * @param main A Gradle-style coordinate (group:artifact:version[:classifier]) + * @param nativeString A suffix for native libraries (e.g., "-natives-linux") + * @param forceExt A forced file extension (default is ".jar") + * @returns An object with `path` and `name`, where `path` is the directory path and `name` is the filename + */ +function getPathLibraries(main: string, nativeString?: string, forceExt?: string) { + // Example "net.minecraftforge:forge:1.19-41.0.63" + const libSplit = main.split(':'); + + // If there's a fourth element, it's typically a classifier appended to version + const fileName = libSplit[3] ? `${libSplit[2]}-${libSplit[3]}` : libSplit[2]; + + // Replace '@' in versions if present (e.g., "1.0@beta" => "1.0.beta") + let finalFileName = fileName.includes('@') + ? fileName.replace('@', '.') + : `${fileName}${nativeString || ''}${forceExt || '.jar'}`; + + // Construct the path: "net.minecraftforge" => "net/minecraftforge" + // artifact => "forge" + // version => "1.19-41.0.63" + const pathLib = `${libSplit[0].replace(/\./g, '/')}/${libSplit[1]}/${libSplit[2].split('@')[0]}`; + + return { + path: pathLib, + name: `${libSplit[1]}-${finalFileName}`, + version: libSplit[2], + }; +} + +/** + * Computes a hash (default SHA-1) of the given file by streaming its contents. + * + * @param filePath Full path to the file on disk + * @param algorithm Hashing algorithm (default: "sha1") + * @returns A Promise resolving to the hex string of the file's hash + */ +async function getFileHash(filePath: string, algorithm: string = 'sha1'): Promise { + const shasum = crypto.createHash(algorithm); + const fileStream = fs.createReadStream(filePath); + + return new Promise((resolve) => { + fileStream.on('data', (data) => { + shasum.update(data); + }); + + fileStream.on('end', () => { + resolve(shasum.digest('hex')); + }); + }); +} + +/** + * Determines if a given Minecraft version JSON is considered "old" + * by checking its assets field (e.g., "legacy" or "pre-1.6"). + * + * @param json The Minecraft version JSON + * @returns true if it's an older version, false otherwise + */ +function isold(json: MinecraftVersionJSON): boolean { + return json.assets === 'legacy' || json.assets === 'pre-1.6'; } -function isold(json: any) { - return json.assets === 'legacy' || json.assets === 'pre-1.6' +/** + * Returns metadata necessary to download specific loaders (Forge, Fabric, etc.) + * based on a loader type string (e.g., "forge", "fabric"). + * If the loader type is unrecognized, returns undefined. + * + * @param type A string representing the loader type + */ +function loader(type: string) { + if (type === 'forge') { + return { + metaData: 'https://files.minecraftforge.net/net/minecraftforge/forge/maven-metadata.json', + meta: 'https://files.minecraftforge.net/net/minecraftforge/forge/${build}/meta.json', + promotions: 'https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json', + install: 'https://maven.minecraftforge.net/net/minecraftforge/forge/${version}/forge-${version}-installer', + universal: 'https://maven.minecraftforge.net/net/minecraftforge/forge/${version}/forge-${version}-universal', + client: 'https://maven.minecraftforge.net/net/minecraftforge/forge/${version}/forge-${version}-client' + }; + } else if (type === 'neoforge') { + return { + legacyMetaData: 'https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge', + metaData: 'https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge', + legacyInstall: 'https://maven.neoforged.net/releases/net/neoforged/forge/${version}/forge-${version}-installer.jar', + install: 'https://maven.neoforged.net/releases/net/neoforged/neoforge/${version}/neoforge-${version}-installer.jar' + }; + } else if (type === 'fabric') { + return { + metaData: 'https://meta.fabricmc.net/v2/versions', + json: 'https://meta.fabricmc.net/v2/versions/loader/${version}/${build}/profile/json' + }; + } else if (type === 'legacyfabric') { + return { + metaData: 'https://meta.legacyfabric.net/v2/versions', + json: 'https://meta.legacyfabric.net/v2/versions/loader/${version}/${build}/profile/json' + }; + } else if (type === 'quilt') { + return { + metaData: 'https://meta.quiltmc.org/v3/versions', + json: 'https://meta.quiltmc.org/v3/versions/loader/${version}/${build}/profile/json' + }; + } + // If none match, return undefined +} + +/** + * A list of potential Maven mirrors for downloading libraries. + */ +const mirrors = [ + 'https://maven.minecraftforge.net', + 'https://maven.neoforged.net/releases', + 'https://maven.creeperhost.net', + 'https://libraries.minecraft.net', + 'https://repo1.maven.org/maven2' +]; + +/** + * Reads a .jar or .zip file, returning specific entries or listing file entries in the archive. + * + * @param jar Full path to the jar/zip file + * @param file The file entry to extract data from (e.g., "install_profile.json"). If null, returns all entries or partial lists. + * @param prefix A path prefix filter (e.g., "maven/org/lwjgl/") if you want a list of matching files instead of direct extraction + * @returns A buffer or an array of { name, data }, or a list of filenames if prefix is given + */ +async function getFileFromArchive(jar: string, file: string | null = null, prefix: string | null = null, includeDirs: boolean = false): Promise { + const result: any[] = []; + const zip = new Unzipper(jar); + const entries = zip.getEntries(); + + return new Promise((resolve) => { + for (const entry of entries) { + if (includeDirs ? !prefix : (!entry.isDirectory && !prefix)) { + // If no prefix is given, either return a specific file if 'file' is set, + // or accumulate all entries if 'file' is null + if (entry.entryName === file) { + return resolve(entry.getData()); + } else if (!file) { + result.push({ name: entry.entryName, data: entry.getData(), isDirectory: entry.isDirectory }); + } + } + + // If a prefix is given, collect all entry names under that prefix + if (!entry.isDirectory && entry.entryName.includes(prefix)) { + result.push(entry.entryName); + } + } + + if (file && !prefix) { + // If a specific file was requested but not found, return undefined or empty + return resolve(undefined); + } + + // Otherwise, resolve the array of results + resolve(result); + }); +} + +/** + * Determines if a library should be skipped based on its 'rules' property. + * For example, it might skip libraries if action='disallow' for the current OS, + * or if there are specific conditions not met. + * + * @param lib A library object (with optional 'rules' array) + * @returns true if the library should be skipped, false otherwise + */ +function skipLibrary(lib: MinecraftLibrary): boolean { + // Map Node.js platform strings to Mojang's naming + const LibMap: Record = { + win32: 'windows', + darwin: 'osx', + linux: 'linux' + }; + + // If no rules, it's not skipped + if (!lib.rules) { + return false; + } + + let shouldSkip = true; + + for (const rule of lib.rules) { + // If features exist, your logic can handle them here + if (rule.features) { + // Implementation is up to your usage + continue; + } + + // "allow" means it can be used if OS matches (or no OS specified) + // "disallow" means skip if OS matches (or no OS specified) + if ( + rule.action === 'allow' && + ((rule.os && rule.os.name === LibMap[process.platform]) || !rule.os) + ) { + shouldSkip = false; + } else if ( + rule.action === 'disallow' && + ((rule.os && rule.os.name === LibMap[process.platform]) || !rule.os) + ) { + shouldSkip = true; + } + } + + return shouldSkip; +} + +function fromAnyReadable(webStream: ReadableStream): import('node:stream').Readable { + let NodeReadableStreamCtor: typeof ReadableStream | undefined; + if (!NodeReadableStreamCtor && typeof globalThis?.navigator === 'undefined') { + import('node:stream/web').then((mod) => { NodeReadableStreamCtor = mod.ReadableStream; }); + } + if (NodeReadableStreamCtor && webStream instanceof NodeReadableStreamCtor && typeof (Readable as any).fromWeb === 'function') { + return Readable.fromWeb(webStream as any); + } + + const nodeStream = new Readable({ read() { } }); + const reader = webStream.getReader(); + + (function pump() { + reader.read().then(({ done, value }) => { + if (done) return nodeStream.push(null); + nodeStream.push(Buffer.from(value)); + pump(); + }).catch(err => nodeStream.destroy(err)); + })(); + + return nodeStream; } -export { getPathLibraries, isold }; \ No newline at end of file +// Export all utility functions and constants +export { + getPathLibraries, + getFileHash, + isold, + loader, + mirrors, + getFileFromArchive, + skipLibrary, + fromAnyReadable +}; diff --git a/src/utils/unzipper.ts b/src/utils/unzipper.ts new file mode 100644 index 00000000..bba3ab3f --- /dev/null +++ b/src/utils/unzipper.ts @@ -0,0 +1,159 @@ +import fs from 'fs'; +import zlib from 'zlib'; + +interface ZipEntry { + entryName: string; + isDirectory: boolean; + getData: () => Buffer; +} + +export default class Unzipper { + private entries: ZipEntry[] = []; + + constructor(zipFilePath: string) { + const fileBuffer = fs.readFileSync(zipFilePath); + + const eocdSig = Buffer.from([0x50, 0x4B, 0x05, 0x06]); + const maxCommentLength = 0xFFFF; + const scanStart = Math.max(0, fileBuffer.length - (maxCommentLength + 22)); + + let eocdPos = -1; + for (let i = fileBuffer.length - 22; i >= scanStart; i--) { + if ( + fileBuffer[i] === 0x50 && + fileBuffer[i + 1] === 0x4B && + fileBuffer[i + 2] === 0x05 && + fileBuffer[i + 3] === 0x06 + ) { + eocdPos = i; + break; + } + } + + if (eocdPos !== -1) { + const cdOffset = fileBuffer.readUInt32LE(eocdPos + 16); + const cdSize = fileBuffer.readUInt32LE(eocdPos + 12); + const cdEnd = cdOffset + cdSize; + + let cdCursor = cdOffset; + + while (cdCursor < cdEnd) { + if (cdCursor + 46 > fileBuffer.length) break; // sécurité + + if (fileBuffer.readUInt32LE(cdCursor) !== 0x02014b50) break; + + const compressionMethod = fileBuffer.readUInt16LE(cdCursor + 10); + const compressedSize = fileBuffer.readUInt32LE(cdCursor + 20); + const uncompressedSize = fileBuffer.readUInt32LE(cdCursor + 24); + const fileNameLength = fileBuffer.readUInt16LE(cdCursor + 28); + const extraFieldLength = fileBuffer.readUInt16LE(cdCursor + 30); + const fileCommentLength = fileBuffer.readUInt16LE(cdCursor + 32); + const relativeOffset = fileBuffer.readUInt32LE(cdCursor + 42); + + const fileName = fileBuffer.toString( + 'utf-8', + cdCursor + 46, + cdCursor + 46 + fileNameLength + ); + + const headerOffset = relativeOffset; + // Sécurité sur l'offset du header + if (headerOffset + 30 > fileBuffer.length) { + cdCursor += 46 + fileNameLength + extraFieldLength + fileCommentLength; + continue; + } + if (fileBuffer.readUInt32LE(headerOffset) !== 0x04034b50) { + cdCursor += 46 + fileNameLength + extraFieldLength + fileCommentLength; + continue; + } + + const lfFileNameLength = fileBuffer.readUInt16LE(headerOffset + 26); + const lfExtraFieldLength = fileBuffer.readUInt16LE(headerOffset + 28); + const dataStart = headerOffset + 30 + lfFileNameLength + lfExtraFieldLength; + const dataEnd = dataStart + compressedSize; + + // Sécurité: ne pas dépasser la taille du buffer + if (dataEnd > fileBuffer.length) { + cdCursor += 46 + fileNameLength + extraFieldLength + fileCommentLength; + continue; + } + + const compressedData = fileBuffer.slice(dataStart, dataEnd); + + this.entries.push({ + entryName: fileName, + isDirectory: fileName.endsWith('/'), + getData: () => { + if (compressionMethod === 8) { + return zlib.inflateRawSync(compressedData); + } else if (compressionMethod === 0) { + return compressedData; + } else { + throw new Error(`Unsupported compression method: ${compressionMethod}`); + } + } + }); + + cdCursor += 46 + fileNameLength + extraFieldLength + fileCommentLength; + } + } else { + let currentOffset = 0; + while (currentOffset < fileBuffer.length - 4) { + const signaturePos = fileBuffer.indexOf( + Buffer.from([0x50, 0x4B, 0x03, 0x04]), + currentOffset + ); + if (signaturePos === -1) break; + + const headerOffset = signaturePos; + if (headerOffset + 30 > fileBuffer.length) break; + + const compressionMethod = fileBuffer.readUInt16LE(headerOffset + 8); + const compressedSize = fileBuffer.readUInt32LE(headerOffset + 18); + const uncompressedSize = fileBuffer.readUInt32LE(headerOffset + 22); + const fileNameLength = fileBuffer.readUInt16LE(headerOffset + 26); + const extraFieldLength = fileBuffer.readUInt16LE(headerOffset + 28); + + const fileNameStart = headerOffset + 30; + const fileNameEnd = fileNameStart + fileNameLength; + if (fileNameEnd > fileBuffer.length) break; + + const fileName = fileBuffer.toString( + 'utf-8', + fileNameStart, + fileNameEnd + ); + + const dataStart = fileNameEnd + extraFieldLength; + const dataEnd = dataStart + compressedSize; + + if (dataEnd > fileBuffer.length) { + currentOffset = dataEnd; + continue; + } + + const compressedData = fileBuffer.slice(dataStart, dataEnd); + + this.entries.push({ + entryName: fileName, + isDirectory: fileName.endsWith('/'), + getData: () => { + if (compressionMethod === 8) { + return zlib.inflateRawSync(compressedData); + } else if (compressionMethod === 0) { + return compressedData; + } else { + throw new Error(`Unsupported compression method: ${compressionMethod}`); + } + } + }); + + currentOffset = dataEnd; + } + } + } + + getEntries(): ZipEntry[] { + return this.entries; + } +} diff --git a/test/3D/index.html b/test/3D/index.html deleted file mode 100755 index ad267ef5..00000000 --- a/test/3D/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - My first three.js app - - - - - - - \ No newline at end of file diff --git a/test/3D/index.js b/test/3D/index.js deleted file mode 100755 index 724de854..00000000 --- a/test/3D/index.js +++ /dev/null @@ -1,24 +0,0 @@ -let skinUrl = 'http://textures.minecraft.net/texture/ac3de5b50fb6174da51032677ead046295486bf682b3ea73e0617a210c4b4f46' - -const scene = new THREE.Scene(); -const camera = new THREE.PerspectiveCamera(75, 1000 / 500, 0.1, 100); - -const renderer = new THREE.WebGLRenderer(); -renderer.setSize(1000, 500); -document.body.appendChild(renderer.domElement); - -const geometry = new THREE.BoxGeometry(1, 1, 1); -const material = new THREE.MeshBasicMaterial({ color: '#F1F1F1'}); -const cube = new THREE.Mesh(geometry, material); -scene.add(cube); - -camera.position.z = 2; - -function animate() { - requestAnimationFrame(animate); - cube.rotation.x += 0.01; - cube.rotation.y += 0.05; - renderer.render(scene, camera); -}; - -animate(); \ No newline at end of file diff --git a/test/AZauth.js b/test/AZauth.js index cd6445dc..4f3207b9 100755 --- a/test/AZauth.js +++ b/test/AZauth.js @@ -1,7 +1,7 @@ const prompt = require('prompt') const { AZauth, Launch } = require('../build/Index'); const launch = new Launch(); -const auth = new AZauth('http://craftdium.ml/test'); +const auth = new AZauth('https://nincraft.fr'); const fs = require('fs'); let mc @@ -47,9 +47,10 @@ async function main() { // url: 'https://luuxis.fr/api/user/893bbc-a0bc41-da8568-ef56dd-7f2df8/files', authenticator: mc, timeout: 10000, - path: './.Minecraft', - version: '1.19.3', + path: './Minecraft', + version: '1.16.5', detached: false, + intelEnabledMac: true, downloadFileMultiple: 10, loader: { diff --git a/test/index.js b/test/index.js index 84e123f6..ab4f47cc 100755 --- a/test/index.js +++ b/test/index.js @@ -1,109 +1,55 @@ -const { Microsoft, Launch, Mojang } = require('../build/Index'); -const launch = new Launch(); -const fs = require('fs'); +const { Launch, Microsoft } = require('minecraft-java-core'); +const launcher = new Launch(); -let client_id = '13f589e1-e2fc-443e-a68a-63b0092b8eeb' +const fs = require('fs'); let mc (async () => { if (!fs.existsSync('./account.json')) { - mc = await new Microsoft(client_id).getAuth(); + mc = await new Microsoft().getAuth(); fs.writeFileSync('./account.json', JSON.stringify(mc, null, 4)); } else { mc = JSON.parse(fs.readFileSync('./account.json')); if (!mc.refresh_token) { - mc = await new Microsoft(client_id).getAuth(); + mc = await new Microsoft().getAuth(); fs.writeFileSync('./account.json', JSON.stringify(mc, null, 4)); } else { - mc = await new Microsoft(client_id).refresh(mc); - if (mc.error) mc = await new Microsoft(client_id).getAuth(); + mc = await new Microsoft().refresh(mc); fs.writeFileSync('./account.json', JSON.stringify(mc, null, 4)); + if (mc.error) process.exit(1); } } - let opt = { - // url: 'http://craftdium.ml/launcherSelvania/files?instance=hypixel', + const opt = { + url: "https://luuxcraft.fr/api/user/48c74227-13d1-48d6-931b-0f12b73da340/instance", + path: './minecraft', authenticator: mc, - timeout: 10000, - path: './.Minecraft', - instance: 'Hypixel', - version: '1.20.1', - detached: false, - downloadFileMultiple: 30, + version: '1.8.9', + intelEnabledMac: true, + instance: "Hypixel", + + ignored: [ + "config", + "logs", + "resourcepacks", + "options.txt", + "optionsof.txt" + ], loader: { type: 'forge', build: 'latest', enable: true }, - - verify: false, - ignored: [ - 'config', - 'essential', - 'logs', - 'resourcepacks', - 'saves', - 'screenshots', - 'shaderpacks', - 'W-OVERFLOW', - 'options.txt', - 'optionsof.txt' - ], - JVM_ARGS: [], - GAME_ARGS: [], - - javaPath: null, - - screen: { - width: 1600, - height: 900 - }, - memory: { - min: '4G', - max: '6G' - } - } - - await launch.Launch(opt); - - launch.on('extract', extract => { - console.log(extract); - }); - - launch.on('progress', (progress, size, element) => { - console.log(`Downloading ${element} ${Math.round((progress / size) * 100)}%`); - }); - - launch.on('check', (progress, size, element) => { - console.log(`Checking ${element} ${Math.round((progress / size) * 100)}%`); - }); - - launch.on('estimated', (time) => { - let hours = Math.floor(time / 3600); - let minutes = Math.floor((time - hours * 3600) / 60); - let seconds = Math.floor(time - hours * 3600 - minutes * 60); - console.log(`${hours}h ${minutes}m ${seconds}s`); - }) - - launch.on('speed', (speed) => { - console.log(`${(speed / 1067008).toFixed(2)} Mb/s`) - }) - - launch.on('patch', patch => { - console.log(patch); - }); - - launch.on('data', (e) => { - console.log(e); - }) - - launch.on('close', code => { - console.log(code); - }); - - launch.on('error', err => { - console.log(err); - }); -})() + min: '14G', + max: '16G' + }, + }; + + launcher.Launch(opt); + launcher.on('progress', (progress, size) => console.log(`[DL] ${((progress / size) * 100).toFixed(2)}%`)); + launcher.on('patch', pacth => process.stdout.write(pacth)); + launcher.on('data', line => process.stdout.write(line)); + launcher.on('error', err => console.error(err)); +})(); diff --git a/test/offline.js b/test/offline.js new file mode 100755 index 00000000..5f6cac69 --- /dev/null +++ b/test/offline.js @@ -0,0 +1,26 @@ +const { Launch, Mojang } = require('minecraft-java-core'); +const launcher = new Launch(); +(async () => { + await launcher.Launch({ + path: './minecraft', + authenticator: await Mojang.login('Luuxis'), + version: '1.16.5', + intelEnabledMac: true, + bypassOffline: true, + loader: { + path: './', + type: 'fabric', + build: 'latest', + enable: true + }, + memory: { + min: '2G', + max: '4G' + } + }); + + launcher.on('progress', (progress, size) => console.log(`[DL] ${((progress / size) * 100).toFixed(2)}%`)) + .on('patch', pacth => process.stdout.write(pacth)) + .on('data', line => process.stdout.write(line)) + .on('close', () => console.log('Game exited.')); +})(); diff --git a/tsconfig.json b/tsconfig.json index 076ada6f..9b3e3ebd 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,11 +3,14 @@ "src/**/*" ], "compilerOptions": { - "sourceMap": false, + "sourceMap": true, "target": "ES2020", "module": "CommonJS", - "lib": ["ES2021"], - "declaration": true, + "lib": [ + "ES2021", + "DOM" + ], + "declaration": true, "outDir": "build", "esModuleInterop": true } diff --git a/webfiles/php/scandir.php b/webfiles/php/scandir.php index a26254cf..7312a3c3 100755 --- a/webfiles/php/scandir.php +++ b/webfiles/php/scandir.php @@ -22,7 +22,6 @@ function scanFolder($dir) { $filePath = $dir . '/' . $filename; if ($filename == "php") continue; if (is_dir($filePath)) $result[] = $filename; - } return $result; } @@ -37,7 +36,7 @@ function dirToArray($dir) { $url_req = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH); $url = "http://$_SERVER[HTTP_HOST]$url_req$dir/$path"; - $res[] = array("url" => $url, "size" => $size, "hash" => $hash, "path" => $path); + $res[] = array("url" => $url, "size" => $size, "hash" => $hash, "path" => $path); } return str_replace("\\", "", json_encode($res)); }