Updated atlas building tool, removed old files

This commit is contained in:
Lucas Dower 2023-09-03 22:51:29 +01:00
parent 4654ac90a0
commit 0ecedd4884
No known key found for this signature in database
GPG Key ID: B3EE6B8499593605
7 changed files with 1460 additions and 4916 deletions

5233
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,6 @@
"start": "webpack serve --config ./webpack.dev.js",
"dist": "webpack --config ./webpack.prod.js",
"atlas": "ts-node ./tools/build-atlas.ts",
"palette": "ts-node ./tools/build-palette.ts",
"headless": "ts-node ./tools/run-headless.ts",
"build": "tsc"
},
@ -39,11 +38,10 @@
"@types/varint": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^5.9.1",
"@typescript-eslint/parser": "^5.9.1",
"adm-zip": "^0.5.9",
"browserify-zlib": "^0.2.0",
"bvh-tree": "^1.0.1",
"chalk": "^4.1.2",
"copy-dir": "^1.3.0",
"commander": "^11.0.0",
"css-loader": "^6.7.3",
"eslint": "^8.7.0",
"eslint-config-google": "^0.14.0",
@ -53,7 +51,6 @@
"hsv-rgb": "^1.0.0",
"html-webpack-plugin": "^5.5.0",
"i18next": "^22.4.14",
"images": "^3.2.3",
"jest": "^27.5.1",
"jpeg-js": "^0.4.4",
"json-loader": "^0.5.7",
@ -63,9 +60,8 @@
"prismarine-nbt": "^2.2.1",
"prompt": "^1.2.1",
"raw-loader": "^4.0.2",
"sharp": "^0.31.1",
"sharp": "^0.31.3",
"style-loader": "^3.3.1",
"tga": "^1.0.7",
"ts-jest": "^27.1.3",
"ts-loader": "^9.4.2",
"ts-node": "^10.1.0",

View File

