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} */ 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);