wip model resolver

This commit is contained in:
2026-07-19 21:58:39 -04:00
parent aedeeb63be
commit 72852eb1a5
8 changed files with 299 additions and 22 deletions

View File

@@ -24,13 +24,16 @@
<mc-diorama>
<script type="text/mc-world">
p stone
p stone
p stone
p 0 0 0 stone
p 1 0 0 stone
p 2 0 0 stone
p 3 0 0 stone
p 4 0 0 stone
p 5 0 0 stone
p 6 0 0 stone
p stone_bricks
p deepslate axis=z
<!-- p 0 0 0 stone_bricks-->
<!-- p 0 0 0 deepslate axis=z-->
</script>
</mc-diorama>

View File

@@ -1 +1,124 @@
{"gui_light":"side","display":{"gui":{"rotation":[30,225,0],"translation":[0,0,0],"scale":[0.625,0.625,0.625]},"ground":{"rotation":[0,0,0],"translation":[0,3,0],"scale":[0.25,0.25,0.25]},"fixed":{"rotation":[0,0,0],"translation":[0,0,0],"scale":[0.5,0.5,0.5]},"on_shelf":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[1,1,1]},"thirdperson_righthand":{"rotation":[75,45,0],"translation":[0,2.5,0],"scale":[0.375,0.375,0.375]},"firstperson_righthand":{"rotation":[0,45,0],"translation":[0,0,0],"scale":[0.4,0.4,0.4]},"firstperson_lefthand":{"rotation":[0,225,0],"translation":[0,0,0],"scale":[0.4,0.4,0.4]}}}
{
"gui_light": "side",
"display": {
"gui": {
"rotation": [
30,
225,
0
],
"translation": [
0,
0,
0
],
"scale": [
0.625,
0.625,
0.625
]
},
"ground": {
"rotation": [
0,
0,
0
],
"translation": [
0,
3,
0
],
"scale": [
0.25,
0.25,
0.25
]
},
"fixed": {
"rotation": [
0,
0,
0
],
"translation": [
0,
0,
0
],
"scale": [
0.5,
0.5,
0.5
]
},
"on_shelf": {
"rotation": [
0,
180,
0
],
"translation": [
0,
0,
0
],
"scale": [
1,
1,
1
]
},
"thirdperson_righthand": {
"rotation": [
75,
45,
0
],
"translation": [
0,
2.5,
0
],
"scale": [
0.375,
0.375,
0.375
]
},
"firstperson_righthand": {
"rotation": [
0,
45,
0
],
"translation": [
0,
0,
0
],
"scale": [
0.4,
0.4,
0.4
]
},
"firstperson_lefthand": {
"rotation": [
0,
225,
0
],
"translation": [
0,
0,
0
],
"scale": [
0.4,
0.4,
0.4
]
}
}
}

View File

@@ -1 +1,43 @@
{"parent":"block/block","elements":[{"from":[0,0,0],"to":[16,16,16],"faces":{"down":{"texture":"#down","cullface":"down"},"up":{"texture":"#up","cullface":"up"},"north":{"texture":"#north","cullface":"north"},"south":{"texture":"#south","cullface":"south"},"west":{"texture":"#west","cullface":"west"},"east":{"texture":"#east","cullface":"east"}}}]}
{
"parent": "block/block",
"elements": [
{
"from": [
0,
0,
0
],
"to": [
16,
16,
16
],
"faces": {
"down": {
"texture": "#down",
"cullface": "down"
},
"up": {
"texture": "#up",
"cullface": "up"
},
"north": {
"texture": "#north",
"cullface": "north"
},
"south": {
"texture": "#south",
"cullface": "south"
},
"west": {
"texture": "#west",
"cullface": "west"
},
"east": {
"texture": "#east",
"cullface": "east"
}
}
}
]
}

View File

@@ -1 +1,12 @@
{"parent":"block/cube","textures":{"particle":"#all","down":"#all","up":"#all","north":"#all","east":"#all","south":"#all","west":"#all"}}
{
"parent": "block/cube",
"textures": {
"particle": "#all",
"down": "#all",
"up": "#all",
"north": "#all",
"east": "#all",
"south": "#all",
"west": "#all"
}
}

View File

@@ -1 +1,6 @@
{"parent":"minecraft:block/cube_all","textures":{"all":"minecraft:block/smooth_stone"}}
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "minecraft:block/smooth_stone"
}
}

View File