@ -1,289 +0,0 @@
acacia_log
acacia_planks
acacia_wood
amethyst_block
ancient_debris
andesite
azalea_leaves
basalt
bedrock
birch_log
birch_planks
birch_wood
blackstone
black_concrete
black_concrete_powder
black_glazed_terracotta
black_terracotta
black_wool
blue_concrete
blue_concrete_powder
blue_glazed_terracotta
blue_ice
blue_terracotta
blue_wool
bone_block
bookshelf
brain_coral_block
bricks
brown_concrete
brown_concrete_powder
brown_glazed_terracotta
brown_mushroom_block
brown_terracotta
brown_wool
bubble_coral_block
budding_amethyst
calcite
cartography_table
chiseled_deepslate
chiseled_nether_bricks
chiseled_polished_blackstone
chiseled_quartz_block
chiseled_red_sandstone
chiseled_sandstone
chiseled_stone_bricks
clay
coal_block
coal_ore
coarse_dirt
cobbled_deepslate
cobblestone
copper_block
copper_ore
cracked_deepslate_bricks
cracked_deepslate_tiles
cracked_nether_bricks
cracked_polished_blackstone_bricks
cracked_stone_bricks
crafting_table
crimson_hyphae
crimson_planks
crimson_stem
crying_obsidian
cut_copper
cut_red_sandstone
cut_sandstone
cyan_concrete
cyan_concrete_powder
cyan_glazed_terracotta
cyan_terracotta
cyan_wool
dark_oak_log
dark_oak_planks
dark_oak_wood
dark_prismarine
dead_brain_coral_block
dead_bubble_coral_block
dead_fire_coral_block
dead_horn_coral_block
dead_tube_coral_block
deepslate
deepslate_bricks
deepslate_coal_ore
deepslate_copper_ore
deepslate_diamond_ore
deepslate_emerald_ore
deepslate_gold_ore
deepslate_iron_ore
deepslate_lapis_ore
deepslate_redstone_ore
deepslate_tiles
diamond_block
diamond_ore
diorite
dirt
dripstone_block
emerald_block
emerald_ore
end_stone
end_stone_bricks
exposed_copper
exposed_cut_copper
fire_coral_block
fletching_table
flowering_azalea_leaves
frosted_ice_0
frosted_ice_1
frosted_ice_2
frosted_ice_3
gilded_blackstone
glowstone
gold_block
gold_ore
granite
gravel
gray_concrete
gray_concrete_powder
gray_glazed_terracotta
gray_terracotta
gray_wool
green_concrete
green_concrete_powder
green_glazed_terracotta
green_terracotta
green_wool
hay_block
honeycomb_block
horn_coral_block
ice
iron_block
iron_ore
jungle_log
jungle_planks
jungle_wood
lapis_block
lapis_ore
light_blue_concrete
light_blue_concrete_powder
light_blue_glazed_terracotta
light_blue_terracotta
light_blue_wool
light_gray_concrete
light_gray_concrete_powder
light_gray_glazed_terracotta
light_gray_terracotta
light_gray_wool
lime_concrete
lime_concrete_powder
lime_glazed_terracotta
lime_terracotta
lime_wool
lodestone
magenta_concrete
magenta_concrete_powder
magenta_glazed_terracotta
magenta_terracotta
magenta_wool
magma_block
mangrove_log
mangrove_planks
mangrove_wood
melon
mossy_cobblestone
mossy_stone_bricks
moss_block
mud
muddy_mangrove_roots
mud_bricks
mushroom_stem
netherite_block
netherrack
nether_bricks
nether_gold_ore
nether_quartz_ore
nether_wart_block
note_block
oak_log
oak_planks
oak_wood
obsidian
ochre_froglight
orange_concrete
orange_concrete_powder
orange_glazed_terracotta
orange_terracotta
orange_wool
oxidized_copper
oxidized_cut_copper
packed_ice
packed_mud
pearlescent_froglight
pink_concrete
pink_concrete_powder
pink_glazed_terracotta
pink_terracotta
pink_wool
polished_andesite
polished_basalt
polished_blackstone
polished_blackstone_bricks
polished_deepslate
polished_diorite
polished_granite
prismarine
prismarine_bricks
purple_concrete
purple_concrete_powder
purple_glazed_terracotta
purple_terracotta
purple_wool
purpur_block
purpur_pillar
quartz_block
quartz_bricks
quartz_pillar
raw_copper_block
raw_gold_block
raw_iron_block
redstone_block
redstone_lamp
redstone_ore
red_concrete
red_concrete_powder
red_glazed_terracotta
red_mushroom_block
red_nether_bricks
red_sand
red_terracotta
red_wool
rooted_dirt
sand
sculk
sea_lantern
shroomlight
smithing_table
smooth_basalt
smooth_quartz
smooth_red_sandstone
smooth_sandstone
smooth_stone
snow_block
soul_sand
soul_soil
sponge
spruce_log
spruce_planks
spruce_wood
stone
stone_bricks
stripped_acacia_log
stripped_acacia_wood
stripped_birch_log
stripped_birch_wood
stripped_crimson_hyphae
stripped_crimson_stem
stripped_dark_oak_log
stripped_dark_oak_wood
stripped_jungle_log
stripped_jungle_wood
stripped_mangrove_log
stripped_mangrove_wood
stripped_oak_log
stripped_oak_wood
stripped_spruce_log
stripped_spruce_wood
stripped_warped_hyphae
stripped_warped_stem
target
terracotta
tube_coral_block
tuff
verdant_froglight
warped_hyphae
warped_planks
warped_stem
warped_wart_block
weathered_copper
weathered_cut_copper
wet_sponge
white_concrete
white_concrete_powder
white_glazed_terracotta
white_terracotta
white_wool
yellow_concrete
yellow_concrete_powder
yellow_glazed_terracotta
yellow_terracotta
yellow_wool

View File

