Skip to content

Commit

Permalink
feat: 🎉 begin project
Browse files Browse the repository at this point in the history
  • Loading branch information
RichardDorian committed Oct 1, 2022
1 parent 1026c8a commit 3b8bd0f
Show file tree
Hide file tree
Showing 14 changed files with 505 additions and 32 deletions.
46 changes: 23 additions & 23 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# name: Build
name: Build

# on:
# push:
# branches: [main]
# pull_request:
# branches: [main]
on:
push:
branches: [main]
pull_request:
branches: [main]

# jobs:
# build:
# runs-on: ubuntu-latest
# strategy:
# matrix:
# node-version: [16.x]
# steps:
# - uses: actions/checkout@v2
# - name: Node.js
# uses: actions/setup-node@v2
# with:
# node-version: ${{ matrix.node-version }}
# - run: npm install
# - name: Build code
# run: npm run build
# - name: Test code
# run: npm run test
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- uses: actions/checkout@v2
- name: Node.js
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- name: Build code
run: npm run build
# - name: Test code
# run: npm run test
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
# MinecraftJS Template
# Launcher

Fill with your own content
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/MinecraftJS/launcher/Build?style=for-the-badge)
![GitHub](https://img.shields.io/github/license/MinecraftJS/launcher?style=for-the-badge)
![npm (scoped)](https://img.shields.io/npm/v/@minecraft-js/launcher?style=for-the-badge)

This library makes creating Minecraft launchers in JavaScript very easy. It'll help you managing all the stuff Minecraft requires like downloading the game and the assets.

# Documentation

## Installation

Install the package:

```bash
$ npm install @minecraft-js/launcher
```

And then import it in your JavaScript/TypeScript file

```ts
const { mcFolder } = require('@minecraft-js/launcher'); // CommonJS

import { mcFolder } from '@minecraft-js/launcher'; // ES6
```

## Downloading assets

```ts
await mcFolder.downloadAssets('1.16.5'); // You can put any version here
```
36 changes: 34 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "template",
"name": "@minecraft-js/launcher",
"version": "1.0.0",
"description": "todo: change",
"description": "Makes creating Minecraft launchers in JavaScript an easy task",
"main": "dist/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
Expand All @@ -14,14 +14,14 @@
"keywords": [
"minecraftjs"
],
"author": "todo: change",
"author": "RichardDorian",
"license": "MIT",
"bugs": {
"url": "https://github.com/MinecraftJS/template/issues"
},
"homepage": "https://github.com/MinecraftJS/template#readme",
"dependencies": {},
"devDependencies": {
"@types/node": "^18.7.23",
"prettier": "^2.7.1",
"typescript": "^4.8.3"
},
Expand All @@ -30,5 +30,8 @@
],
"engines": {
"node": ">=18.x"
},
"dependencies": {
"node-downloader-helper": "^2.1.4"
}
}
41 changes: 41 additions & 0 deletions src/MCFolder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { mkdir } from 'node:fs/promises';
import { DOT_MINECRAFT } from './constants';
import { downloadAssets } from './utils/downloadAssets';
import { exists } from './utils/exists';

export class MCFolder {
public static readonly instance = new MCFolder();

public constructor() {}

/**
* Initialize the `.minecraft` folder,
* run all the checks
*/
public async initialize(): Promise<void> {
await this.checkFolderExistance();
}

/**
* Download the Minecraft assets for the given version
* @param version Version you want to download the assets for
*/
public async downloadAssets(version: string): Promise<void> {
await downloadAssets(version);
}

/**
* Check if the `.minecraft` directory exists.
* If it doesn't, it'll create it
*/
private async checkFolderExistance(): Promise<void> {
if (await exists(DOT_MINECRAFT)) return;

await mkdir(DOT_MINECRAFT, { recursive: true });
}
}

MCFolder.instance.initialize();

/** Static instance of the `MCFolder` class */
export const mcFolder = MCFolder.instance;
29 changes: 29 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { join } from 'node:path';

