UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

550 lines (549 loc) 23.8 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MINECRAFT_DEBUG_PORT_OFFSET = exports.MINECRAFT_PORT_INCREMENT = exports.MINECRAFT_BASE_PORT = void 0; const Utilities_1 = __importDefault(require("../core/Utilities")); const Log_1 = __importDefault(require("../core/Log")); const VanillaProjectManager_1 = __importDefault(require("./VanillaProjectManager")); const CreatorTools_1 = require("../app/CreatorTools"); /** * Minecraft server port constants for multi-slot architecture. * Slot 0 = 19132, Slot 1 = 19164, Slot 2 = 19196, etc. (32-port spacing) * Debug ports follow the same pattern starting at 19144 (19132 + 12) */ exports.MINECRAFT_BASE_PORT = 19132; exports.MINECRAFT_PORT_INCREMENT = 32; exports.MINECRAFT_DEBUG_PORT_OFFSET = 12; // Debug port is base port + 12 class MinecraftUtilities { /** * Get the Minecraft UDP port for a given slot number. * Slot 0 = 19132, Slot 1 = 19164, Slot 2 = 19196, etc. * @param slotNumber The slot number (0-based) * @returns The UDP port for Minecraft connections */ static getPortForSlot(slotNumber) { return exports.MINECRAFT_BASE_PORT + slotNumber * exports.MINECRAFT_PORT_INCREMENT; } /** * Get the slot number from a Minecraft UDP port. * @param port The UDP port * @returns The slot number (0-based) */ static getSlotFromPort(port) { return Math.floor((port - exports.MINECRAFT_BASE_PORT) / exports.MINECRAFT_PORT_INCREMENT); } /** * Get the script debugger port for a given slot number. * The debug port is the base port + 12 for each slot. * Slot 0 = 19144, Slot 1 = 19176, Slot 2 = 19208, etc. * @param slotNumber The slot number (0-based) * @returns The debug port for the script debugger */ static getDebugPortForSlot(slotNumber) { return MinecraftUtilities.getPortForSlot(slotNumber) + exports.MINECRAFT_DEBUG_PORT_OFFSET; } static isReloadableSetOfChanges(differenceSet) { return differenceSet.hasFileOnlyOfExtension("js", "ts", "map") && !differenceSet.getHasDeletions(); } static removeSubTypeExtensionFromName(name) { let canonId = name.trim(); if (name.endsWith(".json")) { canonId = canonId.substring(0, canonId.length - 5); } const lastPeriod = name.lastIndexOf("."); if (lastPeriod >= 0) { canonId = canonId.substring(0, lastPeriod); } return canonId; } static getServerStatusFromState(state) { switch (state) { case CreatorTools_1.CreatorToolsMinecraftState.stopped: return "stopped"; case CreatorTools_1.CreatorToolsMinecraftState.error: return "error"; case CreatorTools_1.CreatorToolsMinecraftState.starting: return "starting"; case CreatorTools_1.CreatorToolsMinecraftState.preparing: return "preparing"; case CreatorTools_1.CreatorToolsMinecraftState.started: return "running"; case CreatorTools_1.CreatorToolsMinecraftState.stopping: return "stopping"; case CreatorTools_1.CreatorToolsMinecraftState.disconnected: return "disconnected"; case CreatorTools_1.CreatorToolsMinecraftState.initializing: return "initializing"; case CreatorTools_1.CreatorToolsMinecraftState.initialized: return "initialized"; case CreatorTools_1.CreatorToolsMinecraftState.prepared: return "prepared"; case CreatorTools_1.CreatorToolsMinecraftState.newMinecraft: return "new minecraft"; case CreatorTools_1.CreatorToolsMinecraftState.none: return "none"; default: return "unknown"; } } static getIsBuiltIn(eventId) { return (eventId === "minecraft:entity_spawned" || eventId === "minecraft:entity_born" || eventId === "minecraft:transformed" || eventId === "minecraft:on_prime"); } static getAfterPackPath(path) { const hashIndex = path.indexOf("#"); if (hashIndex >= 0) { path = path.substring(hashIndex + 1); } return path; } static getNamespacedIdNamspace(name) { let canonId = name.toLowerCase().trim(); let colonIndex = canonId.indexOf(":"); if (colonIndex >= 0) { canonId = canonId.substring(0, colonIndex); } return canonId; } static getNamespacedIdName(name) { let canonId = name.toLowerCase().trim(); let colonIndex = canonId.indexOf(":"); if (colonIndex >= 0) { canonId = canonId.substring(colonIndex + 1); } return canonId; } static pathLooksLikeSkinPackContainerName(path) { let pathCanon = path.toLowerCase(); pathCanon = pathCanon.replace(/\\/gi, "/"); pathCanon = pathCanon.replace(/ /gi, "_"); pathCanon = Utilities_1.default.ensureEndsWithSlash(Utilities_1.default.ensureStartsWithSlash(pathCanon)); if (pathCanon.indexOf("skin_packs") >= 0 || pathCanon.indexOf("_sps") >= 0 || pathCanon.indexOf("/sps_") >= 0 || pathCanon.endsWith("sps/") || pathCanon === "/sps/" || pathCanon === "/sp/") { return true; } return false; } static pathLooksLikeBehaviorPackContainerName(path) { let pathCanon = path.toLowerCase(); pathCanon = pathCanon.replace(/\\/gi, "/"); pathCanon = pathCanon.replace(/ /gi, "_"); pathCanon = Utilities_1.default.ensureEndsWithSlash(Utilities_1.default.ensureStartsWithSlash(pathCanon)); if (pathCanon.indexOf("behavior_packs") >= 0 || pathCanon.indexOf("_bps") >= 0 || pathCanon.indexOf("/bps_") >= 0 || pathCanon.endsWith("bps/") || pathCanon === "/bps/" || pathCanon === "/bp/") { return true; } return false; } static pathLooksLikeDesignPackContainerName(path) { let pathCanon = path.toLowerCase(); pathCanon = pathCanon.replace(/\\/gi, "/"); pathCanon = pathCanon.replace(/ /gi, "_"); pathCanon = Utilities_1.default.ensureEndsWithSlash(Utilities_1.default.ensureStartsWithSlash(pathCanon)); if (pathCanon.indexOf("design_packs") >= 0 || pathCanon.indexOf("_dps") >= 0 || pathCanon.indexOf("/dps_") >= 0 || pathCanon.endsWith("dps/") || pathCanon === "/dps/" || pathCanon === "/dp/") { return true; } return false; } static pathLooksLikeResourcePackContainerName(path) { let pathCanon = path.toLowerCase(); pathCanon = pathCanon.replace(/\\/gi, "/"); pathCanon = pathCanon.replace(/ /gi, "_"); pathCanon = Utilities_1.default.ensureEndsWithSlash(Utilities_1.default.ensureStartsWithSlash(pathCanon)); if (pathCanon.indexOf("resource_packs") >= 0 || pathCanon.indexOf("_rps") >= 0 || pathCanon.indexOf("/rps_") >= 0 || pathCanon.endsWith("rps/") || pathCanon === "/rps/" || pathCanon === "/rp/") { return true; } return false; } static pathLooksLikePackContainerName(path) { return (this.pathLooksLikeBehaviorPackContainerName(path) || this.pathLooksLikeResourcePackContainerName(path) || this.pathLooksLikeResourcePackContainerName(path) || this.pathLooksLikeSkinPackContainerName(path)); } static pathLooksLikeDesignPackName(path) { let pathCanon = path.toLowerCase(); pathCanon = pathCanon.replace(/\\/gi, "/"); pathCanon = pathCanon.replace(/ /gi, "_"); pathCanon = Utilities_1.default.ensureEndsWithSlash(Utilities_1.default.ensureStartsWithSlash(pathCanon)); if (pathCanon.indexOf("/design") >= 0 || pathCanon.indexOf("design_pack") >= 0 || pathCanon.indexOf("_dp") >= 0 || // bp is uncommon as the start of a word pathCanon.indexOf("/dp_") >= 0 || pathCanon.indexOf("/dp/") >= 0) { return true; } return false; } static pathLooksLikeBehaviorPackName(path) { let pathCanon = path.toLowerCase(); pathCanon = pathCanon.replace(/\\/gi, "/"); pathCanon = pathCanon.replace(/ /gi, "_"); pathCanon = Utilities_1.default.ensureEndsWithSlash(Utilities_1.default.ensureStartsWithSlash(pathCanon)); if (pathCanon.indexOf("/behavior") >= 0 || pathCanon.indexOf("behavior_pack") >= 0 || pathCanon.indexOf("_bp") >= 0 || // bp is uncommon as the start of a word pathCanon.indexOf("/bp_") >= 0 || pathCanon.indexOf("/bp/") >= 0) { return true; } return false; } static isBedrockItem(itemId) { if (itemId.indexOf("element") >= 0) { return false; } return true; } static getBlockDefaultTexturePath(blockId) { let blockCat = VanillaProjectManager_1.default.getBlocksCatalogDirect(); let textureCat = VanillaProjectManager_1.default.getTerrainTexturesCatalogDirect(); if (!blockCat || !textureCat) { return undefined; } const blockTextureId = blockCat.getDefaultTextureId(blockId); if (!blockTextureId) { return undefined; } return textureCat.getDefaultTexturePath(blockTextureId); } static shortenFilterDescription(descript) { descript = descript.replace("Returns true if ", ""); descript = descript.replace("True if ", ""); descript = descript.replace("Returns true when ", ""); descript = descript.replace("Tests the ", ""); descript = descript.replace("Tests if ", ""); descript = descript.replace("Tests whether ", ""); descript = descript.replace("Tests for ", ""); descript = descript.replace("Returns ", ""); if (descript.startsWith("the ")) { descript = descript.substring(4); } descript = Utilities_1.default.ensureLooksLikeSentence(descript); return descript; } static clearCommonTerms(path) { path = Utilities_1.default.replaceAllCaseInsensitive(path, "/resource_packs/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/behavior_packs/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/design_packs/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/skin_packs/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/resource_pack/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/behavior_pack/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/design_pack/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/skin_pack/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/behavior/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/resource/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/design/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/static-assets/", "/"); path = Utilities_1.default.replaceAllCaseInsensitive(path, "/zips/", "/"); path = path.replace(/\/\//gi, "/"); return path; } static pathLooksLikeResourcePackName(path) { let pathCanon = path.toLowerCase(); pathCanon = pathCanon.replace(/\\/gi, "/"); pathCanon = pathCanon.replace(/ /gi, "_"); pathCanon = Utilities_1.default.ensureEndsWithSlash(Utilities_1.default.ensureStartsWithSlash(pathCanon)); if (pathCanon.indexOf("/resource") >= 0 || pathCanon.indexOf("resource_pack") >= 0 || pathCanon.indexOf("_rp") >= 0 || // rp is uncommon as the start of a word pathCanon.indexOf("/rp_") >= 0 || pathCanon.indexOf("/rp/") >= 0) { return true; } return false; } static pathLooksLikeSkinPackName(path) { let pathCanon = path.toLowerCase(); pathCanon = pathCanon.replace(/\\/gi, "/"); pathCanon = pathCanon.replace(/ /gi, "_"); pathCanon = Utilities_1.default.ensureEndsWithSlash(Utilities_1.default.ensureStartsWithSlash(pathCanon)); // because sp might common in english as an abbreviation, be less tolerant // compared to behavior/resource packs in assuming "sp" means skin pack if (pathCanon.indexOf("/skin") >= 0 || pathCanon.indexOf("skin_pack") >= 0) { return true; } return false; } static pathLooksLikePersonaPackName(path) { let pathCanon = path.toLowerCase(); pathCanon = pathCanon.replace(/\\/gi, "/"); pathCanon = pathCanon.replace(/ /gi, "_"); pathCanon = Utilities_1.default.ensureEndsWithSlash(Utilities_1.default.ensureStartsWithSlash(pathCanon)); if (pathCanon.indexOf("/persona/") >= 0) { return true; } return false; } static pathLooksLikeWorldFolderName(path) { let pathCanon = path.toLowerCase(); pathCanon = pathCanon.replace(/\\/gi, "/"); pathCanon = pathCanon.replace(/ /gi, "_"); pathCanon = Utilities_1.default.ensureEndsWithSlash(Utilities_1.default.ensureStartsWithSlash(pathCanon)); if (pathCanon.indexOf("/world") >= 0) { return true; } return false; } static pathLooksLikeSubPacksFolderName(path) { let pathCanon = path.toLowerCase(); pathCanon = pathCanon.replace(/\\/gi, "/"); pathCanon = pathCanon.replace(/ /gi, "_"); pathCanon = Utilities_1.default.ensureEndsWithSlash(Utilities_1.default.ensureStartsWithSlash(pathCanon)); if (pathCanon.indexOf("/subpacks") >= 0) { return true; } return false; } static pathLooksLikePackName(path) { return (this.pathLooksLikeBehaviorPackName(path) || this.pathLooksLikeResourcePackName(path) || this.pathLooksLikeSkinPackName(path)); } static replaceMinecraftPathTokens(tokenizePath) { if (tokenizePath.startsWith("<RPME>")) { tokenizePath += ".geo.json"; } else if (tokenizePath.startsWith("<BPE>") || tokenizePath.startsWith("<BPLE>") || tokenizePath.startsWith("<BPSR>")) { tokenizePath += ".json"; } else if (tokenizePath.startsWith("<RPE>")) { tokenizePath += ".entity.json"; } else if (tokenizePath.startsWith("<RPAC>")) { tokenizePath += ".animation_controllers.json"; } else if (tokenizePath.startsWith("<RPRC>")) { tokenizePath += ".render_controllers.json"; } else if (tokenizePath.startsWith("<RPA>")) { tokenizePath += ".animation.json"; } else if (tokenizePath.startsWith("<RPTE>")) { if (tokenizePath.indexOf(".") < 0) { tokenizePath += ".png"; } } tokenizePath = tokenizePath.replace(/<RPTE>/gi, "/resource_pack/textures/entity/"); tokenizePath = tokenizePath.replace(/<RPME>/gi, "/resource_pack/models/entity/"); tokenizePath = tokenizePath.replace(/<RPAC>/gi, "/resource_pack/animation_controllers/"); tokenizePath = tokenizePath.replace(/<RPRC>/gi, "/resource_pack/render_controllers/"); tokenizePath = tokenizePath.replace(/<RPA>/gi, "/resource_pack/animations/"); tokenizePath = tokenizePath.replace(/<RPE>/gi, "/resource_pack/entity/"); tokenizePath = tokenizePath.replace(/<BPE>/gi, "/behavior_pack/entities/"); tokenizePath = tokenizePath.replace(/<BPLE>/gi, "/behavior_pack/loot_tables/entities/"); tokenizePath = tokenizePath.replace(/<BPSR>/gi, "/behavior_pack/spawn_rules/"); return tokenizePath; } static makeNameScriptSafe(tokenName) { tokenName = tokenName.replace(/[^a-z0-9_]/gi, "-").replace(/\s+/g, "-"); while (tokenName.length > 1 && !Utilities_1.default.isAlpha(tokenName.substring(0, 1))) { tokenName = tokenName.substring(1); } if (!Utilities_1.default.isAlpha(tokenName.substring(0, 1))) { tokenName = "a" + tokenName; } return tokenName; } static makeNameFolderSafe(tokenName) { tokenName = Utilities_1.default.replaceAll(tokenName, " ", "-").toLowerCase(); if (tokenName.length > 16) { tokenName = tokenName.substring(0, 16); } return tokenName; } static getVersionArrayFrom(ver) { if (typeof ver === "number") { if (Math.floor(ver) !== ver) { // deal with decimal numbers that have been observed, e.g., 1.1 return [Math.floor(ver), Math.floor((ver - Math.floor(ver)) * 10), 0]; } else { return [ver, 0, 0]; } } if (ver === undefined) { return [0, 0, 0]; } if (typeof ver === "string") { let fvArr = ver.split("."); let fvArrInt = []; for (let i = 0; i < fvArr.length; i++) { try { const num = parseInt(fvArr[i]); if (isNaN(num)) { return [0, 0, 0]; } fvArrInt.push(num); } catch (e) { } } while (fvArrInt.length < 3) { fvArrInt.push(0); } return fvArrInt; } return ver; } static getVersionNumber(ver) { if (ver === undefined) { return 0; } let fvArr = ver.split("."); let fvArrInt = []; for (let i = 0; i < fvArr.length; i++) { try { const num = parseInt(fvArr[i]); if (isNaN(num)) { return 0; } fvArrInt.push(num); } catch (e) { } } while (fvArrInt.length < 3) { fvArrInt.push(0); } if (fvArrInt.length < 3) { return 0; } let verNum = fvArrInt[0] * 1000000 + 10000000; verNum += fvArrInt[1] * 1000 + fvArrInt[2]; return verNum; } static cleanUpScriptDescription(scriptDescription) { scriptDescription = Utilities_1.default.replaceAll(scriptDescription, "/*", ""); scriptDescription = Utilities_1.default.replaceAll(scriptDescription, "*/\n", ""); scriptDescription = Utilities_1.default.replaceAll(scriptDescription, "*\n", ""); scriptDescription = Utilities_1.default.replaceAll(scriptDescription, "*/", ""); scriptDescription = Utilities_1.default.replaceAll(scriptDescription, "*", ""); scriptDescription = Utilities_1.default.replaceAll(scriptDescription, "@beta", ""); scriptDescription = scriptDescription.trim(); return scriptDescription; } static getIdsAndVersions(packStr) { const refs = []; const packRefStrs = packStr.split(","); for (const packRefStr of packRefStrs) { const packRefStrParts = packRefStr.split("@"); let wasAdded = false; if (packRefStrParts.length === 2) { const versionNumberParts = packRefStrParts[1].split("."); if (versionNumberParts.length === 3) { const verNumber = []; for (let i = 0; i < versionNumberParts.length; i++) { let num = undefined; try { num = parseInt(versionNumberParts[i]); } catch (e) { } if (num !== undefined) { verNumber.push(num); } } if (verNumber.length === 3 && this.isValidUuid(packRefStrParts[0])) { refs.push({ uuid: packRefStrParts[0], version: verNumber, }); wasAdded = true; } } } if (!wasAdded) { Log_1.default.fail("UUID/version is not in a good form (uuid@x.y.z) - is '" + packRefStr + "'"); } } return refs; } static isValidUuid(uuid) { // sample uuid: 414a42cd-98d4-4e0d-8e3f-e34ab8a0c05e // xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx if (uuid.length === 36) { const parts = uuid.split("-"); if (parts.length === 5 && parts[0].length === 8 && parts[1].length === 4 && parts[2].length === 4 && parts[3].length === 4 && parts[4].length === 12) { for (let i = 0; i < parts.length; i++) { for (let j = 0; j < parts[i].length; j++) { if (!Utilities_1.default.isAlphaNumeric(parts[i][j])) { return false; } } } } } return false; } static fixupJson(json) { json = json.replace(/([, ;}\]])0b([, ;}\]])/gi, "$1false$2"); json = json.replace(/([, ;}\]])1b([, ;}\]])/gi, "$1true$2"); json = json.replace(/(\d)b([, ;\]])/gi, "$1$2"); json = json.replace(/(\d)d([, ;\]])/gi, "$1$2"); json = json.replace(/(\d)f([, ;\]])/gi, "$1$2"); json = json.replace(/(\d)s([, ;\]])/gi, "$1$2"); json = json.replace(/\[I;/gi, "["); json = json.replace(/…/gi, ""); /* json = json.replace(/([, ;\]])none([, ;\]])/gi, "$1\"none\"$2"); json = json.replace(/([, ;\]])south([, ;\]])/gi, "$1\"south\"$2"); json = json.replace(/([, ;\]])north([, ;\]])/gi, "$1\"north\"$2"); json = json.replace(/([, ;\]])east([, ;\]])/gi, "$1\"east\"$2"); json = json.replace(/([, ;\]])west([, ;\]])/gi, "$1\"west\"$2"); json = json.replace(/([, ;\]])side([, ;\]])/gi, "$1\"side\"$2"); */ return json; } static canonicalizeName(id) { if (id === undefined || id === null) { Log_1.default.debug("canonicalizeName called with undefined/null id"); return ""; } let canonId = id.toLowerCase().trim(); if (canonId.startsWith("minecraft:")) { canonId = canonId.substring(10, canonId.length); } return canonId; } static canonicalizeFullName(id) { if (id === undefined || id === null) { Log_1.default.debug("canonicalizeFullName called with undefined/null id"); return ""; } let canonId = id.toLowerCase().trim(); if (canonId.indexOf(":") < 0) { canonId = "minecraft:" + canonId; } return canonId; } } exports.default = MinecraftUtilities;