@ -1,419 +1,288 @@
// import images from 'images';
// import path from 'path';
// import prompt from 'prompt';
import { program } from 'commander';
import fs from 'fs';
import path from 'path';
import sharp from 'sharp';
import { getAverageColour, getStandardDeviation } from './misc';
import { ASSERT } from '../src/util/error_util';
import { RGBAUtil } from '../src/colour';
// import { RGBA, RGBAUtil } from '../src/colour';
// import { AppUtil } from '../src/util';
// import { LOG, LOG_WARN, Logger } from '../src/util/log_util';
program
.argument('<textures_directory>', 'The directory to load the blocks texture files from (assets/minecraft/textures/block)')
.argument('<models_directory>', 'The directory to load the blocks model files from (assets/minecraft/models/block)')
.argument('<output_directory>', 'The directory to write the texture atlas files to')
.argument('<ignore_file_path>', 'Ignore file path')
// const AdmZip = require('adm-zip');
// const copydir = require('copy-dir');
program.parse();
// import { AppPaths, PathUtil } from '../src/util/path_util';
// import { log } from './logging';
// import { ASSERT_EXISTS, getAverageColour, getMinecraftDir, getStandardDeviation } from './misc';
const paths = {
textures: program.args[0],
models: program.args[1],
output: program.args[2],
ignore: program.args[3],
}
// const BLOCKS_DIR = PathUtil.join(AppPaths.Get.tools, '/blocks');
// const MODELS_DIR = PathUtil.join(AppPaths.Get.tools, '/models');
type FaceData<T> = {
up: T,
down: T,
north: T,
south: T,
east: T,
west: T,
}
// type TFaceData<T> = {
// up: T,
// down: T,
// north: T,
// south: T,
// east: T,
// west: T,
// }
// GO!
// 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[],
// };
const ignoreList = new Set(fs.readFileSync(paths.ignore, 'utf8').split(/\r?\n/));
// void async function main() {
// AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
// Logger.Get.enableLogToFile();
// Logger.Get.initLogFile('atlas');
// Load all models to use
const allModels = fs.readdirSync(paths.models);
const loadedModels = allModels
// Remove ignored models
.filter((modelFileName) => {
return !ignoreList.has(modelFileName);
})
// Get each models content
.map((modelFileName) => {
const modelFilePath = path.join(paths.models, modelFileName);
const fileContents = fs.readFileSync(modelFilePath, 'utf8');
const model = JSON.parse(fileContents);
// const minecraftDir = getMinecraftDir();
switch (model.parent) {
case 'minecraft:block/cube_column_horizontal':
return {
modelFileName: modelFileName,
up: model.textures.side,
down: model.textures.side,
north: model.textures.end,
south: model.textures.end,
east: model.textures.side,
west: model.textures.side,
};
case 'minecraft:block/cube_all':
return {
modelFileName: modelFileName,
up: model.textures.all,
down: model.textures.all,
north: model.textures.all,
south: model.textures.all,
east: model.textures.all,
west: model.textures.all,
};
case 'minecraft:block/cube_column':
return {
modelFileName: modelFileName,
up: model.textures.end,
down: model.textures.end,
north: model.textures.side,
south: model.textures.side,
east: model.textures.side,
west: model.textures.side,
};
case 'minecraft:block/cube_bottom_top':
return {
modelFileName: modelFileName,
up: model.textures.top,
down: model.textures.bottom,
north: model.textures.side,
south: model.textures.side,
east: model.textures.side,
west: model.textures.side,
};
case 'minecraft:block/cube':
return {
modelFileName: modelFileName,
up: model.textures.up,
down: model.textures.down,
north: model.textures.north,
south: model.textures.south,
east: model.textures.east,
west: model.textures.west,
};
case 'minecraft:block/template_single_face':
return {
modelFileName: modelFileName,
up: model.textures.texture,
down: model.textures.texture,
north: model.textures.texture,
south: model.textures.texture,
east: model.textures.texture,
west: model.textures.texture,
};
case 'minecraft:block/template_glazed_terracotta':
return {
modelFileName: modelFileName,
up: model.textures.pattern,
down: model.textures.pattern,
north: model.textures.pattern,
south: model.textures.pattern,
east: model.textures.pattern,
west: model.textures.pattern,
};
case 'minecraft:block/leaves':
return {
modelFileName: modelFileName,
up: model.textures.all,
down: model.textures.all,
north: model.textures.all,
south: model.textures.all,
east: model.textures.all,
west: model.textures.all,
};
default:
return null;
}
}, [])
.filter((entry) => {
return entry !== null;
});
// // Clean up temporary data from previous use
// {
// fs.rmSync(BLOCKS_DIR, { recursive: true, force: true });
// fs.rmSync(MODELS_DIR, { recursive: true, force: true });
// }
const allTextures = new Set<string>();
loadedModels.forEach((model) => {
allTextures.add(model?.up);
allTextures.add(model?.down);
allTextures.add(model?.east);
allTextures.add(model?.west);
allTextures.add(model?.north);
allTextures.add(model?.south);
});
// // 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 atlasSize = Math.ceil(Math.sqrt(allTextures.size));
let nextAtlasColumn = 0;
let nextAtlasRow = 0;
// const isResponseYes = ['Y', 'y'].includes(permission as string);
// if (!isResponseYes) {
// process.exit(0);
// }
// }
const textureData = Array.from(allTextures)
.map(async (texture) => {
const shortName = texture.split('/')[1]; // Eww
const texturePath = path.join(paths.textures, shortName + '.png');
// ASSERT_EXISTS(minecraftDir);
const image = sharp(texturePath);
const imageData = Uint8ClampedArray.from(await image.raw().ensureAlpha(1.0).toBuffer()); // 16 x 16 x 4
// // Prompt user to pick a version
// let chosenVersionName: string;
// let chosenVersionDir: string;
// {
// const versionsDir = PathUtil.join(minecraftDir, '/versions');
// ASSERT_EXISTS(versionsDir);
return {
textureName: texture,
texturePath: texturePath,
image: image,
imageData: imageData,
}
});
// 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}`);
// });
// }
type ArrayElement<ArrayType extends readonly unknown[]> =
ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
// // 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;
// },
// },
// },
// });
Promise.all(textureData)
.then(async (res) => {
const tmp = res
.sort((a, b) => {
return a.textureName < b.textureName ? -1 : 1;
})
.map(async (texture) => {
const averageColour = getAverageColour(texture.imageData);
const standardDeviation = getStandardDeviation(texture.imageData, averageColour);
// chosenVersionName = versions[(<number>packChoice) - 1].file;
// chosenVersionDir = PathUtil.join(versionsDir, chosenVersionName);
// }
const atlasColumn = nextAtlasColumn;
const atlasRow = nextAtlasRow;
// // Get vanilla models and textures
// {
// const jarName = `${chosenVersionName}.jar`;
// const jarDir = PathUtil.join(chosenVersionDir, jarName);
// ASSERT_EXISTS(jarDir);
++nextAtlasColumn;
if (nextAtlasColumn >= atlasSize) {
++nextAtlasRow;
nextAtlasColumn = 0;
}
// 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}'`);
// }
return {
textureName: texture.textureName,
texturePath: texture.texturePath,
atlasColumn: atlasColumn,
atlasRow: atlasRow,
colour: averageColour,
std: standardDeviation,
};
});
// // Prompt user to pick a resource pack
// let chosenResourcePackDir: string | undefined;
// {
// const resourcePacksDir = PathUtil.join(minecraftDir, '/resourcepacks');
// ASSERT_EXISTS(resourcePacksDir);
Promise.all(tmp)
.then(async (data) => {
const textureMap = new Map<string, Omit<ArrayElement<typeof data>, 'textureName' | 'texturePath'>>();
data.forEach((texture) => {
textureMap.set(texture.textureName, {
atlasColumn: texture.atlasColumn,
atlasRow: texture.atlasRow,
colour: texture.colour,
std: texture.std,
});
});
// const resourcePacks = fs.readdirSync(resourcePacksDir);
// {
// log('Option', `1) Vanilla`);
// resourcePacks.forEach((resourcePack, index) => {
// log('Option', `${index + 2}) ${resourcePack}`);
// });
// }
const baseImage = await sharp({
create: {
width: atlasSize * 16 * 3,
height: atlasSize * 16 * 3,
channels: 4,
background: { r: 255, g: 255, b: 255, alpha: 0.0 },
}
});
// 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;
// },
// },
// },
// });
const compositeData: sharp.OverlayOptions[] = [];
data.forEach((x) => {
for (let i = 0; i < 3; ++i) {
for (let j = 0; j < 3; ++j) {
compositeData.push({
input: x.texturePath,
blend: 'over',
left: (x.atlasColumn * 16) * 3 + 16 * i,
top: (x.atlasRow * 16) * 3 + 16 * j,
});
}
}
})
// chosenResourcePackDir = (<number>resourcePackChoiceIndex) === 1 ? undefined : resourcePacks[(<number>resourcePackChoiceIndex) - 2];
// }
baseImage.composite(compositeData)
.toFile(path.join(paths.output, 'atlas.png'))
.then((res) => {
console.log('Done!');
})
.catch((err) => {
console.error(err);
});
// // 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 blocks = loadedModels.map((model) => {
ASSERT(model !== null);
// const blockTexturesSrc = PathUtil.join(chosenResourcePackDir, 'assets/minecraft/textures/block');
// const blockTexturesDst = BLOCKS_DIR;
const faces = {
up: model.up,
down: model.down,
north: model.north,
south: model.south,
east: model.east,
west: model.west,
};
// 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 faceColours = Object.values(faces).map((texture) => {
const textureData = textureMap.get(texture);
ASSERT(textureData !== undefined);
return textureData.colour;
});
// 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`);
// }
return {
name: 'minecraft:' + model.modelFileName.split('.')[0],
faces: faces,
colour: RGBAUtil.average(...faceColours),
}
});
// // 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}'`);
// }
// }
// }
console.log(textureMap);
// const usedTextures = new Set<string>();
// const usedModels: Array<{ name: string, faces: TFaceData<string> }> = [];
const textures: Record<any, any> = {};
textureMap.forEach((value, key) => {
textures[key] = value;
});
// // Load all models to use
// {
// const allModels = fs.readdirSync(MODELS_DIR);
// log('Info', `Found ${allModels.length} models in '${MODELS_DIR}'`);
const atlasFile = {
formatVersion: 3,
atlasSize: atlasSize,
blocks: blocks,
textures: textures,
}
// allModels.forEach((modelRelDir, index) => {
// const modelAbsDir = PathUtil.join(MODELS_DIR, modelRelDir);
// const parsed = path.parse(modelAbsDir);
fs.writeFileSync(path.join(paths.output, 'atlas.atlas'), JSON.stringify(atlasFile, null, 4));
});
// 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');
});

