mirror of
https://github.com/Kir-Antipov/mc-publish.git
synced 2024-11-25 01:41:05 -05:00
Made utils for working with Minecraft versions
This commit is contained in:
parent
7cc8951c69
commit
e38f6957c3
4 changed files with 201 additions and 1 deletions
27
package-lock.json
generated
27
package-lock.json
generated
|
@ -2262,6 +2262,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"data-uri-to-buffer": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og=="
|
||||||
|
},
|
||||||
"data-urls": {
|
"data-urls": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
|
||||||
|
@ -2711,6 +2716,14 @@
|
||||||
"bser": "2.1.1"
|
"bser": "2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fetch-blob": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-hunJbvy/6OLjCD0uuhLdp0mMPzP/yd2ssd1t2FCJsaA7wkWhpbp9xfuNVpv7Ll4jFhzp6T4LAupSiV9uOeg0VQ==",
|
||||||
|
"requires": {
|
||||||
|
"web-streams-polyfill": "^3.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"file-entry-cache": {
|
"file-entry-cache": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||||
|
@ -3910,6 +3923,15 @@
|
||||||
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node-fetch": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-bKMI+C7/T/SPU1lKnbQbwxptpCrG9ashG+VkytmXCPZyuM9jB6VU+hY0oi4lC8LxTtAeWdckNCTa3nrGsAdA3Q==",
|
||||||
|
"requires": {
|
||||||
|
"data-uri-to-buffer": "^3.0.1",
|
||||||
|
"fetch-blob": "^3.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node-int64": {
|
"node-int64": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||||
|
@ -4784,6 +4806,11 @@
|
||||||
"makeerror": "1.0.x"
|
"makeerror": "1.0.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"web-streams-polyfill": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-Czi3fG883e96T4DLEPRvufrF2ydhOOW1+1a6c3gNjH2aIh50DNFBdfwh2AKoOf1rXvpvavAoA11Qdq9+BKjE0Q=="
|
||||||
|
},
|
||||||
"webidl-conversions": {
|
"webidl-conversions": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.5.0",
|
"@actions/core": "^1.5.0",
|
||||||
"fast-glob": "^3.2.7"
|
"fast-glob": "^3.2.7",
|
||||||
|
"node-fetch": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
153
src/utils/minecraft-utils.ts
Normal file
153
src/utils/minecraft-utils.ts
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
import fetch from "node-fetch";
|
||||||
|
import Version from "./version";
|
||||||
|
|
||||||
|
export enum MinecraftVersionType {
|
||||||
|
Release = "release",
|
||||||
|
Snapshot = "snapshot",
|
||||||
|
OldBeta = "old_beta",
|
||||||
|
OldAlpha = "old_alpha"
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MinecraftVersion {
|
||||||
|
public readonly id: string;
|
||||||
|
public readonly name: string;
|
||||||
|
public readonly version: Version;
|
||||||
|
public readonly type: MinecraftVersionType;
|
||||||
|
public readonly url: string;
|
||||||
|
public readonly time: Date;
|
||||||
|
public readonly releaseTime: Date;
|
||||||
|
|
||||||
|
public constructor(id: string, name: string, type: MinecraftVersionType, url: string, time: Date, releaseTime: Date) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.version = new Version(name);
|
||||||
|
this.type = type;
|
||||||
|
this.url = url;
|
||||||
|
this.time = time;
|
||||||
|
this.releaseTime = releaseTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isRelease(): boolean {
|
||||||
|
return this.type === MinecraftVersionType.Release;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isSnapshot(): boolean {
|
||||||
|
return this.type === MinecraftVersionType.Snapshot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParsedMinecraftVersion {
|
||||||
|
id: string;
|
||||||
|
type: MinecraftVersionType;
|
||||||
|
url: string;
|
||||||
|
time: string;
|
||||||
|
releaseTime: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cachedVersionsById: Map<string, MinecraftVersion> = null;
|
||||||
|
async function getVersionMap(): Promise<Map<string, MinecraftVersion>> {
|
||||||
|
if (!cachedVersionsById) {
|
||||||
|
cachedVersionsById = await loadVersions();
|
||||||
|
}
|
||||||
|
return cachedVersionsById;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadVersions(): Promise<Map<string, MinecraftVersion>> {
|
||||||
|
const response = <{ versions: ParsedMinecraftVersion[] }>await (await fetch("https://launchermeta.mojang.com/mc/game/version_manifest.json")).json();
|
||||||
|
const versionsById = new Map<string, MinecraftVersion>();
|
||||||
|
for (let i = 0; i < response.versions.length; ++i) {
|
||||||
|
const version = response.versions[i];
|
||||||
|
versionsById.set(version.id, new MinecraftVersion(version.id, getNearestReleaseVersionName(response.versions, i), version.type, version.url, new Date(version.time), new Date(version.releaseTime)));
|
||||||
|
}
|
||||||
|
return versionsById;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNearestReleaseVersionName(versions: ParsedMinecraftVersion[], start: number): string {
|
||||||
|
for (let i = start; i >= 0; --i) {
|
||||||
|
if (versions[i].type === MinecraftVersionType.Release) {
|
||||||
|
return versions[i].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const versionMatch = versions[start].id.match(/\d+\.\d+(?:\.\d+)?/);
|
||||||
|
if (versionMatch && versionMatch.length > 0) {
|
||||||
|
return versionMatch[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = start + 1; i < versions.length; ++i) {
|
||||||
|
if (versions[i].type === MinecraftVersionType.Release) {
|
||||||
|
return extractVersion(versions[i].id).split(".").map((x, i) => i === 1 ? (+x + 1) : x).filter((x, i) => i < 2).join(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getVersions(): Promise<MinecraftVersion[]> {
|
||||||
|
return [...(await getVersionMap()).values()];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getVersionById(id: string): Promise<MinecraftVersion | null> {
|
||||||
|
return (await getVersionMap()).get(id.trim()) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function findVersionByName(name: string, snapshot?: boolean): Promise<MinecraftVersion | null> {
|
||||||
|
const versionMap = await getVersionMap();
|
||||||
|
snapshot ??= isSnapshot(name);
|
||||||
|
const foundVersion = versionMap.get(name);
|
||||||
|
if (foundVersion && foundVersion.isSnapshot === !!snapshot) {
|
||||||
|
return foundVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = extractVersion(name);
|
||||||
|
for (const version of versionMap.values()) {
|
||||||
|
if (version.name === name && version.isSnapshot) {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractVersion(versionName: string): string {
|
||||||
|
return versionName.match(/(?<![a-z][\w\s\-.]*)\d+/ig).join(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
const weirdOldSnapshots = new Set(["1.7.1", "1.7", "1.6.3", "1.6", "1.5", "1.4.3", "1.4.1", "1.4", "1.3"]);
|
||||||
|
export function isSnapshot(versionName: string): boolean {
|
||||||
|
return !versionName.match(/^\s*\d+\.\d+/) || !!versionName.match(/pre|rc|snapshot/i) || weirdOldSnapshots.has(versionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseVersionNameFromFileVersion(fileVersion: string): string | null {
|
||||||
|
const mcMatch = fileVersion.match(/mc(\d+\.\d+(?:\.\d+)?)/i);
|
||||||
|
if (mcMatch) {
|
||||||
|
return mcMatch[1];
|
||||||
|
} else {
|
||||||
|
const versionCandidates = fileVersion.split(/[+-]/).map(x => x.match(/\d+\.\d+(?:\.\d+)?/)).filter(x => x).map(x => x[0]);
|
||||||
|
return versionCandidates.length > 1 ? versionCandidates.filter(x => x.startsWith("1.")).reverse()[0] : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getLatestRelease(): Promise<MinecraftVersion | null> {
|
||||||
|
return (await getVersions()).find(x => x.isRelease) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCompatibleBuilds(build: string | Version): Promise<MinecraftVersion[]> {
|
||||||
|
if (!(build instanceof Version)) {
|
||||||
|
build = new Version(build);
|
||||||
|
}
|
||||||
|
const versions = new Array<MinecraftVersion>();
|
||||||
|
for (const version of await getVersions()) {
|
||||||
|
if (version.version.major !== build.major) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version.version.minor < build.minor) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version.version.minor === build.minor && version.version.build >= build.build) {
|
||||||
|
versions.push(version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return versions;
|
||||||
|
}
|
19
src/utils/version.ts
Normal file
19
src/utils/version.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
export default class Version {
|
||||||
|
public readonly major: number;
|
||||||
|
public readonly minor: number;
|
||||||
|
public readonly build: number;
|
||||||
|
|
||||||
|
public constructor(major: number, minor: number, build: number);
|
||||||
|
|
||||||
|
public constructor(version: string);
|
||||||
|
|
||||||
|
public constructor(major: number | string, minor?: number, build?: number) {
|
||||||
|
if (typeof major === "string") {
|
||||||
|
[this.major, this.minor, this.build] = major.split(".").map(x => isNaN(+x) ? 0 : +x).concat(0, 0);
|
||||||
|
} else {
|
||||||
|
this.major = major || 0;
|
||||||
|
this.minor = minor || 0;
|
||||||
|
this.build = build || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue