Skip to content

Commit

Permalink
upd: New dot material
Browse files Browse the repository at this point in the history
- Added WSS functions
- Added dots materials
  • Loading branch information
jasonjgardner committed Dec 23, 2022
1 parent 13b2fe1 commit 39cf83b
Show file tree
Hide file tree
Showing 16 changed files with 358 additions and 85 deletions.
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"test": "deno run --allow-read --allow-net --allow-env --allow-write ./src/mod.ts --DEPLOY true",
"build": "deno run --allow-read --allow-net --allow-env --allow-write ./src/mod.ts",
"art": "deno run --allow-read --allow-net --allow-env --allow-write ./src/mod.ts --ART_DIR ./px",
"serve": "deno run --allow-read --allow-net --allow-env --allow-write ./serve.ts"
"serve": "deno run --allow-read --allow-net --allow-env --allow-write --unstable --allow-ffi ./serve.ts"
},
"fmt": {
"files": {
Expand Down
9 changes: 5 additions & 4 deletions import_map.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
"canvas/": "https://deno.land/x/[email protected]/",
"culori": "https://deno.land/x/[email protected]/index.js",
"case/": "https://deno.land/x/[email protected]/",
"path/": "https://deno.land/[email protected]/path/",
"fs/": "https://deno.land/[email protected]/fs/",
"fmt/": "https://deno.land/[email protected]/fmt/",
"log/": "https://deno.land/[email protected]/log/",
"path/": "https://deno.land/[email protected]/path/",
"fs/": "https://deno.land/[email protected]/fs/",
"fmt/": "https://deno.land/[email protected]/fmt/",
"log/": "https://deno.land/[email protected]/log/",
"http/": "https://deno.land/[email protected]/http/",
"deno_markdown/": "https://deno.land/x/[email protected]/",
"@minecraft/server": "npm:@minecraft/server@^1.0.0-beta.release.1.19.40"
}
Expand Down
72 changes: 20 additions & 52 deletions serve.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import type { Axis, WssParams, WssState } from "./typings/types.ts";
import { decode } from "./src/components/ImagePrinter.ts";
import assemble from "./src/components/_assemble.ts";
import { serve } from "https://deno.land/[email protected]/http/server.ts";
import { join } from "https://deno.land/[email protected]/path/win32.ts";
import { ensureDir } from "https://deno.land/[email protected]/fs/mod.ts";
import { serve } from "http/server.ts";
import { join } from "path/win32.ts";
import { ensureDir } from "fs/mod.ts";

type SubscribeEvents =
| "AdditionalContentLoaded"
Expand Down Expand Up @@ -105,6 +103,7 @@ const state: WssState = {
offset: [8, 0, -16],
useAbsolutePosition: false,
axis: "x" as Axis,
enableBlockHistory: false,
blockHistory: [],
blockHistoryMaxLength: 500,
functionLog: join(Deno.cwd(), 'build', 'wss', 'functions')
Expand All @@ -131,9 +130,7 @@ const formatPosition = (x: number, y: number, z: number, offsetX?: number, offse
return useAbsolutePosition ? `${nx} ${ny} ${nz}` : `~${nx} ~${ny} ~${nz}`;
};

function getBlockLibrary(material: string, exclude?: string[]) {
return assemble(exclude).filter((b) => b.behaviorId.includes(material));
}


let connectionUpdateInterval: number | undefined;

Expand Down Expand Up @@ -185,6 +182,15 @@ async function processMessage(

// TODO: Add index help function

if (contents.startsWith("history/")) {
const steps = parseInt(contents.replace("history/", ""), 10);

state.blockHistory = [];
state.enableBlockHistory = steps > 0;
state.blockHistoryMaxLength = steps;
return;
}

// Live reload
if (contents.startsWith("lr/")) {
await watch(contents.replace("lr/", "").trim());
Expand All @@ -211,36 +217,6 @@ async function processMessage(
return;
}

if (contents.startsWith("axis/")) {
state.axis = contents.replace("axis/", "").trim() as Axis;
console.info("Axis set to %s", state.axis);
return;
}

if (contents.startsWith("https://") || contents.startsWith("http://")) {
console.info("Image URL updated to", contents);
updateContent(contents);
return;
}

if (contents.startsWith("material/")) {
const material = contents.replace("material/", "").replace(/\s+/g, "_");
state.material = material;
console.info("Material updated to", material);
return;
}

if (contents.startsWith("position/")) {
const position = contents.replace("position/", "").split(/[\s,]+/g, 3).map(
(v) => parseInt(v, 10),
).slice(0, 3) as [number, number, number];

state.offset = position;
state.useAbsolutePosition = true;
console.info("Position updated to %o", position);
return;
}

if (contents.startsWith("log/") && state.functionLog) {
const fn = contents.replace("log/", "").trim();

Expand Down Expand Up @@ -305,15 +281,7 @@ async function updateContent(imgUrl: string) {
}

state.updatePending = true;
const commands = await decode(
new URL(imgUrl),
getBlockLibrary(state.material ?? "plastic_50"),
state.offset ?? [0, 0, 0],
state.axis,
state.useAbsolutePosition === true,
);
requests.length = 0;
commands.map((c) => queueCommandRequest(c));

console.info("Queued %d commands", commands.length);
state.updatePending = false;
}
Expand Down Expand Up @@ -359,7 +327,7 @@ function queueCommandRequest(commandLine: string) {
result: false,
});

// sessionStorage.setItem(`request[${uuid}]`, content);
//sessionStorage.setItem(`request[${uuid}]`, content);

// Speed up rend rate based on number of requests
state.sendRate = requests.length > 100 ? 3 : 1;
Expand All @@ -376,7 +344,7 @@ async function onOpenHandler(socket: WebSocket) {

if (
(requestsCount === 0 && !state.updatePending) ||
requests[state.currentRequestIdx].result
requests[state.currentRequestIdx]?.result
) {
return;
}
Expand Down Expand Up @@ -413,7 +381,7 @@ function processCommandResponse(msg: { body: any, header: any }) {
return;
}

if (msg.body.statusMessage === "Block placed" && msg.body.position) {
if (state.enableBlockHistory === true && msg.body.statusMessage === "Block placed" && msg.body.position) {
const pos = Object.values(msg.body.position).map((v) => parseInt(`${v}`, 10)).slice(0, 3) as [number, number, number];
sessionStorage.setItem("lastBlock", JSON.stringify(pos));

Expand All @@ -435,9 +403,9 @@ function processCommandResponse(msg: { body: any, header: any }) {

delete requests[idx];

//const pendingRequest = requests.find((r) => r.uuid === msg.header.requestId);
// const pendingRequest = requests.find((r) => r.uuid === msg.header.requestId);

//const sessionData = sessionStorage.getItem(`request[${msg.body.requestId}]`);
// const sessionData = sessionStorage.getItem(`request[${msg.body.requestId}]`);

// if (pendingRequest) {
// pendingRequest.result = true;
Expand Down
Binary file added src/assets/materials/dot_glowing_mer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/materials/dot_mer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/materials/dot_multiply.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/materials/dot_normal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/BlockEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export default class BlockEntry {
get textureSet() {
return {
color: this.id, // this.aHexColor,
metalness_emissive_roughness: <RGB> [
metalness_emissive_roughness: this._material.mer ?? <RGB> [
this._material.metalness(this._level),
this._material.emissive(this._level),
this._material.roughness(this._level),
Expand Down
164 changes: 147 additions & 17 deletions src/components/ImagePrinter.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import type { Axis } from "../../typings/types.ts";
import { decode as decodeImage, Frame, GIF, Image } from "imagescript/mod.ts";
import { extname, join } from "https://deno.land/[email protected]/path/mod.ts";
import { sprintf } from "https://deno.land/[email protected]/fmt/printf.ts";
import { EOL } from "https://deno.land/[email protected]/fs/mod.ts";
import { type Frame, GIF, Image } from "imagescript/mod.ts";
import { extname, join } from "path/mod.ts";
import { sprintf } from "fmt/printf.ts";
import { EOL } from "fs/mod.ts";
import { materials } from "../store/_materials.ts";
import BlockEntry from "./BlockEntry.ts";
import { DIR_BP } from "../store/_config.ts";
import { BLOCK_VERSION, DIR_BP } from "../store/_config.ts";
import { hex2rgb } from "https://crux.land/3RdawE";

//import { encode, Int } from "https://deno.land/x/[email protected]/mod.ts";
//import { encode, Int, stringify } from "npm:[email protected]";
// import * as nbt from "npm:[email protected]";
import type { IMaterial, RGB } from "../../typings/types.ts";

const MAX_PRINT_SIZE = 3 * 16;
Expand All @@ -17,6 +19,7 @@ const MASK_COLOR = [
]; // Image.rgbToColor(...hex2rgb("#ff00ff"));
const FUNCTIONS_NAMESPACE = "printer";
const DIR_FUNCTIONS = join(DIR_BP, "functions", FUNCTIONS_NAMESPACE);
const DIR_STRUCTURES = join(DIR_BP, "structures");

function colorDistance(color1: RGB, color2: RGB) {
return Math.sqrt(
Expand All @@ -25,6 +28,112 @@ function colorDistance(color1: RGB, color2: RGB) {
);
}

// export function createStructureTag() {
// const block_palette: Array<CompoundTag> = [];
// return {
// format_version: new Int(1),
// size: [1, 1, 1] as ListTag<IntTag>,
// structure_world_origin: [0, 0, 0] as ListTag<IntTag>,
// structure: {
// block_indices: [[0, 0, 0], [
// -1,
// -1,
// -1,
// ]] as ListTag<ListTag<IntTag>>,
// entities: [] as ListTag<CompoundTag>,
// palette: {
// default: {
// block_palette,
// block_position_data: {},
// },
// },
// },
// };
// }

// function placeBlock(name: string, version = 17825806) {
// return
// }

export async function constructDecoded(
name: string,
frames: GIF | Array<Image | Frame>,
palette: BlockEntry[],
) {
const frameCount = frames.length;
const positionData = [];
const layer = [];
const waterLayer = [];
let idx = 0;

let xDim = 0;
let yDim = 0;

const blockPalette = [];

for (let z = 0; z < frameCount; z++) {
const img = frames[z];

for (const [x, y, c] of img.iterateWithColors()) {
const nearest =
getNearestColor(<RGB> Image.colorToRGB(c), palette)?.behaviorId ??
"minecraft:cobblestone";
layer.push(z, Math.abs(y - img.height), x);
waterLayer.push(-1, -1, -1);

blockPalette.push(
{
version: BLOCK_VERSION,
name: nearest,
//states: nbt.comp({}),
},
);

positionData.push([idx, {
block_entity_data: {},
}]);

xDim = Math.max(xDim, x);
yDim = Math.max(yDim, y);
idx++;
}
}

const tag = {
format_version: 1,
size: [
xDim,
yDim,
frameCount,
],
structure_world_origin: [0, 0, 0],
structure: {
block_indices: [layer, waterLayer],
//entities: nbt.list([]),
palette: {
default: {
block_palette: blockPalette,
block_position_data: Object
.fromEntries(
positionData,
),
},
},
},
};

const encoder = new TextEncoder();
const enc = encoder.encode(JSON.stringify(tag));

await Deno.writeFile(
join(
DIR_STRUCTURES,
`${name}.mcstructure`,
),
new Uint8Array(new Uint16Array(enc).buffer),
);
}

export function getNearestColor(
color: RGB,
palette: BlockEntry[],
Expand Down Expand Up @@ -58,20 +167,34 @@ function writeFill(
return `fill ${position} ${position} ${fillWith} 0 keep`;
}

/**
* @deprecated
*/
export async function decode(
src: URL,
palette: BlockEntry[],
offset: number[],
axis: Axis = "z",
absolutePosition = false,
resize?: number,
): Promise<string[]> {
// TODO: Add 10000 line limit
const imgSrc = await decodeImage(
await (await fetch(src)).arrayBuffer(),
true,
);
const img = imgSrc instanceof GIF ? imgSrc[0] : imgSrc;
const img = (await decodeUrl(src))[0];

if (resize) {
img.resize(resize, resize);
}

return convertImage(img, palette, offset, axis, absolutePosition);
}

export function convertImage(
img: Image | Frame,
palette: BlockEntry[],
offset: number[],
axis: Axis = "z",
absolutePosition = false,
): string[] {
const func: string[] = [];

for (const [x, y, c] of img.iterateWithColors()) {
Expand Down Expand Up @@ -158,18 +281,25 @@ async function printDecoded(
);
}

export async function decodeUrl({ href }: URL): Promise<GIF | Image[]> {
const res = await fetch(href);
const data = new Uint8Array(await res.arrayBuffer());

return (extname(href) !== ".gif")
? [await Image.decode(data)]
: (await GIF.decode(data, false));
}

/**
* @deprecated
*/
export async function pixelPrinter(
name: string,
imageUrl: URL,
palette: BlockEntry[],
chunks = 2,
) {
const res = await fetch(imageUrl.href);
const data = new Uint8Array(await res.arrayBuffer());

const frames = (extname(imageUrl.href) !== ".gif")
? [await Image.decode(data)]
: (await GIF.decode(data, false));
const frames = await decodeUrl(imageUrl);

const size = Math.min(MAX_PRINT_SIZE, chunks * 16);

Expand Down
Loading

0 comments on commit 39cf83b

Please sign in to comment.