View File

@ -1,68 +0,0 @@
// import fs from 'fs';
// import path from 'path';
// import prompt from 'prompt';
// import { Palette } from '../src/palette';
// import { AppPaths, PathUtil } from '../src/util/path_util';
// import { log } from './logging';
// const PALETTE_NAME_REGEX = /^[a-zA-Z\-]+$/;
// void async function main() {
// AppPaths.Get.setBaseDir(PathUtil.join(__dirname, '../..'));
// log('Info', 'Creating a new palette...');
// const paletteBlocksDir = path.join(AppPaths.Get.tools, './new-palette-blocks.txt');
// if (!fs.existsSync(paletteBlocksDir)) {
// log('Failure', 'Could not find /tools/new-palette-blocks.txt');
// return;
// }
// log('Success', 'Found list of blocks to use in /tools/new-palette-blocks.txt');
// let blocksToUse: string[] = fs.readFileSync(paletteBlocksDir, 'utf8').replace(/\r/g, '').split('\n');
// blocksToUse = blocksToUse.filter((block) => {
// return block.length !== 0;
// });
// if (blocksToUse.length === 0) {
// log('Failure', 'No blocks listed for palette');
// log('Info', 'List the blocks you want from /tools/all-supported-blocks.txt ');
// return;
// }
// log('Info', `Found ${blocksToUse.length} blocks to use`);
// const schema: prompt.Schema = {
// properties: {
// paletteName: {
// pattern: PALETTE_NAME_REGEX,
// description: 'What do you want to call this block palette? (e.g. my-block-palette)',
// message: 'Must be only letters or dash',
// required: true,
// },
// },
// };
// const promptUser = await prompt.get(schema);
// log('Info', 'Creating palette...');
// const palette = Palette.create();
// if (palette === undefined) {
// log('Failure', 'Invalid palette name');
// return;
// }
// log('Info', 'Adding blocks to palette...');
// for (const blockNames of blocksToUse) {
// palette.add(blockNames);
// }
// log('Info', 'Saving palette...');
// const success = palette.save(promptUser.paletteName as string);
// if (success) {
// log('Success', 'Palette saved.');
// } else {
// log('Failure', 'Could not save palette.');
// }
// }();
console.log('Unimplemented');

