diff --git a/HoloPrint.js b/HoloPrint.js index 25a3cdc..871b0c6 100644 --- a/HoloPrint.js +++ b/HoloPrint.js @@ -37,7 +37,7 @@ export async function makePack(structureFiles, config = {}, resourcePackStack, p console.info("Finished reading structure NBTs!"); console.log("NBTs:", nbts); let structureSizes = nbts.map(nbt => nbt["size"].map(x => +x)); // Stored as Number instances: https://github.com/Offroaders123/NBTify/issues/50 - let structureNames = structureFiles.map(structureFile => structureFile.name.replace(/(\.holoprint)?\.[^.]+$/, "")); + let packName = config.PACK_NAME ?? getDefaultPackName(structureFiles); // Make the pack let loadedStuff = await loadStuff({ @@ -667,9 +667,9 @@ export async function makePack(structureFiles, config = {}, resourcePackStack, p } }))); hudScreenUI["material_list"]["size"][1] = finalisedMaterialList.length * 12 + 12; // 12px for each item + 12px for the heading - hudScreenUI["material_list_heading"]["controls"][1]["pack_name"]["text"] += structureNames.join(", "); + hudScreenUI["material_list_heading"]["controls"][1]["pack_name"]["text"] += packName; - manifest["header"]["name"] = `§uHoloPrint:§r ${structureNames.join(", ")}`; + manifest["header"]["name"] = packName; manifest["header"]["description"] = `§u★HoloPrint§r resource pack generated on §o${(new Date()).toLocaleString()}§r\nDeveloped by §l§6SuperLlama88888§r`; if(config.AUTHORS.length) { manifest["header"]["description"] += `\nStructure made by ${config.AUTHORS.join(" and ")}`; @@ -688,10 +688,14 @@ export async function makePack(structureFiles, config = {}, resourcePackStack, p let pack = new JSZip(); if(structureFiles.length == 1) { - pack.file(".mcstructure", structureFiles[0]); + pack.file(".mcstructure", structureFiles[0], { + comment: structureFiles[0].name + }); } else { structureFiles.forEach((structureFile, i) => { - pack.file(`${i}.mcstructure`, structureFile); + pack.file(`${i}.mcstructure`, structureFile, { + comment: structureFile.name + }); }); } pack.file("manifest.json", JSON.stringify(manifest)); @@ -734,21 +738,23 @@ export async function makePack(structureFiles, config = {}, resourcePackStack, p }); } - return new File([zippedPack], `${structureNames.join("+")}.holoprint.mcpack`); + return new File([zippedPack], `${packName}.holoprint.mcpack`); } /** - * Retrieves the structure file from a completed HoloPrint resource pack + * Retrieves the structure files from a completed HoloPrint resource pack. * @param {File} resourcePack HoloPrint resource pack (`*.mcpack) - * @returns {Promise} + * @returns {Promise>} */ -export async function extractStructureFileFromPack(resourcePack) { +export async function extractStructureFilesFromPack(resourcePack) { let packFolder = await JSZip.loadAsync(resourcePack); - let structureBlob = await packFolder.file(".mcstructure")?.async("blob"); - if(!structureBlob) { - return undefined; - } + let structureZipObjects = Object.values(packFolder.files).filter(file => file.name.endsWith(".mcstructure")); + let structureBlobs = await Promise.all(structureZipObjects.map(async zipObject => await zipObject.async("blob"))); let packName = resourcePack.name.slice(0, resourcePack.name.indexOf(".")); - return new File([structureBlob], `${packName}.mcstructure`); + if(structureBlobs.length == 1) { + return [new File([structureBlobs[0]], structureZipObjects[0].comment ?? `${packName}.mcstructure`)]; + } else { + return await Promise.all(structureBlobs.map(async (structureBlob, i) => new File([structureBlob], structureZipObjects[i].comment ?? `${packName}_${i}.mcstructure`))); + } } /** * Updates a HoloPrint resource pack by remaking it. @@ -759,11 +765,23 @@ export async function extractStructureFileFromPack(resourcePack) { * @returns {Promise} */ export async function updatePack(resourcePack, config, resourcePackStack, previewCont) { - let structureFile = extractStructureFileFromPack(resourcePack); - if(!structureFile) { - throw new Error(`No structure file found inside resource pack ${resourcePack.name}; cannot update pack!`); + let structureFiles = extractStructureFilesFromPack(resourcePack); + if(!structureFiles) { + throw new Error(`No structure files found inside resource pack ${resourcePack.name}; cannot update pack!`); + } + return await makePack(structureFiles, config, resourcePackStack, previewCont); +} +/** + * Returns the default pack name that would be used if no pack name is specified. + * @param {Array} structureFiles + * @returns {String} + */ +export function getDefaultPackName(structureFiles) { + let defaultName = structureFiles.map(structureFile => structureFile.name.replace(/(\.holoprint)?\.[^.]+$/, "")).join(", "); + if(defaultName.length > 40) { + defaultName = `${defaultName.slice(0, 19)}...${defaultName.slice(-19)}` } - return await makePack(structureFile, config, resourcePackStack, previewCont); + return defaultName; } /** @@ -791,6 +809,7 @@ function addDefaultConfig(config) { SPAWN_ANIMATION_LENGTH: 0.4, // in seconds WRONG_BLOCK_OVERLAY_COLOR: [1, 0, 0, 0.3], MATERIAL_LIST_LANGUAGE: "en_US", + PACK_NAME: undefined, PACK_ICON_BLOB: undefined, AUTHORS: [], DESCRIPTION: undefined, @@ -1266,6 +1285,7 @@ function stringifyWithFixedDecimals(value) { * @property {Number} SPAWN_ANIMATION_LENGTH Length of each individual block's spawn animation (seconds) * @property {Array} WRONG_BLOCK_OVERLAY_COLOR Clamped colour quartet * @property {String} MATERIAL_LIST_LANGUAGE The language code, as appearing in `texts/languages.json` + * @property {String|undefined} PACK_NAME The name of the completed pack; will default to the structure file names * @property {Blob} PACK_ICON_BLOB Blob for `pack_icon.png` * @property {Array} AUTHORS * @property {String|undefined} DESCRIPTION diff --git a/index.css b/index.css index 2e09a69..9e52d46 100644 --- a/index.css +++ b/index.css @@ -129,6 +129,9 @@ input[type="number"], input[type="text"], textarea { outline-width: thin; accent-color: auto; } +input[type="text"]::placeholder { + text-overflow: ellipsis; +} button:not(:disabled):hover, input[type="file"]:not(:disabled):hover::file-selector-button, select:not(:disabled):hover, .buttonlike:hover { background: #E8C8E8; } diff --git a/index.html b/index.html index 64b1b16..8c54077 100644 --- a/index.html +++ b/index.html @@ -77,6 +77,7 @@

HoloPrint

Metadata + diff --git a/index.js b/index.js index 70c4050..55db73c 100644 --- a/index.js +++ b/index.js @@ -37,6 +37,7 @@ let dropFileNotice; let generatePackForm; let generatePackFormSubmitButton; let structureFilesInput; +let packNameInput; let logger; let supabaseLogger; @@ -47,6 +48,8 @@ document.onEvent("DOMContentLoaded", async () => { generatePackForm = selectEl("#generatePackForm"); dropFileNotice = selectEl("#dropFileNotice"); structureFilesInput = generatePackForm.elements.namedItem("structureFiles"); + packNameInput = generatePackForm.elements.namedItem("packName"); + structureFilesInput.onEventAndNow("input", updatePackNameInputPlaceholder); if(location.search == "?loadFile") { window.launchQueue?.setConsumer(async launchParams => { @@ -142,26 +145,20 @@ async function handleInputFiles(files) { let resourcePacks = files.filter(file => file.name.endsWith(".mcpack")); for(let resourcePack of resourcePacks) { - let structureFile = await HoloPrint.extractStructureFileFromPack(resourcePack); - if(structureFile) { - structureFiles.push(structureFile); - } + let extractedStructureFiles = await HoloPrint.extractStructureFilesFromPack(resourcePack); + structureFiles.push(...extractedStructureFiles); } if(structureFiles.length) { let dataTransfer = new DataTransfer(); [...structureFilesInput.files, ...structureFiles].forEach(structureFile => dataTransfer.items.add(structureFile)); structureFilesInput.files = dataTransfer.files; } + updatePackNameInputPlaceholder(); } - -async function handleLaunchFile(file) { - if(!file.name.endsWith(".mcstructure")) { - console.error(`File is not a structure file: ${file.name}`); - return; - } - let pack = await makePack([file]); - return pack; +function updatePackNameInputPlaceholder() { + packNameInput.setAttribute("placeholder", HoloPrint.getDefaultPackName([...structureFilesInput.files])); } + async function temporarilyChangeText(el, text, duration = 2000) { let originalText = el.innerText; el.innerText = text; @@ -188,6 +185,7 @@ async function makePack(structureFiles, localResourcePacks) { TEXTURE_OUTLINE_ALPHA_DIFFERENCE_MODE: formData.get("textureOutlineAlphaDifferenceMode"), DO_SPAWN_ANIMATION: formData.get("spawnAnimationEnabled"), MATERIAL_LIST_LANGUAGE: formData.get("materialListLanguage"), + PACK_NAME: formData.get("packName") || undefined, PACK_ICON_BLOB: formData.get("packIcon").size? formData.get("packIcon") : undefined, AUTHORS: authors, DESCRIPTION: formData.get("description") || undefined