/** Path to the `.minecraft` folder */
export const DOT_MINECRAFT =
process.platform === 'win32'
? join(process.env.APPDATA, '.minecraft')
: process.platform === 'darwin'
? join(process.env.HOME, 'Library', 'Application Support', 'minecraft')
: join(process.env.HOME, '.minecraft');

/** URL pointing to the version manifest */
export const VERSION_MANIFEST_URL =
'https://piston-meta.mojang.com/mc/game/version_manifest_v2.json';

export function OBJECT_FOLDER(hash: string): string {
return join(DOT_MINECRAFT, 'assets', 'objects', hash.slice(0, 2));
}

export function OBJECT_PATH(hash: string): string {
return join(OBJECT_FOLDER(hash), hash);
}

export function ASSET_DOWNLOAD_URL(hash: string): string {
return `http://resources.download.minecraft.net/${hash.slice(0, 2)}/${hash}`;
}

export function ASSET_INDEX_PATH(id: string): string {
return join(DOT_MINECRAFT, 'assets', 'indexes', `${id}.json`);
}
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export * as constants from './constants';
export * from './MCFolder';
export * from './utils/downloadAssets';
export * from './utils/getAssetIndex';
export * from './utils/getVersion';
export * from './utils/getVersionManifest';
86 changes: 86 additions & 0 deletions src/utils/downloadAssets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { DownloaderHelper } from 'node-downloader-helper';
import { createHash } from 'node:crypto';
import { readFile, writeFile } from 'node:fs/promises';
import {
ASSET_DOWNLOAD_URL,
ASSET_INDEX_PATH,
OBJECT_FOLDER,
OBJECT_PATH,
} from '../constants';
import { exists } from './exists';
import { getAssetIndex } from './getAssetIndex';

/**
* Download the Minecraft assets for the given version
* @param version Version you want to download the assets for
* @param options Options you can pass to this function to modify its behavior
*/
export async function downloadAssets(
version: string,
options?: DownloadAssetsOptions
): Promise<void> {
options = options ?? {};

const { id, index } = await getAssetIndex(version);

await writeFile(ASSET_INDEX_PATH(id), JSON.stringify(index));

const toDownload: { hash: string; size: number }[] = [];

for (const object of Object.values(index.objects)) {
const path = OBJECT_PATH(object.hash);

if (!(await exists(path))) {
toDownload.push(object);
continue;
}

if (
options.disableSizeCheck !== true ||
options.disableHashCheck !== true
) {
const file = await readFile(path);

if (options.disableSizeCheck !== true && file.length !== object.size) {
toDownload.push(object);
continue;
}

if (options.disableHashCheck !== true) {
const hash = createHash('sha1').update(file).digest('hex');
if (hash !== object.hash) toDownload.push(object);
}
}
}

for (const object of toDownload) {
await downloadAsset(object.hash);
}
}

/**
* Download an asset from the given hash
* @param hash Hash of the file you want to download
*/
function downloadAsset(hash: string): Promise<void> {
return new Promise((resolve, reject) => {
const download = new DownloaderHelper(
ASSET_DOWNLOAD_URL(hash),
OBJECT_FOLDER(hash),
{
fileName: hash,
}
);

download.on('error', reject);
download.on('end', () => resolve());
download.start();
});
}

export interface DownloadAssetsOptions {
/** Whether or not to disable the size check */
disableSizeCheck?: boolean;
/** Whether or not to disable the hash check */
disableHashCheck?: boolean;
}
12 changes: 12 additions & 0 deletions src/utils/exists.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { stat } from 'fs/promises';

/**
* Check if the given path exists
* @param path The path to test
* @returns Whether or not the path exists
*/
export function exists(path: string): Promise<boolean> {
return stat(path)
.then(() => true)
.catch(() => false);
}
Loading

0 comments on commit 3b8bd0f

Please sign in to comment.