View File

@ -1,61 +0,0 @@
import chalk from 'chalk';
export type TLogStyle = 'None' | 'Option' | 'Prompt' | 'Info' | 'Warning' | 'Failure' | 'Success';
export function log(style: TLogStyle, message: string) {
switch (style) {
case 'None': {
/* eslint-disable-next-line no-console */
console.log(` ${chalk.whiteBright(message)}`);
break;
}
case 'Prompt': {
/* eslint-disable-next-line no-console */
console.log(`${chalk.blue.inverse('INFO')} ${chalk.blue(message)}`);
break;
}
case 'Option': {
/* eslint-disable-next-line no-console */
console.log(`${chalk.magenta(message)}`);
break;
}
case 'Info': {
/* eslint-disable-next-line no-console */
console.log(`${chalk.white(message)}`);
break;
}
case 'Warning': {
/* eslint-disable-next-line no-console */
console.log(`${chalk.yellow.inverse('WARN')} ${chalk.yellow(message)}`);
break;
}
case 'Failure': {
/* eslint-disable-next-line no-console */
console.log(`${chalk.red.inverse('UHOH')} ${chalk.red(message)}`);
break;
}
case 'Success': {
/* eslint-disable-next-line no-console */
console.log(`${chalk.green.inverse(' OK ')} ${chalk.green(message)}`);
break;
}
}
}
/**
* Conditionally log to the console
* @param condition The condition to evaluate
* @param trueMessage The message to print if the condition is true
* @param falseMessage The message to print if the condition is false
* @param exitOnFalse Should the process exit if the condition is false
*/
export function clog(condition: boolean, trueMessage: string, falseMessage: string, exitOnFalse: boolean = true) {
if (condition) {
log('Success', trueMessage);
} else {
log('Failure', falseMessage);
if (exitOnFalse) {
process.exit(1);
}
}
}

