@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
550 lines (549 loc) • 23.8 kB
JavaScript
;
// 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;