mirror of
https://github.com/artegoser/pimi-launcher-core.git
synced 2024-11-22 04:06:21 +03:00
doc: rename, formatting
This commit is contained in:
parent
a6cfdd3c8e
commit
dfa54d3f65
8 changed files with 4219 additions and 821 deletions
|
@ -4,9 +4,6 @@
|
|||
"commonjs": true,
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"standard"
|
||||
],
|
||||
"globals": {
|
||||
"Atomics": "readonly",
|
||||
"SharedArrayBuffer": "readonly"
|
||||
|
|
91
README.md
91
README.md
|
@ -1,15 +1,19 @@
|
|||
![logo](https://owo.whats-th.is/8mT5kxc.png)
|
||||
##### This project is complete for now.
|
||||
|
||||
##### This project is fork of [MCLC](https://github.com/Pierce01/MinecraftLauncher-core)
|
||||
|
||||
[![Build Status](https://travis-ci.com/Pierce01/MinecraftLauncher-core.svg?branch=master)](https://travis-ci.com/Pierce01/MinecraftLauncher-core)
|
||||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
|
||||
![version](https://img.shields.io/badge/stable_version-3.17.0-blue)
|
||||
![badge](https://img.shields.io/badge/ncurses-not_supported-purple)
|
||||
|
||||
MCLC (Minecraft Launcher Core) is a NodeJS solution for launching modded and vanilla Minecraft without having to download and format everything yourself.
|
||||
PiMi (Minecraft Launcher Core) is a NodeJS solution for launching modded and vanilla Minecraft without having to download and format everything yourself.
|
||||
Basically a core for your Electron or script based launchers.
|
||||
|
||||
### Getting support
|
||||
|
||||
Since people seem to use this, I've created a Discord server for anyone who needs to get in contact with me or get help!
|
||||
|
||||
<p>
|
||||
<a href="https://discord.gg/8uYVbXP">
|
||||
<img src="https://img.shields.io/discord/568550848871923723?logo=discord"
|
||||
|
@ -21,51 +25,53 @@ Since people seem to use this, I've created a Discord server for anyone who need
|
|||
`npm i minecraft-launcher-core`
|
||||
|
||||
### Standard Example
|
||||
|
||||
```javascript
|
||||
const { Client, Authenticator } = require('minecraft-launcher-core');
|
||||
const { Client, Authenticator } = require("minecraft-launcher-core");
|
||||
const launcher = new Client();
|
||||
|
||||
let opts = {
|
||||
// For production launchers, I recommend not passing
|
||||
// the getAuth function through the authorization field and instead
|
||||
// handling authentication outside before you initialize
|
||||
// MCLC so you can handle auth based errors and validation!
|
||||
// PiMi so you can handle auth based errors and validation!
|
||||
authorization: Authenticator.getAuth("username", "password"),
|
||||
root: "./minecraft",
|
||||
version: {
|
||||
number: "1.14",
|
||||
type: "release"
|
||||
type: "release",
|
||||
},
|
||||
memory: {
|
||||
max: "6G",
|
||||
min: "4G"
|
||||
}
|
||||
}
|
||||
min: "4G",
|
||||
},
|
||||
};
|
||||
|
||||
launcher.launch(opts);
|
||||
|
||||
launcher.on('debug', (e) => console.log(e));
|
||||
launcher.on('data', (e) => console.log(e));
|
||||
launcher.on("debug", (e) => console.log(e));
|
||||
launcher.on("data", (e) => console.log(e));
|
||||
```
|
||||
|
||||
### Documentation
|
||||
|
||||
#### Client Functions
|
||||
|
||||
| Function | Type | Description |
|
||||
|----------|---------|-----------------------------------------------------------------------------------------|
|
||||
| -------- | ------- | ------------------------------------------------------------------------------------------ |
|
||||
| `launch` | Promise | Launches the client with the specified `options` as a parameter. Returns child the process |
|
||||
|
||||
##### launch
|
||||
|
||||
| Parameter | Type | Description | Required |
|
||||
|--------------------------|----------|-------------------------------------------------------------------------------------------|----------|
|
||||
| `options.clientPackage` | String | Path or URL to a zip file, which will be extracted to the root directory. (Not recommended for production use)| False |
|
||||
| ------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------- | -------- |
|
||||
| `options.clientPackage` | String | Path or URL to a zip file, which will be extracted to the root directory. (Not recommended for production use) | False |
|
||||
| `options.removePackage` | Boolean | Option to remove the client package zip file after its finished extracting. | False |
|
||||
| `options.installer` | String | Path to installer being executed. | False |
|
||||
| `options.root` | String | Path where you want the launcher to work in. `C:/Users/user/AppData/Roaming/.mc` | True |
|
||||
| `options.cache` | String | Path where launcher files will be cached in. `C:/Users/user/AppData/Roaming/.mc/cache` | False |
|
||||
| `options.os` | String | windows, osx or linux. MCLC will auto determine the OS if this field isn't provided. | False |
|
||||
| `options.customLaunchArgs`| Array | Array of custom Minecraft arguments you want to add. | False |
|
||||
| `options.os` | String | windows, osx or linux. PiMi will auto determine the OS if this field isn't provided. | False |
|
||||
| `options.customLaunchArgs` | Array | Array of custom Minecraft arguments you want to add. | False |
|
||||
| `options.customArgs` | Array | Array of custom Java arguments you want to add. | False |
|
||||
| `options.features` | Array | Array of game argument feature flags. ex: `is_demo_user` or `has_custom_resolution` | False |
|
||||
| `options.version.number` | String | Minecraft version that is going to be launched. | True |
|
||||
|
@ -85,9 +91,11 @@ launcher.on('data', (e) => console.log(e));
|
|||
| `options.timeout` | Integer | Timeout on download requests. | False |
|
||||
| `options.window.width` | String | Width of the Minecraft Client. | False |
|
||||
| `options.window.height` | String | Height of the Minecraft Client. | False |
|
||||
| `options.window.fullscreen`| Boolean| Fullscreen the Minecraft Client. | False |
|
||||
| `options.window.fullscreen` | Boolean | Fullscreen the Minecraft Client. | False |
|
||||
| `options.overrides` | Object | Json object redefining paths for better customization. Example below. | False |
|
||||
#### IF YOU'RE NEW TO MCLC, LET IT HANDLE EVERYTHING! DO NOT USE OVERRIDES!
|
||||
|
||||
#### IF YOU'RE NEW TO PiMi, LET IT HANDLE EVERYTHING! DO NOT USE OVERRIDES!
|
||||
|
||||
```js
|
||||
let opts = {
|
||||
otherOps...,
|
||||
|
@ -115,7 +123,7 @@ let opts = {
|
|||
// in the version json.
|
||||
fallbackMaven: 'https://search.maven.org/remotecontent?filepath='
|
||||
},
|
||||
// The following is options for which version of ForgeWrapper MCLC uses. This allows us to launch modern Forge.
|
||||
// The following is options for which version of ForgeWrapper PiMi uses. This allows us to launch modern Forge.
|
||||
fw: {
|
||||
baseUrl: 'https://github.com/ZekerZhayard/ForgeWrapper/releases/download/',
|
||||
version: '1.5.1',
|
||||
|
@ -128,12 +136,19 @@ let opts = {
|
|||
```
|
||||
|
||||
#### Notes
|
||||
|
||||
##### Custom
|
||||
If you are loading up a client outside of vanilla Minecraft or Forge (Optifine and for an example), you'll need to download the needed files yourself if you don't provide downloads url downloads like Forge and Fabric. If no version jar is specified, MCLC will default back to the normal MC jar so mods like Fabric work.
|
||||
|
||||
If you are loading up a client outside of vanilla Minecraft or Forge (Optifine and for an example), you'll need to download the needed files yourself if you don't provide downloads url downloads like Forge and Fabric. If no version jar is specified, PiMi will default back to the normal MC jar so mods like Fabric work.
|
||||
|
||||
##### Installer
|
||||
|
||||
This runs an executable with specified launch arguments. Was used to support Forge 1.13 before ForgeWrapper.
|
||||
|
||||
##### Authentication
|
||||
MCLC's authenticator module does not support Microsoft authentication. You will need to use a library like [MSMC](https://github.com/Hanro50/MSMC). If you want to create your own solution, the following is the authorization JSON object format.
|
||||
|
||||
PiMi's authenticator module does not support Microsoft authentication. You will need to use a library like [MSMC](https://github.com/Hanro50/MSMC). If you want to create your own solution, the following is the authorization JSON object format.
|
||||
|
||||
```js
|
||||
{
|
||||
access_token: '',
|
||||
|
@ -156,49 +171,49 @@ MCLC's authenticator module does not support Microsoft authentication. You will
|
|||
##### getAuth
|
||||
|
||||
| Parameter | Type | Description | Required |
|
||||
|-----------|--------|--------------------------------------------------------------|----------|
|
||||
| `username`| String | Email or username | True |
|
||||
| `password`| String | Password for the Mojang account being used if online mode. | False |
|
||||
| `client_token`| String | Client token that will be used. If one is not specified, one will be generated | False |
|
||||
| -------------- | ------ | ------------------------------------------------------------------------------ | -------- |
|
||||
| `username` | String | Email or username | True |
|
||||
| `password` | String | Password for the Mojang account being used if online mode. | False |
|
||||
| `client_token` | String | Client token that will be used. If one is not specified, one will be generated | False |
|
||||
|
||||
##### validate
|
||||
|
||||
| Parameter | Type | Description | Required |
|
||||
|--------------|--------|-------------------------------------------------------------------|----------|
|
||||
| -------------- | ------ | -------------------------------------------------------------------------------- | -------- |
|
||||
| `access_token` | String | Token being checked if it can be used to login with (online mode). | True |
|
||||
| `client_token` | String | Client token being checked to see if there was a change of client (online mode). | True |
|
||||
|
||||
##### refreshAuth
|
||||
|
||||
| Parameter | Type | Description | Required |
|
||||
|--------------------|--------|-------------------------------------------------------------------------------------|----------|
|
||||
| -------------- | ------ | ----------------------------------------------------------------------------------- | -------- |
|
||||
| `access_token` | String | Token being checked if it can be used to login with (online mode). | True |
|
||||
| `client_token` | String | Token being checked if it's the same client that the access_token was created from. | True |
|
||||
|
||||
##### invalidate
|
||||
|
||||
| Parameter | Type | Description | Required |
|
||||
|--------------|--------|-------------------------------------------------------------------|----------|
|
||||
| -------------- | ------ | ----------------------------------------------------------------------------------- | -------- |
|
||||
| `access_token` | String | Token being checked if it can be used to login with (online mode). | True |
|
||||
| `client_token` | String | Token being checked if it's the same client that the access_token was created from. | True |
|
||||
|
||||
##### signOut
|
||||
|
||||
| Parameter | Type | Description | Required |
|
||||
|--------------|--------|--------------------------------------|----------|
|
||||
| ---------- | ------ | --------------------------- | -------- |
|
||||
| `username` | String | Username used to login with | True |
|
||||
| `password` | String | Password used to login with | True |
|
||||
|
||||
##### changeApiUrl
|
||||
|
||||
| Parameter | Type | Description | Required |
|
||||
|-----------|--------|--------------------------------------------------------------|----------|
|
||||
| `url` | String | New URL that MCLC will make calls to authenticate the login. | True |
|
||||
| --------- | ------ | ------------------------------------------------------------ | -------- |
|
||||
| `url` | String | New URL that PiMi will make calls to authenticate the login. | True |
|
||||
|
||||
#### Events
|
||||
|
||||
| Event Name | Type | Description |
|
||||
|-------------------|---------|---------------------------------------------------------------------------------------|
|
||||
| ----------------- | ------- | ----------------------------------------------------------------------------------- |
|
||||
| `arguments` | Object | Emitted when launch arguments are set for the Minecraft Jar. |
|
||||
| `data` | String | Emitted when information is returned from the Minecraft Process |
|
||||
| `close` | Integer | Code number that is returned by the Minecraft Process |
|
||||
|
@ -208,15 +223,17 @@ MCLC's authenticator module does not support Microsoft authentication. You will
|
|||
| `debug` | String | Emitted when functions occur, made to help debug if errors occur |
|
||||
| `progress` | Object | Emitted when files are being downloaded in order. (Assets, Forge, Natives, Classes) |
|
||||
|
||||
|
||||
#### What should it look like running from console?
|
||||
|
||||
The `pid` is printed in console after the process is launched.
|
||||
![gif](https://owo.whats-th.is/3N3PMC4.gif)
|
||||
|
||||
## Contributors
|
||||
|
||||
These are the people that helped out that aren't listed [here](https://github.com/Pierce01/MinecraftLauncher-core/graphs/contributors)!
|
||||
* [Pyker](https://github.com/Pyker) - Forge dependency parsing.
|
||||
* [Khionu](https://github.com/khionu) - Research on how Minecraft's`natives` are handled.
|
||||
* [Coding-Kiwi](https://github.com/Coding-Kiwi) - Pointed out I didn't pass `clientToken` in initial authentication function.
|
||||
* maxbsoft - Pointed out that a certain JVM option causes OSX Minecraft to bug out.
|
||||
* [Noé](https://github.com/NoXeDev) - Pointed out launch args weren't being passed for Forge 1.13+.
|
||||
|
||||
- [Pyker](https://github.com/Pyker) - Forge dependency parsing.
|
||||
- [Khionu](https://github.com/khionu) - Research on how Minecraft's`natives` are handled.
|
||||
- [Coding-Kiwi](https://github.com/Coding-Kiwi) - Pointed out I didn't pass `clientToken` in initial authentication function.
|
||||
- maxbsoft - Pointed out that a certain JVM option causes OSX Minecraft to bug out.
|
||||
- [Noé](https://github.com/NoXeDev) - Pointed out launch args weren't being passed for Forge 1.13+.
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
const request = require('request')
|
||||
const { v3 } = require('uuid')
|
||||
const request = require("request");
|
||||
const { v3 } = require("uuid");
|
||||
|
||||
let uuid
|
||||
let api_url = 'https://authserver.mojang.com'
|
||||
let uuid;
|
||||
let api_url = "https://authserver.mojang.com";
|
||||
|
||||
module.exports.getAuth = function (username, password, client_token = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getUUID(username)
|
||||
getUUID(username);
|
||||
if (!password) {
|
||||
const user = {
|
||||
access_token: uuid,
|
||||
client_token: client_token || uuid,
|
||||
uuid,
|
||||
name: username,
|
||||
user_properties: '{}'
|
||||
}
|
||||
user_properties: "{}",
|
||||
};
|
||||
|
||||
return resolve(user)
|
||||
return resolve(user);
|
||||
}
|
||||
|
||||
const requestObject = {
|
||||
url: api_url + '/authenticate',
|
||||
url: api_url + "/authenticate",
|
||||
json: {
|
||||
agent: {
|
||||
name: 'Minecraft',
|
||||
version: 1
|
||||
name: "Minecraft",
|
||||
version: 1,
|
||||
},
|
||||
username,
|
||||
password,
|
||||
clientToken: uuid,
|
||||
requestUser: true
|
||||
}
|
||||
}
|
||||
requestUser: true,
|
||||
},
|
||||
};
|
||||
|
||||
request.post(requestObject, function (error, response, body) {
|
||||
if (error) return reject(error)
|
||||
if (error) return reject(error);
|
||||
if (!body || !body.selectedProfile) {
|
||||
return reject(new Error('Validation error: ' + response.statusMessage))
|
||||
return reject(new Error("Validation error: " + response.statusMessage));
|
||||
}
|
||||
|
||||
const userProfile = {
|
||||
|
@ -45,48 +45,48 @@ module.exports.getAuth = function (username, password, client_token = null) {
|
|||
uuid: body.selectedProfile.id,
|
||||
name: body.selectedProfile.name,
|
||||
selected_profile: body.selectedProfile,
|
||||
user_properties: parsePropts(body.user.properties)
|
||||
}
|
||||
user_properties: parsePropts(body.user.properties),
|
||||
};
|
||||
|
||||
resolve(userProfile)
|
||||
})
|
||||
})
|
||||
}
|
||||
resolve(userProfile);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.validate = function (accessToken, clientToken) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestObject = {
|
||||
url: api_url + '/validate',
|
||||
url: api_url + "/validate",
|
||||
json: {
|
||||
accessToken,
|
||||
clientToken
|
||||
}
|
||||
}
|
||||
clientToken,
|
||||
},
|
||||
};
|
||||
|
||||
request.post(requestObject, async function (error, response, body) {
|
||||
if (error) return reject(error)
|
||||
if (error) return reject(error);
|
||||
|
||||
if (!body) resolve(true)
|
||||
else reject(body)
|
||||
})
|
||||
})
|
||||
}
|
||||
if (!body) resolve(true);
|
||||
else reject(body);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.refreshAuth = function (accessToken, clientToken) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestObject = {
|
||||
url: api_url + '/refresh',
|
||||
url: api_url + "/refresh",
|
||||
json: {
|
||||
accessToken,
|
||||
clientToken,
|
||||
requestUser: true
|
||||
}
|
||||
}
|
||||
requestUser: true,
|
||||
},
|
||||
};
|
||||
|
||||
request.post(requestObject, function (error, response, body) {
|
||||
if (error) return reject(error)
|
||||
if (error) return reject(error);
|
||||
if (!body || !body.selectedProfile) {
|
||||
return reject(new Error('Validation error: ' + response.statusMessage))
|
||||
return reject(new Error("Validation error: " + response.statusMessage));
|
||||
}
|
||||
|
||||
const userProfile = {
|
||||
|
@ -94,75 +94,75 @@ module.exports.refreshAuth = function (accessToken, clientToken) {
|
|||
client_token: getUUID(body.selectedProfile.name),
|
||||
uuid: body.selectedProfile.id,
|
||||
name: body.selectedProfile.name,
|
||||
user_properties: parsePropts(body.user.properties)
|
||||
}
|
||||
user_properties: parsePropts(body.user.properties),
|
||||
};
|
||||
|
||||
return resolve(userProfile)
|
||||
})
|
||||
})
|
||||
}
|
||||
return resolve(userProfile);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.invalidate = function (accessToken, clientToken) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestObject = {
|
||||
url: api_url + '/invalidate',
|
||||
url: api_url + "/invalidate",
|
||||
json: {
|
||||
accessToken,
|
||||
clientToken
|
||||
}
|
||||
}
|
||||
clientToken,
|
||||
},
|
||||
};
|
||||
|
||||
request.post(requestObject, function (error, response, body) {
|
||||
if (error) return reject(error)
|
||||
if (error) return reject(error);
|
||||
|
||||
if (!body) return resolve(true)
|
||||
else return reject(body)
|
||||
})
|
||||
})
|
||||
}
|
||||
if (!body) return resolve(true);
|
||||
else return reject(body);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.signOut = function (username, password) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestObject = {
|
||||
url: api_url + '/signout',
|
||||
url: api_url + "/signout",
|
||||
json: {
|
||||
username,
|
||||
password
|
||||
}
|
||||
}
|
||||
password,
|
||||
},
|
||||
};
|
||||
|
||||
request.post(requestObject, function (error, response, body) {
|
||||
if (error) return reject(error)
|
||||
if (error) return reject(error);
|
||||
|
||||
if (!body) return resolve(true)
|
||||
else return reject(body)
|
||||
})
|
||||
})
|
||||
}
|
||||
if (!body) return resolve(true);
|
||||
else return reject(body);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.changeApiUrl = function (url) {
|
||||
api_url = url
|
||||
}
|
||||
api_url = url;
|
||||
};
|
||||
|
||||
function parsePropts (array) {
|
||||
function parsePropts(array) {
|
||||
if (array) {
|
||||
const newObj = {}
|
||||
const newObj = {};
|
||||
for (const entry of array) {
|
||||
if (newObj[entry.name]) {
|
||||
newObj[entry.name].push(entry.value)
|
||||
newObj[entry.name].push(entry.value);
|
||||
} else {
|
||||
newObj[entry.name] = [entry.value]
|
||||
newObj[entry.name] = [entry.value];
|
||||
}
|
||||
}
|
||||
return JSON.stringify(newObj)
|
||||
return JSON.stringify(newObj);
|
||||
} else {
|
||||
return '{}'
|
||||
return "{}";
|
||||
}
|
||||
}
|
||||
|
||||
function getUUID (value) {
|
||||
function getUUID(value) {
|
||||
if (!uuid) {
|
||||
uuid = v3(value, v3.DNS)
|
||||
uuid = v3(value, v3.DNS);
|
||||
}
|
||||
return uuid
|
||||
return uuid;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,204 +1,304 @@
|
|||
const child = require('child_process')
|
||||
const path = require('path')
|
||||
const Handler = require('./handler')
|
||||
const fs = require('fs')
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const child = require("child_process");
|
||||
const path = require("path");
|
||||
const Handler = require("./handler");
|
||||
const fs = require("fs");
|
||||
const EventEmitter = require("events").EventEmitter;
|
||||
|
||||
class MCLCore extends EventEmitter {
|
||||
async launch (options) {
|
||||
class PiMiCore extends EventEmitter {
|
||||
async launch(options) {
|
||||
try {
|
||||
this.options = { ...options }
|
||||
this.options.root = path.resolve(this.options.root)
|
||||
this.options = { ...options };
|
||||
this.options.root = path.resolve(this.options.root);
|
||||
this.options.overrides = {
|
||||
detached: true,
|
||||
...this.options.overrides,
|
||||
url: {
|
||||
meta: 'https://launchermeta.mojang.com',
|
||||
resource: 'https://resources.download.minecraft.net',
|
||||
mavenForge: 'http://files.minecraftforge.net/maven/',
|
||||
defaultRepoForge: 'https://libraries.minecraft.net/',
|
||||
fallbackMaven: 'https://search.maven.org/remotecontent?filepath=',
|
||||
...this.options.overrides
|
||||
? this.options.overrides.url
|
||||
: undefined
|
||||
meta: "https://launchermeta.mojang.com",
|
||||
resource: "https://resources.download.minecraft.net",
|
||||
mavenForge: "http://files.minecraftforge.net/maven/",
|
||||
defaultRepoForge: "https://libraries.minecraft.net/",
|
||||
fallbackMaven: "https://search.maven.org/remotecontent?filepath=",
|
||||
...(this.options.overrides ? this.options.overrides.url : undefined),
|
||||
},
|
||||
fw: {
|
||||
baseUrl: 'https://github.com/ZekerZhayard/ForgeWrapper/releases/download/',
|
||||
version: '1.5.5',
|
||||
sh1: '566dfd60aacffaa02884614835f1151d36f1f985',
|
||||
baseUrl:
|
||||
"https://github.com/ZekerZhayard/ForgeWrapper/releases/download/",
|
||||
version: "1.5.5",
|
||||
sh1: "566dfd60aacffaa02884614835f1151d36f1f985",
|
||||
size: 34331,
|
||||
...this.options.overrides
|
||||
? this.options.overrides.fw
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
...(this.options.overrides ? this.options.overrides.fw : undefined),
|
||||
},
|
||||
};
|
||||
|
||||
this.handler = new Handler(this)
|
||||
this.handler = new Handler(this);
|
||||
|
||||
this._printVersion()
|
||||
this._printVersion();
|
||||
|
||||
const java = await this.handler.checkJava(this.options.javaPath || 'java')
|
||||
const java = await this.handler.checkJava(
|
||||
this.options.javaPath || "java"
|
||||
);
|
||||
if (!java.run) {
|
||||
this.emit('debug', `[MCLC]: Couldn't start Minecraft due to: ${java.message}`)
|
||||
this.emit('close', 1)
|
||||
return null
|
||||
this.emit(
|
||||
"debug",
|
||||
`[PiMi]: Couldn't start Minecraft due to: ${java.message}`
|
||||
);
|
||||
this.emit("close", 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
this._createRootDirectory()
|
||||
this._createGameDirectory()
|
||||
this._createRootDirectory();
|
||||
this._createGameDirectory();
|
||||
|
||||
await this._extractPackage()
|
||||
await this._extractPackage();
|
||||
|
||||
if (this.options.installer) {
|
||||
// So installers that create a profile in launcher_profiles.json can run without breaking.
|
||||
const profilePath = path.join(this.options.root, 'launcher_profiles.json')
|
||||
if (!fs.existsSync(profilePath) || !JSON.parse(fs.readFileSync(profilePath)).profiles) {
|
||||
fs.writeFileSync(profilePath, JSON.stringify({ profiles: {} }, null, 4))
|
||||
const profilePath = path.join(
|
||||
this.options.root,
|
||||
"launcher_profiles.json"
|
||||
);
|
||||
if (
|
||||
!fs.existsSync(profilePath) ||
|
||||
!JSON.parse(fs.readFileSync(profilePath)).profiles
|
||||
) {
|
||||
fs.writeFileSync(
|
||||
profilePath,
|
||||
JSON.stringify({ profiles: {} }, null, 4)
|
||||
);
|
||||
}
|
||||
const code = await this.handler.runInstaller(this.options.installer)
|
||||
const code = await this.handler.runInstaller(this.options.installer);
|
||||
if (!this.options.version.custom && code === 0) {
|
||||
this.emit('debug', '[MCLC]: Installer successfully ran, but no custom version was provided')
|
||||
this.emit(
|
||||
"debug",
|
||||
"[PiMi]: Installer successfully ran, but no custom version was provided"
|
||||
);
|
||||
}
|
||||
this.emit('debug', `[MCLC]: Installer closed with code ${code}`)
|
||||
this.emit("debug", `[PiMi]: Installer closed with code ${code}`);
|
||||
}
|
||||
|
||||
const directory = this.options.overrides.directory || path.join(this.options.root, 'versions', this.options.version.custom ? this.options.version.custom : this.options.version.number)
|
||||
this.options.directory = directory
|
||||
const directory =
|
||||
this.options.overrides.directory ||
|
||||
path.join(
|
||||
this.options.root,
|
||||
"versions",
|
||||
this.options.version.custom
|
||||
? this.options.version.custom
|
||||
: this.options.version.number
|
||||
);
|
||||
this.options.directory = directory;
|
||||
|
||||
const versionFile = await this.handler.getVersion()
|
||||
const mcPath = this.options.overrides.minecraftJar || (this.options.version.custom
|
||||
? path.join(this.options.root, 'versions', this.options.version.custom, `${this.options.version.custom}.jar`)
|
||||
: path.join(directory, `${this.options.version.number}.jar`))
|
||||
this.options.mcPath = mcPath
|
||||
const nativePath = await this.handler.getNatives()
|
||||
const versionFile = await this.handler.getVersion();
|
||||
const mcPath =
|
||||
this.options.overrides.minecraftJar ||
|
||||
(this.options.version.custom
|
||||
? path.join(
|
||||
this.options.root,
|
||||
"versions",
|
||||
this.options.version.custom,
|
||||
`${this.options.version.custom}.jar`
|
||||
)
|
||||
: path.join(directory, `${this.options.version.number}.jar`));
|
||||
this.options.mcPath = mcPath;
|
||||
const nativePath = await this.handler.getNatives();
|
||||
|
||||
if (!fs.existsSync(mcPath)) {
|
||||
this.emit('debug', '[MCLC]: Attempting to download Minecraft version jar')
|
||||
await this.handler.getJar()
|
||||
this.emit(
|
||||
"debug",
|
||||
"[PiMi]: Attempting to download Minecraft version jar"
|
||||
);
|
||||
await this.handler.getJar();
|
||||
}
|
||||
|
||||
const modifyJson = await this._getModifyJson()
|
||||
const modifyJson = await this._getModifyJson();
|
||||
|
||||
const args = []
|
||||
const args = [];
|
||||
|
||||
let jvm = [
|
||||
'-XX:-UseAdaptiveSizePolicy',
|
||||
'-XX:-OmitStackTraceInFastThrow',
|
||||
'-Dfml.ignorePatchDiscrepancies=true',
|
||||
'-Dfml.ignoreInvalidMinecraftCertificates=true',
|
||||
"-XX:-UseAdaptiveSizePolicy",
|
||||
"-XX:-OmitStackTraceInFastThrow",
|
||||
"-Dfml.ignorePatchDiscrepancies=true",
|
||||
"-Dfml.ignoreInvalidMinecraftCertificates=true",
|
||||
`-Djava.library.path=${nativePath}`,
|
||||
`-Xmx${this.handler.getMemory()[0]}`,
|
||||
`-Xms${this.handler.getMemory()[1]}`
|
||||
]
|
||||
if (this.handler.getOS() === 'osx') {
|
||||
if (parseInt(versionFile.id.split('.')[1]) > 12) jvm.push(await this.handler.getJVM())
|
||||
} else jvm.push(await this.handler.getJVM())
|
||||
`-Xms${this.handler.getMemory()[1]}`,
|
||||
];
|
||||
if (this.handler.getOS() === "osx") {
|
||||
if (parseInt(versionFile.id.split(".")[1]) > 12)
|
||||
jvm.push(await this.handler.getJVM());
|
||||
} else jvm.push(await this.handler.getJVM());
|
||||
|
||||
if (this.options.customArgs) jvm = jvm.concat(this.options.customArgs)
|
||||
if (this.options.customArgs) jvm = jvm.concat(this.options.customArgs);
|
||||
if (this.options.overrides.logj4ConfigurationFile) {
|
||||
jvm.push(`-Dlog4j.configurationFile=${path.resolve(this.options.overrides.logj4ConfigurationFile)}`)
|
||||
jvm.push(
|
||||
`-Dlog4j.configurationFile=${path.resolve(
|
||||
this.options.overrides.logj4ConfigurationFile
|
||||
)}`
|
||||
);
|
||||
}
|
||||
// https://help.minecraft.net/hc/en-us/articles/4416199399693-Security-Vulnerability-in-Minecraft-Java-Edition
|
||||
if (parseInt(versionFile.id.split('.')[1]) === 17) jvm.push('-Dlog4j2.formatMsgNoLookups=true')
|
||||
if (parseInt(versionFile.id.split('.')[1]) < 17) {
|
||||
if (!jvm.find(arg => arg.includes('Dlog4j.configurationFile'))) {
|
||||
const configPath = path.resolve(this.options.overrides.cwd || this.options.root)
|
||||
const intVersion = parseInt(versionFile.id.split('.')[1])
|
||||
if (parseInt(versionFile.id.split(".")[1]) === 17)
|
||||
jvm.push("-Dlog4j2.formatMsgNoLookups=true");
|
||||
if (parseInt(versionFile.id.split(".")[1]) < 17) {
|
||||
if (!jvm.find((arg) => arg.includes("Dlog4j.configurationFile"))) {
|
||||
const configPath = path.resolve(
|
||||
this.options.overrides.cwd || this.options.root
|
||||
);
|
||||
const intVersion = parseInt(versionFile.id.split(".")[1]);
|
||||
if (intVersion >= 12) {
|
||||
await this.handler.downloadAsync('https://launcher.mojang.com/v1/objects/02937d122c86ce73319ef9975b58896fc1b491d1/log4j2_112-116.xml',
|
||||
configPath, 'log4j2_112-116.xml', true, 'log4j')
|
||||
jvm.push('-Dlog4j.configurationFile=log4j2_112-116.xml')
|
||||
await this.handler.downloadAsync(
|
||||
"https://launcher.mojang.com/v1/objects/02937d122c86ce73319ef9975b58896fc1b491d1/log4j2_112-116.xml",
|
||||
configPath,
|
||||
"log4j2_112-116.xml",
|
||||
true,
|
||||
"log4j"
|
||||
);
|
||||
jvm.push("-Dlog4j.configurationFile=log4j2_112-116.xml");
|
||||
} else if (intVersion >= 7) {
|
||||
await this.handler.downloadAsync('https://launcher.mojang.com/v1/objects/dd2b723346a8dcd48e7f4d245f6bf09e98db9696/log4j2_17-111.xml',
|
||||
configPath, 'log4j2_17-111.xml', true, 'log4j')
|
||||
jvm.push('-Dlog4j.configurationFile=log4j2_17-111.xml')
|
||||
await this.handler.downloadAsync(
|
||||
"https://launcher.mojang.com/v1/objects/dd2b723346a8dcd48e7f4d245f6bf09e98db9696/log4j2_17-111.xml",
|
||||
configPath,
|
||||
"log4j2_17-111.xml",
|
||||
true,
|
||||
"log4j"
|
||||
);
|
||||
jvm.push("-Dlog4j.configurationFile=log4j2_17-111.xml");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const classes = this.options.overrides.classes || this.handler.cleanUp(await this.handler.getClasses(modifyJson))
|
||||
const classPaths = ['-cp']
|
||||
const separator = this.handler.getOS() === 'windows' ? ';' : ':'
|
||||
this.emit('debug', `[MCLC]: Using ${separator} to separate class paths`)
|
||||
const classes =
|
||||
this.options.overrides.classes ||
|
||||
this.handler.cleanUp(await this.handler.getClasses(modifyJson));
|
||||
const classPaths = ["-cp"];
|
||||
const separator = this.handler.getOS() === "windows" ? ";" : ":";
|
||||
this.emit("debug", `[PiMi]: Using ${separator} to separate class paths`);
|
||||
// Handling launch arguments.
|
||||
const file = modifyJson || versionFile
|
||||
const file = modifyJson || versionFile;
|
||||
// So mods like fabric work.
|
||||
const jar = fs.existsSync(mcPath)
|
||||
? `${separator}${mcPath}`
|
||||
: `${separator}${path.join(directory, `${this.options.version.number}.jar`)}`
|
||||
classPaths.push(`${this.options.forge ? this.options.forge + separator : ''}${classes.join(separator)}${jar}`)
|
||||
classPaths.push(file.mainClass)
|
||||
: `${separator}${path.join(
|
||||
directory,
|
||||
`${this.options.version.number}.jar`
|
||||
)}`;
|
||||
classPaths.push(
|
||||
`${
|
||||
this.options.forge ? this.options.forge + separator : ""
|
||||
}${classes.join(separator)}${jar}`
|
||||
);
|
||||
classPaths.push(file.mainClass);
|
||||
|
||||
this.emit('debug', '[MCLC]: Attempting to download assets')
|
||||
await this.handler.getAssets()
|
||||
this.emit("debug", "[PiMi]: Attempting to download assets");
|
||||
await this.handler.getAssets();
|
||||
|
||||
// Forge -> Custom -> Vanilla
|
||||
const launchOptions = await this.handler.getLaunchOptions(modifyJson)
|
||||
const launchOptions = await this.handler.getLaunchOptions(modifyJson);
|
||||
|
||||
const launchArguments = args.concat(jvm, classPaths, launchOptions)
|
||||
this.emit('arguments', launchArguments)
|
||||
this.emit('debug', `[MCLC]: Launching with arguments ${launchArguments.join(' ')}`)
|
||||
const launchArguments = args.concat(jvm, classPaths, launchOptions);
|
||||
this.emit("arguments", launchArguments);
|
||||
this.emit(
|
||||
"debug",
|
||||
`[PiMi]: Launching with arguments ${launchArguments.join(" ")}`
|
||||
);
|
||||
|
||||
return this.startMinecraft(launchArguments)
|
||||
return this.startMinecraft(launchArguments);
|
||||
} catch (e) {
|
||||
this.emit('debug', `[MCLC]: Failed to start due to ${e}, closing...`)
|
||||
return null
|
||||
this.emit("debug", `[PiMi]: Failed to start due to ${e}, closing...`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
_printVersion () {
|
||||
if (fs.existsSync(path.join(__dirname, '..', 'package.json'))) {
|
||||
const { version } = require('../package.json')
|
||||
this.emit('debug', `[MCLC]: MCLC version ${version}`)
|
||||
} else { this.emit('debug', '[MCLC]: Package JSON not found, skipping MCLC version check.') }
|
||||
_printVersion() {
|
||||
if (fs.existsSync(path.join(__dirname, "..", "package.json"))) {
|
||||
const { version } = require("../package.json");
|
||||
this.emit("debug", `[PiMi]: PiMi version ${version}`);
|
||||
} else {
|
||||
this.emit(
|
||||
"debug",
|
||||
"[PiMi]: Package JSON not found, skipping PiMi version check."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_createRootDirectory () {
|
||||
_createRootDirectory() {
|
||||
if (!fs.existsSync(this.options.root)) {
|
||||
this.emit('debug', '[MCLC]: Attempting to create root folder')
|
||||
fs.mkdirSync(this.options.root)
|
||||
this.emit("debug", "[PiMi]: Attempting to create root folder");
|
||||
fs.mkdirSync(this.options.root);
|
||||
}
|
||||
}
|
||||
|
||||
_createGameDirectory () {
|
||||
_createGameDirectory() {
|
||||
if (this.options.overrides.gameDirectory) {
|
||||
this.options.overrides.gameDirectory = path.resolve(this.options.overrides.gameDirectory)
|
||||
this.options.overrides.gameDirectory = path.resolve(
|
||||
this.options.overrides.gameDirectory
|
||||
);
|
||||
if (!fs.existsSync(this.options.overrides.gameDirectory)) {
|
||||
fs.mkdirSync(this.options.overrides.gameDirectory, { recursive: true })
|
||||
fs.mkdirSync(this.options.overrides.gameDirectory, { recursive: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async _extractPackage () {
|
||||
async _extractPackage() {
|
||||
if (this.options.clientPackage) {
|
||||
this.emit('debug', `[MCLC]: Extracting client package to ${this.options.root}`)
|
||||
await this.handler.extractPackage()
|
||||
this.emit(
|
||||
"debug",
|
||||
`[PiMi]: Extracting client package to ${this.options.root}`
|
||||
);
|
||||
await this.handler.extractPackage();
|
||||
}
|
||||
}
|
||||
|
||||
async _getModifyJson () {
|
||||
let modifyJson = null
|
||||
async _getModifyJson() {
|
||||
let modifyJson = null;
|
||||
|
||||
if (this.options.forge) {
|
||||
this.options.forge = path.resolve(this.options.forge)
|
||||
this.emit('debug', '[MCLC]: Detected Forge in options, getting dependencies')
|
||||
modifyJson = await this.handler.getForgedWrapped()
|
||||
this.options.forge = path.resolve(this.options.forge);
|
||||
this.emit(
|
||||
"debug",
|
||||
"[PiMi]: Detected Forge in options, getting dependencies"
|
||||
);
|
||||
modifyJson = await this.handler.getForgedWrapped();
|
||||
} else if (this.options.version.custom) {
|
||||
this.emit('debug', '[MCLC]: Detected custom in options, setting custom version file')
|
||||
modifyJson = modifyJson || JSON.parse(fs.readFileSync(path.join(this.options.root, 'versions', this.options.version.custom, `${this.options.version.custom}.json`), { encoding: 'utf8' }))
|
||||
this.emit(
|
||||
"debug",
|
||||
"[PiMi]: Detected custom in options, setting custom version file"
|
||||
);
|
||||
modifyJson =
|
||||
modifyJson ||
|
||||
JSON.parse(
|
||||
fs.readFileSync(
|
||||
path.join(
|
||||
this.options.root,
|
||||
"versions",
|
||||
this.options.version.custom,
|
||||
`${this.options.version.custom}.json`
|
||||
),
|
||||
{ encoding: "utf8" }
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return modifyJson
|
||||
return modifyJson;
|
||||
}
|
||||
|
||||
startMinecraft (launchArguments) {
|
||||
const minecraft = child.spawn(this.options.javaPath ? this.options.javaPath : 'java', launchArguments,
|
||||
{ cwd: this.options.overrides.cwd || this.options.root, detached: this.options.overrides.detached })
|
||||
minecraft.stdout.on('data', (data) => this.emit('data', data.toString('utf-8')))
|
||||
minecraft.stderr.on('data', (data) => this.emit('data', data.toString('utf-8')))
|
||||
minecraft.on('close', (code) => this.emit('close', code))
|
||||
return minecraft
|
||||
startMinecraft(launchArguments) {
|
||||
const minecraft = child.spawn(
|
||||
this.options.javaPath ? this.options.javaPath : "java",
|
||||
launchArguments,
|
||||
{
|
||||
cwd: this.options.overrides.cwd || this.options.root,
|
||||
detached: this.options.overrides.detached,
|
||||
}
|
||||
);
|
||||
minecraft.stdout.on("data", (data) =>
|
||||
this.emit("data", data.toString("utf-8"))
|
||||
);
|
||||
minecraft.stderr.on("data", (data) =>
|
||||
this.emit("data", data.toString("utf-8"))
|
||||
);
|
||||
minecraft.on("close", (code) => this.emit("close", code));
|
||||
return minecraft;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MCLCore
|
||||
module.exports = PiMiCore;
|
||||
|
|
29
index.d.ts
vendored
29
index.d.ts
vendored
|
@ -38,7 +38,7 @@ declare module "minecraft-launcher-core" {
|
|||
*/
|
||||
clientPackage?: string;
|
||||
/**
|
||||
* if true MCLC will remove the client package zip file after its finished extracting.
|
||||
* if true PiMi will remove the client package zip file after its finished extracting.
|
||||
*/
|
||||
removePackage?: boolean;
|
||||
/**
|
||||
|
@ -81,11 +81,11 @@ declare module "minecraft-launcher-core" {
|
|||
/**
|
||||
* type of release, usually `release` or `snapshot`
|
||||
*/
|
||||
type: 'release' | 'snapshot' | string;
|
||||
type: "release" | "snapshot" | string;
|
||||
/**
|
||||
* The name of the folder, jar file, and version json in the version folder.
|
||||
*
|
||||
* ` MCLC will look in the `versions` folder for this name
|
||||
* ` PiMi will look in the `versions` folder for this name
|
||||
* @example '1.16.4-fabric'
|
||||
*/
|
||||
custom?: string;
|
||||
|
@ -152,7 +152,7 @@ declare module "minecraft-launcher-core" {
|
|||
fullscreen?: boolean;
|
||||
};
|
||||
quickPlay?: {
|
||||
type: 'singleplayer' | 'multiplayer' | 'realms' | 'legacy';
|
||||
type: "singleplayer" | "multiplayer" | "realms" | "legacy";
|
||||
identifier: string;
|
||||
path?: string;
|
||||
};
|
||||
|
@ -171,8 +171,8 @@ declare module "minecraft-launcher-core" {
|
|||
name: string;
|
||||
user_properties: Partial<any>;
|
||||
meta?: {
|
||||
type: "mojang" | "msa",
|
||||
demo?: boolean
|
||||
type: "mojang" | "msa";
|
||||
demo?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -201,10 +201,7 @@ declare module "minecraft-launcher-core" {
|
|||
* @param access_token Token being checked if it can be used to login with (online mode)
|
||||
* @param client_token Client token being checked to see if there was a change of client (online mode)
|
||||
*/
|
||||
refreshAuth(
|
||||
access_token: string,
|
||||
client_token: string,
|
||||
): Promise<IUser>;
|
||||
refreshAuth(access_token: string, client_token: string): Promise<IUser>;
|
||||
/**
|
||||
*
|
||||
* @param access_token Token being checked if it can be used to login with (online mode)
|
||||
|
@ -225,17 +222,21 @@ declare module "minecraft-launcher-core" {
|
|||
changeApiUrl(url: string): void;
|
||||
}
|
||||
|
||||
import { EventEmitter } from 'events'
|
||||
import { ChildProcessWithoutNullStreams } from 'child_process'
|
||||
import { EventEmitter } from "events";
|
||||
import { ChildProcessWithoutNullStreams } from "child_process";
|
||||
|
||||
export class Client extends EventEmitter {
|
||||
launch(options: ILauncherOptions): Promise<ChildProcessWithoutNullStreams | null>;
|
||||
launch(
|
||||
options: ILauncherOptions
|
||||
): Promise<ChildProcessWithoutNullStreams | null>;
|
||||
protected printVersion(): void;
|
||||
protected createRootDirectory(): void;
|
||||
protected createGameDirectory(): void;
|
||||
protected extractPackage(): Promise<void>;
|
||||
protected getModifyJson(): Promise<any>;
|
||||
protected startMinecraft(launchArguments: string[]): ChildProcessWithoutNullStreams;
|
||||
protected startMinecraft(
|
||||
launchArguments: string[]
|
||||
): ChildProcessWithoutNullStreams;
|
||||
}
|
||||
|
||||
export const Authenticator: IAuthenticator;
|
||||
|
|
2952
package-lock.json
generated
Normal file
2952
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
18
package.json
18
package.json
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"name": "minecraft-launcher-core",
|
||||
"version": "3.17.0",
|
||||
"description": "Lightweight module that downloads and runs Minecraft using javascript / NodeJS",
|
||||
"name": "pimi-launcher-core",
|
||||
"version": "1.0.0",
|
||||
"description": "Core for pimi-launcher (Minecraft)",
|
||||
"main": "index.js",
|
||||
"types": "./index.d.ts",
|
||||
"dependencies": {
|
||||
"adm-zip": "^0.4.13",
|
||||
"checksum": "^0.1.1",
|
||||
|
@ -23,7 +24,7 @@
|
|||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Pierce01/MinecraftLauncher-core.git"
|
||||
"url": "git+https://github.com/artegoser/pimi-launcher-core.git"
|
||||
},
|
||||
"keywords": [
|
||||
"minecraft",
|
||||
|
@ -32,7 +33,14 @@
|
|||
"launcher",
|
||||
"minecraft-forge"
|
||||
],
|
||||
"author": "Pierce Harriz",
|
||||
"author": "artegoser <me@artegoser.ru> (https://github.com/artegoser)",
|
||||
"contributors": [
|
||||
"Pierce Harriz (https://github.com/Pierce01)",
|
||||
"Bricklou (https://github.com/Bricklou)",
|
||||
"Suyashtnt (https://github.com/Suyashtnt)",
|
||||
"Coding-Kiwi (https://github.com/Coding-Kiwi)",
|
||||
"KevSlashNull (https://github.com/KevSlashNull)"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Pierce01/MinecraftLauncher-core/issues"
|
||||
|
|
Loading…
Add table
Reference in a new issue