View File

@ -1,29 +1,15 @@
import path from 'path';
import prompt from 'prompt';
import { RGBA } from '../src/colour';
import { clog, log } from './logging';
export const ASSERT = (condition: boolean, onFailMessage: string) => {
if (!condition) {
log('Failure', onFailMessage);
process.exit(0);
}
};
type PNG = {};
export function getAverageColour(image: PNG): RGBA {
/*
export function getAverageColour(image: Uint8ClampedArray): RGBA {
let r = 0;
let g = 0;
let b = 0;
let a = 0;
let weight = 0;
for (let x = 0; x < image.width; ++x) {
for (let y = 0; y < image.height; ++y) {
const index = 4 * (image.width * y + x);
const rgba = image.data.slice(index, index + 4);
for (let x = 0; x < 16; ++x) {
for (let y = 0; y < 16; ++y) {
const index = 4 * (16 * y + x);
const rgba = image.slice(index, index + 4);
const alpha = rgba[3] / 255;
r += (rgba[0] / 255) * alpha;
g += (rgba[1] / 255) * alpha;
@ -32,27 +18,22 @@ export function getAverageColour(image: PNG): RGBA {
weight += alpha;
}
}
const numPixels = image.width * image.height;
const numPixels = 16 * 16;
return {
r: r / weight,
g: g / weight,
b: b / weight,
a: a / numPixels,
};
*/
return { r: 0, g: 0, b: 0, a: 0 };
}
export function getStandardDeviation(image: PNG, average: RGBA): number {
return 0; // TODO Unimplemented
/*
export function getStandardDeviation(image: Uint8ClampedArray, average: RGBA): number {
let squaredDist = 0.0;
let weight = 0.0;
for (let x = 0; x < image.width; ++x) {
for (let y = 0; y < image.height; ++y) {
const index = 4 * (image.width * y + x);
const rgba = image.data.slice(index, index + 4);
for (let x = 0; x < 16; ++x) {
for (let y = 0; y < 16; ++y) {
const index = 4 * (16 * y + x);
const rgba = image.slice(index, index + 4);
const alpha = rgba[3] / 255;
weight += alpha;
const r = (rgba[0] / 255) * alpha;
@ -62,35 +43,4 @@ export function getStandardDeviation(image: PNG, average: RGBA): number {
}
}
return Math.sqrt(squaredDist / weight);
*/
}
export async function getPermission() {
const directory = getMinecraftDir();
log('Prompt', `This script requires files inside of ${directory}`);
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 responseYes = ['Y', 'y'].includes(permission as string);
if (!responseYes) {
process.exit(0);
}
}
export function getMinecraftDir(): string {
switch (process.platform) {
case 'darwin': // MacOS
return path.join(process.env.HOME!, './Library/Application Support/minecraft');
case 'win32': // Windows
return path.join(process.env.APPDATA!, './.minecraft');
default:
return path.join(require('os').homedir(), '/.minecraft');
}
}