wip compile blockstates

This commit is contained in:
2026-07-18 17:34:13 -04:00
parent ef93bfcd7d
commit a0afd4f79a
6 changed files with 193 additions and 18 deletions

45
src/beautify.esm.js Normal file

File diff suppressed because one or more lines are too long

0
src/minerama.css Normal file
View File

114
src/minerama.js Normal file
View File

@@ -0,0 +1,114 @@
export class Renderer {
constructor() {
this.canvas = document.createElement('canvas');
this.canvas.style.display = 'none';
document.body.appendChild(this.canvas);
this.gl = this.canvas.getContext('webgl2', {antialias: false, alpha: true})
}
}
function renderVariantCondition(key) {
if (key) {
return key.split(',').map(
it => it.split("=")
).map(
([n, v]) => `state[${JSON.stringify(n)}] === ${JSON.stringify(v)}`
).join(" && ")
} else {
return 'true';
}
}
function renderApply(data) {
if (Array.isArray(data)) {
const parts = [];
let total = 0.0;
for (const {weight = 1.0} of data) total += weight;
let accum = 0.0;
for (const elem of data) {
const {weight = 1.0} = elem;
accum += weight;
if (accum === total) {
parts.push(JSON.stringify(elem));
} else {
parts.push(`(hash % ${total}) < ${accum} ? ${JSON.stringify(elem)} : `)
}
}
return parts.join('');
} else {
return JSON.stringify(data)
}
}
/**
* @param {Object} data
* @returns {String}
*/
function renderBlockstateResolver(data) {
const {variants, multipart} = data;
if (variants) {
if (Object.keys(variants).length === 1 && variants[""]) {
return `return ${(renderApply(variants[""]))};`;
} else {
let cases = [];
for (const [key, defn] of Object.entries(variants)) {
cases.push(`if (${(renderVariantCondition(key))}) return ${(renderApply(defn))};`)
}
cases.push(`return {"model": ":missing"};`)
return cases.join('else ')
}
} else if (multipart) {
return 'console.warn("NOT IMPLEMENTED")'
} else {
console.warn('invalid blockstate', data)
}
}
/**
* @param {String} src
* @returns {Promise<void>}
*/
async function parse(src) {
const lines = src.replace(/#.*?(?:\n|$)/, '\n').trim().split(/(?:\n[ \t]*)+/);
for (const line of lines) {
const args = line.split(/[ \t]+/);
const cmd = args[0].toLowerCase();
if (cmd === 'p') {
const block = args[1];
try {
const res = await fetch(`assets/minecraft/blockstates/${block}.json`);
let data = await res.json();
let resolver_src = renderBlockstateResolver(data);
// console.log(beautify.js(`${block} = (state, hash) => {${resolver_src}}`))
let resolver = new Function("state", "hash", resolver_src);
console.log(resolver)
} catch (ex) {
console.warn(`Fetch for ${block} failed:`, ex);
}
}
}
}
export class MCDioramaElement extends HTMLElement {
connectedCallback() {
const canvas = document.createElement('canvas');
this.appendChild(canvas);
const ctx = canvas.getContext('2d');
setTimeout(() => {
const script = this.querySelector('script[type="text/mc-world"]');
parse(script.textContent);
}, 0)
}
}
customElements.define('mc-diorama', MCDioramaElement);