Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | 1x 1x 1x 1x 1x 1x 1x 1x | import Path from "path";
import pngSize from "lib/helpers/pngSize";
import { sliceIndexedImage, toIndex } from "shared/lib/tiles/indexedImage";
import { readFileToIndexedImage } from "lib/tiles/readFileToTiles";
import { Static, TSchema } from "@sinclair/typebox";
import { Value } from "@sinclair/typebox/value";
import { readJson } from "lib/helpers/fs/readJson";
export type AssetFolder =
"backgrounds" | "fonts" | "music" | "sprites" | "sounds";
export const potentialAssetFolders = async (
filename: string,
): Promise<AssetFolder[]> => {
const ext = Path.extname(filename.toLowerCase());
if (ext === ".uge" || ext === ".mod") {
return ["music"];
}
if (ext === ".wav" || ext === ".vgm" || ext === ".sav") {
return ["sounds"];
}
if (ext !== ".png") {
return [];
}
const folders: AssetFolder[] = [];
const size = await pngSize(filename);
if (!size || !size.width || !size.height) {
return [];
}
if (size.width % 8 !== 0 && size.height % 8 !== 0) {
// Images must be multiples of 8 in dimension
return [];
}
if (size.width > 2040 || size.height > 2040) {
// Image is too large
return [];
}
const imageData = await readFileToIndexedImage(filename, (r, g, b) => {
// Blue divider
if (b >= 200 && g < 20) {
return 0;
}
// Green or Magenta transparent color
if ((g > 249 && r < 180 && b < 20) || (r > 249 && b > 249)) {
return 0;
}
return 1;
});
let hasTransparency = false;
for (let i = 0; i < imageData.data.length; i++) {
if (!imageData.data[i]) {
hasTransparency = true;
break;
}
}
// Is Sprite?
if (hasTransparency) {
folders.push("sprites");
}
// Is Background?
if (size.width >= 160 && size.height >= 144 && !hasTransparency) {
folders.push("backgrounds");
}
// Is Font?
if (size.width === 128) {
if (!hasTransparency) {
folders.push("fonts");
} else {
// Check each tile has either a pixel in top left or is fully transparent
const tilesX = size.width / 8;
const tilesY = size.height / 8;
let isFont = true;
for (let ty = 0; ty < tilesY && isFont; ty++) {
for (let tx = 0; tx < tilesX && isFont; tx++) {
const topLeftPixelIndex = toIndex(tx * 8, ty * 8, imageData);
const topLeftPixel = imageData.data[topLeftPixelIndex];
if (topLeftPixel) {
// Tile tx,ty is okay
continue;
}
// Check if tile is fully transparent
const tileData = sliceIndexedImage(imageData, tx * 8, ty * 8, 8, 8);
for (let i = 0; i < tileData.data.length; i++) {
if (tileData.data[i]) {
isFont = false;
break;
}
}
}
}
if (isFont) {
folders.push("fonts");
}
}
}
return folders;
};
export const getAssetResource = async <T extends TSchema>(
resourceType: T,
filename: string,
): Promise<Static<T> | undefined> => {
try {
const resourcePath = filename + ".gbsres";
const resourceData = await readJson(resourcePath);
return Value.Cast(resourceType, resourceData);
} catch {
console.log("No .gbsres exists yet for file: " + filename);
}
return undefined;
};
|