@@ -174,13 +174,16 @@ export class BlockstateResolver {
this.pending.delete(id);
if (this.onResolve) {
this.onResolve(id, resolver);
this.onResolve(id);
}
})
.catch(reason => {
this.resolvers.set(id, this.resolvers.get(':invalid'));
this.pending.delete(id);
console.log(`failed to resolve blockstate ${id}: ${reason}`);
console.warn(`failed to resolve blockstate ${id}: ${reason}`);
if (this.onResolve) {
this.onResolve(id);
}
}));
}
@@ -189,7 +192,26 @@ export class BlockstateResolver {
resolve(id, pos, state) {
const resolver = this.getResolver(id);
const hash = pos[0] * 3.236 + pos[1] * 4.854 + pos[2] * 8.090;
// Read the 3 floats directly as 32-bit integers
let buffer = new Float32Array([pos[0], pos[1], pos[2]]).buffer;
let uview = new Uint32Array(buffer);
// Mix using large primes
let hash = Math.imul(uview[0], 73856093) ^
Math.imul(uview[1], 19349663) ^
Math.imul(uview[2], 83492791);
// Avalanche step: Force high bits to mix into low bits (fixes the % 8 issue)
hash ^= hash >>> 16;
hash = Math.imul(hash, 0x85ebca6b);
hash ^= hash >>> 13;
hash = Math.imul(hash, 0xc2b2ae35);
hash ^= hash >>> 16;
// Ensure unsigned 32-bit int
hash >>>= 0;
return resolver(state, hash);
}
}

View File

@@ -1,4 +1,5 @@
import {BlockstateResolver} from "./blockstate";
import {ModelResolver} from "./model";
export class Renderer {
constructor() {
@@ -12,26 +13,38 @@ export class Renderer {
async function parse(src) {
const lines = src.replace(/#.*?(?:\n|$)/, '\n').trim().split(/(?:\n[ \t]*)+/);
let count = 0;
const res = new BlockstateResolver();
const bres = new BlockstateResolver();
const mres = new ModelResolver();
function ff() {
const drawList = new Map();
for (const line of lines) {
const args = line.split(/[ \t]+/);
const cmd = args[0].toLowerCase();
if (cmd === 'p') {
const id = args[1];
const hash = count;
count += 1;
console.log(id, JSON.stringify(res.getResolver(id)({}, hash)));
const pos = [args[1], args[2], args[3]];
const id = args[4];
const state = Object.fromEntries(args.slice(5).map(it => it.split('=')));
for (const part of bres.resolve(id, pos, state)) {
drawList.set(part.model, null);
}
}
}
for (const id of drawList.keys()) {
const data = mres.get(id);
console.log(id, data);
}
}
res.onResolve = (id, fn) => {
console.log('resolved', id, 'to', fn)
bres.onResolve = (id) => {
console.log('resolved blockstate', id)
ff()
}
mres.onResolve = (id) => {
console.log('resolved model', id)
ff()
}

58
src/model.js Normal file
View File

@@ -0,0 +1,58 @@
export class ModelResolver {
constructor() {
this.models = new Map();
this.pending = new Map();
this.onResolve = undefined;
const cuboid = {
"from": [0, 0, 0],
"to": [0, 0, 0],
"faces": {
"down": {"texture": "#all"},
"up": {"texture": "#all"},
"north": {"texture": "#all"},
"south": {"texture": "#all"},
"west": {"texture": "#all"},
"east": {"texture": "#all"}
}
};
this.models.set(':pending', {"textures": {"all": ":pending"}, "elements": [cuboid]});
this.models.set(':missing', {"textures": {"all": ":missing"}, "elements": [cuboid]});
}
get(id) {
id = id.includes(":") ? id : `minecraft:${id}`;
if (this.models.has(id)) {
return this.models.get(id);
}
if (!this.pending.has(id)) {
const [space, name] = id.split(':');
const url = `/assets/${space}/models/${name}.json`;
this.pending.set(id, fetch(url)
.then(res => res.json())
.then(data => {
this.models.set(id, data)
this.pending.delete(id)
if (this.onResolve) {
this.onResolve(id);
}
})
.catch(reason => {
this.models.set(id, this.models.get(':invalid'));
this.pending.delete(id);
console.log(`failed to resolve model ${id}: ${reason}`)
if (this.onResolve) {
this.onResolve(id);
}
}));
}
return this.models.get(':pending');
}
}