mirror of
https://github.com/LucasDower/ObjToSchematic.git
synced 2024-12-03 02:39:59 +08:00
420 lines
18 KiB
TypeScript
420 lines
18 KiB
TypeScript
// import images from 'images';
|
|
// import path from 'path';
|
|
// import prompt from 'prompt';
|
|
|
|
// import { RGBA, RGBAUtil } from '../src/colour';
|
|
// import { AppUtil } from '../src/util';
|
|
// import { LOG, LOG_WARN, Logger } from '../src/util/log_util';
|
|
|
|
// const AdmZip = require('adm-zip');
|
|
// const copydir = require('copy-dir');
|
|
|
|
// import { AppPaths, PathUtil } from '../src/util/path_util';
|
|
// import { log } from './logging';
|
|
// import { ASSERT_EXISTS, getAverageColour, getMinecraftDir, getStandardDeviation } from './misc';
|
|
|
|
// const BLOCKS_DIR = PathUtil.join(AppPaths.Get.tools, '/blocks');
|
|
// const MODELS_DIR = PathUtil.join(AppPaths.Get.tools, '/models');
|
|
|
|
// type TFaceData<T> = {
|
|
// up: T,
|
|
// down: T,
|
|
// north: T,
|
|
// south: T,
|
|
// east: T,
|
|
// west: T,
|
|
// }
|
|
|
|
// export type TAtlasVersion = {
|
|
// formatVersion: 3,
|
|
// atlasSize: number,
|
|
// blocks: Array<{ name: string, faces: TFaceData<string>, colour: RGBA }>,
|
|
// textures: { [texture: string]: { atlasColumn: number, atlasRow: number, colour: RGBA, std: number } },
|
|
// supportedBlockNames: string[],
|
|
// };
|
|
|
|
// void async function main() {
|
|
// AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
|
|
// Logger.Get.enableLogToFile();
|
|
// Logger.Get.initLogFile('atlas');
|
|
|
|
// const minecraftDir = getMinecraftDir();
|
|
|
|
// // Clean up temporary data from previous use
|
|
// {
|
|
// fs.rmSync(BLOCKS_DIR, { recursive: true, force: true });
|
|
// fs.rmSync(MODELS_DIR, { recursive: true, force: true });
|
|
// }
|
|
|
|
// // Ask for permission to access Minecraft dir
|
|
// {
|
|
// log('Prompt', `This script requires files inside '${minecraftDir}'`);
|
|
|
|
// const { permission } = await prompt.get({
|
|
// properties: {
|
|
// permission: {
|
|
// pattern: /^[YyNn]$/,
|
|
// description: 'Do you give permission to access these files? (y/n)',
|
|
// message: 'Response must be Y or N',
|
|
// required: true,
|
|
// },
|
|
// },
|
|
// });
|
|
|
|
// const isResponseYes = ['Y', 'y'].includes(permission as string);
|
|
// if (!isResponseYes) {
|
|
// process.exit(0);
|
|
// }
|
|
// }
|
|
|
|
// ASSERT_EXISTS(minecraftDir);
|
|
|
|
// // Prompt user to pick a version
|
|
// let chosenVersionName: string;
|
|
// let chosenVersionDir: string;
|
|
// {
|
|
// const versionsDir = PathUtil.join(minecraftDir, '/versions');
|
|
// ASSERT_EXISTS(versionsDir);
|
|
|
|
// const versions = fs.readdirSync(versionsDir)
|
|
// .filter((file) => fs.lstatSync(PathUtil.join(versionsDir, file)).isDirectory())
|
|
// .map((file) => ({ file, birthtime: fs.lstatSync(PathUtil.join(versionsDir, file)).birthtime }))
|
|
// .sort((a, b) => b.birthtime.getTime() - a.birthtime.getTime());
|
|
// {
|
|
// versions.forEach((version, index) => {
|
|
// log('Option', `${index + 1}) ${version.file}`);
|
|
// });
|
|
// }
|
|
|
|
// // Prompt user to pick a version
|
|
// const { packChoice } = await prompt.get({
|
|
// properties: {
|
|
// packChoice: {
|
|
// description: `Which version do you want to build an atlas for? (1-${versions.length})`,
|
|
// message: `Response must be between 1 and ${versions.length}`,
|
|
// required: true,
|
|
// conform: (value) => {
|
|
// return value >= 1 && value <= versions.length;
|
|
// },
|
|
// },
|
|
// },
|
|
// });
|
|
|
|
// chosenVersionName = versions[(<number>packChoice) - 1].file;
|
|
// chosenVersionDir = PathUtil.join(versionsDir, chosenVersionName);
|
|
// }
|
|
|
|
// // Get vanilla models and textures
|
|
// {
|
|
// const jarName = `${chosenVersionName}.jar`;
|
|
// const jarDir = PathUtil.join(chosenVersionDir, jarName);
|
|
// ASSERT_EXISTS(jarDir);
|
|
|
|
// log('Info', `Upzipping '${jarDir}'...`);
|
|
// {
|
|
// const zip = new AdmZip(jarDir);
|
|
// const zipEntries = zip.getEntries();
|
|
// zipEntries.forEach((zipEntry: any) => {
|
|
// if (zipEntry.entryName.startsWith('assets/minecraft/textures/block')) {
|
|
// zip.extractEntryTo(zipEntry.entryName, BLOCKS_DIR, false, true);
|
|
// } else if (zipEntry.entryName.startsWith('assets/minecraft/models/block')) {
|
|
// zip.extractEntryTo(zipEntry.entryName, MODELS_DIR, false, true);
|
|
// }
|
|
// });
|
|
// }
|
|
// log('Success', `Extracted Vanilla models to '${MODELS_DIR}'`);
|
|
// log('Success', `Extracted Vanilla textures to '${BLOCKS_DIR}'`);
|
|
// }
|
|
|
|
// // Prompt user to pick a resource pack
|
|
// let chosenResourcePackDir: string | undefined;
|
|
// {
|
|
// const resourcePacksDir = PathUtil.join(minecraftDir, '/resourcepacks');
|
|
// ASSERT_EXISTS(resourcePacksDir);
|
|
|
|
// const resourcePacks = fs.readdirSync(resourcePacksDir);
|
|
// {
|
|
// log('Option', `1) Vanilla`);
|
|
// resourcePacks.forEach((resourcePack, index) => {
|
|
// log('Option', `${index + 2}) ${resourcePack}`);
|
|
// });
|
|
// }
|
|
|
|
// const { resourcePackChoiceIndex } = await prompt.get({
|
|
// properties: {
|
|
// packChoice: {
|
|
// description: `Which resource pack do you want to build an atlas for? (1-${resourcePacks.length + 1})`,
|
|
// message: `Response must be between 1 and ${resourcePacks.length + 1}`,
|
|
// required: true,
|
|
// conform: (value) => {
|
|
// return value >= 1 && value <= resourcePacks.length + 1;
|
|
// },
|
|
// },
|
|
// },
|
|
// });
|
|
|
|
// chosenResourcePackDir = (<number>resourcePackChoiceIndex) === 1 ? undefined : resourcePacks[(<number>resourcePackChoiceIndex) - 2];
|
|
// }
|
|
|
|
// // Get resource pack textures
|
|
// if (chosenResourcePackDir !== undefined) {
|
|
// log('Warning', 'Using non-16x16 texture packs is not supported and will result in undefined behaviour');
|
|
// {
|
|
// if (fs.lstatSync(chosenResourcePackDir).isDirectory()) {
|
|
// log('Info', `Resource pack '${chosenResourcePackDir}' is a directory`);
|
|
|
|
// const blockTexturesSrc = PathUtil.join(chosenResourcePackDir, 'assets/minecraft/textures/block');
|
|
// const blockTexturesDst = BLOCKS_DIR;
|
|
|
|
// log('Info', `Copying ${blockTexturesSrc} to ${blockTexturesDst}...`);
|
|
// copydir(blockTexturesSrc, blockTexturesDst, {
|
|
// utimes: true,
|
|
// mode: true,
|
|
// cover: true,
|
|
// });
|
|
// } else {
|
|
// log('Info', `Resource pack '${chosenResourcePackDir}' is not a directory, expecting to be a .zip`);
|
|
|
|
// const zip = new AdmZip(chosenResourcePackDir);
|
|
// const zipEntries = zip.getEntries();
|
|
// zipEntries.forEach((zipEntry: any) => {
|
|
// if (zipEntry.entryName.startsWith('assets/minecraft/textures/block')) {
|
|
// zip.extractEntryTo(zipEntry.entryName, BLOCKS_DIR, false, true);
|
|
// }
|
|
// });
|
|
// }
|
|
// }
|
|
// log('Success', `Copied block textures successfully`);
|
|
// }
|
|
|
|
// // Load the ignore list
|
|
// let ignoreList: Array<string> = [];
|
|
// {
|
|
// log('Info', 'Loading ignore list...');
|
|
// {
|
|
// const ignoreListPath = PathUtil.join(AppPaths.Get.tools, './models-ignore-list.txt');
|
|
// if (fs.existsSync(ignoreListPath)) {
|
|
// log('Success', `Found ignore list in '${ignoreListPath}'`);
|
|
// ignoreList = fs.readFileSync(ignoreListPath, 'utf-8').replace(/\r/g, '').split('\n');
|
|
// log('Info', `Found ${ignoreList.length} blocks in ignore list`);
|
|
// } else {
|
|
// log('Warning', `Could not find ignore list '${ignoreListPath}'`);
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// const usedTextures = new Set<string>();
|
|
// const usedModels: Array<{ name: string, faces: TFaceData<string> }> = [];
|
|
|
|
// // Load all models to use
|
|
// {
|
|
// const allModels = fs.readdirSync(MODELS_DIR);
|
|
// log('Info', `Found ${allModels.length} models in '${MODELS_DIR}'`);
|
|
|
|
// allModels.forEach((modelRelDir, index) => {
|
|
// const modelAbsDir = PathUtil.join(MODELS_DIR, modelRelDir);
|
|
// const parsed = path.parse(modelAbsDir);
|
|
|
|
// if (parsed.ext !== '.json' || ignoreList.includes(parsed.base)) {
|
|
// return;
|
|
// }
|
|
|
|
// const fileData = fs.readFileSync(modelAbsDir, 'utf8');
|
|
// const modelData = JSON.parse(fileData);
|
|
|
|
// const faceData: TFaceData<string> | undefined = (() => {
|
|
// switch (modelData.parent) {
|
|
// case 'minecraft:block/cube_column_horizontal':
|
|
// return {
|
|
// up: modelData.textures.side,
|
|
// down: modelData.textures.side,
|
|
// north: modelData.textures.end,
|
|
// south: modelData.textures.end,
|
|
// east: modelData.textures.side,
|
|
// west: modelData.textures.side,
|
|
// };
|
|
// case 'minecraft:block/cube_all':
|
|
// return {
|
|
// up: modelData.textures.all,
|
|
// down: modelData.textures.all,
|
|
// north: modelData.textures.all,
|
|
// south: modelData.textures.all,
|
|
// east: modelData.textures.all,
|
|
// west: modelData.textures.all,
|
|
// };
|
|
// case 'minecraft:block/cube_column':
|
|
// return {
|
|
// up: modelData.textures.end,
|
|
// down: modelData.textures.end,
|
|
// north: modelData.textures.side,
|
|
// south: modelData.textures.side,
|
|
// east: modelData.textures.side,
|
|
// west: modelData.textures.side,
|
|
// };
|
|
// case 'minecraft:block/cube_bottom_top':
|
|
// return {
|
|
// up: modelData.textures.top,
|
|
// down: modelData.textures.bottom,
|
|
// north: modelData.textures.side,
|
|
// south: modelData.textures.side,
|
|
// east: modelData.textures.side,
|
|
// west: modelData.textures.side,
|
|
// };
|
|
// case 'minecraft:block/cube':
|
|
// return {
|
|
// up: modelData.textures.up,
|
|
// down: modelData.textures.down,
|
|
// north: modelData.textures.north,
|
|
// south: modelData.textures.south,
|
|
// east: modelData.textures.east,
|
|
// west: modelData.textures.west,
|
|
// };
|
|
// case 'minecraft:block/template_single_face':
|
|
// return {
|
|
// up: modelData.textures.texture,
|
|
// down: modelData.textures.texture,
|
|
// north: modelData.textures.texture,
|
|
// south: modelData.textures.texture,
|
|
// east: modelData.textures.texture,
|
|
// west: modelData.textures.texture,
|
|
// };
|
|
// case 'minecraft:block/template_glazed_terracotta':
|
|
// return {
|
|
// up: modelData.textures.pattern,
|
|
// down: modelData.textures.pattern,
|
|
// north: modelData.textures.pattern,
|
|
// south: modelData.textures.pattern,
|
|
// east: modelData.textures.pattern,
|
|
// west: modelData.textures.pattern,
|
|
// };
|
|
// case 'minecraft:block/leaves':
|
|
// return {
|
|
// up: modelData.textures.all,
|
|
// down: modelData.textures.all,
|
|
// north: modelData.textures.all,
|
|
// south: modelData.textures.all,
|
|
// east: modelData.textures.all,
|
|
// west: modelData.textures.all,
|
|
// };
|
|
// }
|
|
// })();
|
|
|
|
// // Debug logging to file
|
|
// if (faceData === undefined) {
|
|
// LOG_WARN(`Could not parse '${parsed.base}'`);
|
|
// return;
|
|
// } else {
|
|
// LOG(`Parsed '${parsed.base}'`);
|
|
// }
|
|
|
|
// // Check that the textures that this model uses can be found
|
|
// Object.values(faceData).forEach((texture) => {
|
|
// const textureBaseName = texture.split('/')[1] + '.png';
|
|
// const textureAbsDir = PathUtil.join(BLOCKS_DIR, textureBaseName);
|
|
|
|
// if (fs.existsSync(textureAbsDir)) {
|
|
// LOG(`Found '${textureAbsDir}'`);
|
|
// } else {
|
|
// log('Warning', `'${parsed.base}' uses texture '${texture}' but the texture file could not be found at '${textureAbsDir}'`);
|
|
// return;
|
|
// }
|
|
// });
|
|
|
|
// // Update usedTextures and usedModels
|
|
// Object.values(faceData).forEach((texture) => {
|
|
// usedTextures.add(texture);
|
|
// });
|
|
// usedModels.push({
|
|
// name: parsed.name,
|
|
// faces: faceData,
|
|
// });
|
|
// });
|
|
|
|
// LOG('All Textures', usedTextures);
|
|
// LOG('All Models', usedModels);
|
|
// log('Info', `Found ${usedModels.length} models to use`);
|
|
|
|
// // Prompt user for an atlas name
|
|
// const { atlasName } = await prompt.get({
|
|
// properties: {
|
|
// atlasName: {
|
|
// pattern: /^[a-zA-Z\-]+$/,
|
|
// description: 'What do you want to call this texture atlas?',
|
|
// message: 'Name must only be letters or dash',
|
|
// required: true,
|
|
// },
|
|
// },
|
|
// });
|
|
|
|
// // Create atlas texture file
|
|
// const textureDetails: { [texture: string]: { atlasColumn: number, atlasRow: number, colour: RGBA, std: number } } = {};
|
|
// const atlasSize = Math.ceil(Math.sqrt(usedTextures.size));
|
|
// {
|
|
// const atlasWidth = atlasSize * 16;
|
|
|
|
// let offsetX = 0;
|
|
// let offsetY = 0;
|
|
// const outputImage = images(atlasWidth * 3, atlasWidth * 3);
|
|
|
|
// usedTextures.forEach((texture) => {
|
|
// const shortName = texture.split('/')[1]; // Eww
|
|
// const absolutePath = path.join(BLOCKS_DIR, shortName + '.png');
|
|
// const fileData = fs.readFileSync(absolutePath);
|
|
// //const pngData = PNG.sync.read(fileData);
|
|
// const image = images(absolutePath);
|
|
|
|
// for (let x = 0; x < 3; ++x) {
|
|
// for (let y = 0; y < 3; ++y) {
|
|
// outputImage.draw(image, 16 * (3 * offsetX + x), 16 * (3 * offsetY + y));
|
|
// }
|
|
// }
|
|
|
|
// // TODO Unimplemented
|
|
// /*
|
|
// const average = getAverageColour(pngData);
|
|
// textureDetails[texture] = {
|
|
// atlasColumn: offsetX,
|
|
// atlasRow: offsetY,
|
|
// colour: average,
|
|
// std: getStandardDeviation(pngData, average),
|
|
// };
|
|
// */
|
|
|
|
// ++offsetX;
|
|
// if (offsetX >= atlasSize) {
|
|
// ++offsetY;
|
|
// offsetX = 0;
|
|
// }
|
|
// });
|
|
|
|
// const atlasDir = PathUtil.join(AppPaths.Get.atlases, `./${atlasName}.png`);
|
|
// outputImage.save(atlasDir);
|
|
// }
|
|
|
|
// const modelDetails = new Array<{ name: string, faces: TFaceData<string>, colour: RGBA }>();
|
|
// {
|
|
// usedModels.forEach((model) => {
|
|
// const faceColours = Object.values(model.faces)
|
|
// .map((face) => textureDetails[face]!.colour);
|
|
|
|
// modelDetails.push({
|
|
// name: AppUtil.Text.namespaceBlock(model.name),
|
|
// faces: model.faces,
|
|
// colour: RGBAUtil.average(...faceColours),
|
|
// });
|
|
// });
|
|
// }
|
|
|
|
// const toExport: TAtlasVersion = {
|
|
// formatVersion: 3,
|
|
// atlasSize: atlasSize,
|
|
// blocks: modelDetails,
|
|
// textures: textureDetails,
|
|
// supportedBlockNames: modelDetails.map((model) => model.name),
|
|
// };
|
|
|
|
// fs.writeFileSync(path.join(AppPaths.Get.atlases, `./${atlasName}.atlas`), JSON.stringify(toExport, null, 4));
|
|
// }
|
|
// }();
|
|
console.log('Unimplemented');
|