From e203261b82e739b8755285a4e8b6493578dc97d3 Mon Sep 17 00:00:00 2001 From: KKW557 Date: Mon, 3 Mar 2025 21:11:40 +0800 Subject: [PATCH 01/13] Add colored banner --- src/render/DyeColors.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/render/DyeColors.ts diff --git a/src/render/DyeColors.ts b/src/render/DyeColors.ts new file mode 100644 index 00000000..e69de29b From e256d572d2afa95344589841edc041b6cb6eff66 Mon Sep 17 00:00:00 2001 From: KKW557 Date: Mon, 3 Mar 2025 21:16:08 +0800 Subject: [PATCH 02/13] Add colored banners --- src/render/DyeColors.ts | 39 ++++++++++++++++ src/render/SpecialRenderer.ts | 87 +++++++++++++++-------------------- 2 files changed, 77 insertions(+), 49 deletions(-) diff --git a/src/render/DyeColors.ts b/src/render/DyeColors.ts index e69de29b..bbac2d11 100644 --- a/src/render/DyeColors.ts +++ b/src/render/DyeColors.ts @@ -0,0 +1,39 @@ +import { Color } from '../util/index.js' + +const white = Color.intToRgb(16383998) +const orange = Color.intToRgb(16351261) +const magenta = Color.intToRgb(13061821) +const light_blue = Color.intToRgb(3847130) +const yellow = Color.intToRgb(16701501) +const lime = Color.intToRgb(8439583) +const pink = Color.intToRgb(15961002) +const gray = Color.intToRgb(4673362) +const light_gray = Color.intToRgb(10329495) +const cyan = Color.intToRgb(1481884) +const purple = Color.intToRgb(8991416) +const blue = Color.intToRgb(3949738) +const brown = Color.intToRgb(8606770) +const green = Color.intToRgb(6192150) +const red = Color.intToRgb(11546150) +const black = Color.intToRgb(1908001) + +export const DyeColors: { + [key: string]: (props: { [key: string]: string }) => Color, +} = { + white: () => white, + orange: () => orange, + magenta: () => magenta, + light_blue: () => light_blue, + yellow: () => yellow, + lime: () => lime, + pink: () => pink, + gray: () => gray, + light_gray: () => light_gray, + cyan: () => cyan, + purple: () => purple, + blue: () => blue, + brown: () => brown, + green: () => green, + red: () => red, + black: () => black, +} diff --git a/src/render/SpecialRenderer.ts b/src/render/SpecialRenderer.ts index 6920d87a..59031666 100644 --- a/src/render/SpecialRenderer.ts +++ b/src/render/SpecialRenderer.ts @@ -6,6 +6,7 @@ import { BlockModel } from './BlockModel.js' import { Cull } from './Cull.js' import { Mesh } from './Mesh.js' import type { TextureAtlasProvider } from './TextureAtlas.js' +import { DyeColors } from './DyeColors.js' function liquidRenderer(type: string, level: number, atlas: TextureAtlasProvider, cull: Cull, tintindex?: number) { const y = cull['up'] ? 16 : [14.2, 12.5, 10.5, 9, 7, 5.3, 3.7, 1.9, 16, 16, 16, 16, 16, 16, 16, 16][level] @@ -605,12 +606,12 @@ export namespace SpecialRenderers { from: [-2, -8, 6], to: [18, 32, 7], faces: { - north: {uv: [0.25, 0.25, 5.25, 10.25], texture: '#0'}, - east: {uv: [0, 0.25, 0.25, 10.25], texture: '#0'}, - south: {uv: [5.5, 0.25, 10.5, 10.25], texture: '#0'}, - west: {uv: [5.25, 0.25, 5.5, 10.25], texture: '#0'}, - up: {uv: [5.25, 0.25, 0.25, 0], texture: '#0'}, - down: {uv: [10.25, 0, 5.25, 0.25], texture: '#0'}, + north: {uv: [0.25, 0.25, 5.25, 10.25], texture: '#0', tintindex: 0}, + east: {uv: [0, 0.25, 0.25, 10.25], texture: '#0', tintindex: 0}, + south: {uv: [5.5, 0.25, 10.5, 10.25], texture: '#0', tintindex: 0}, + west: {uv: [5.25, 0.25, 5.5, 10.25], texture: '#0', tintindex: 0}, + up: {uv: [5.25, 0.25, 0.25, 0], texture: '#0', tintindex: 0}, + down: {uv: [10.25, 0, 5.25, 0.25], texture: '#0', tintindex: 0}, }, }, { @@ -637,7 +638,7 @@ export namespace SpecialRenderers { down: {uv: [10.5, 10.5, 5.5, 11], texture: '#0'}, }, }, - ]).getMesh(atlas, Cull.none()) + ]).getMesh(atlas, Cull.none(), DyeColors[color]?.({})) } } @@ -650,12 +651,12 @@ export namespace SpecialRenderers { from: [-2, -8, -1.5], to: [18, 32, -0.5], faces: { - north: {uv: [0.25, 0.25, 5.25, 10.25], texture: '#0'}, - east: {uv: [0, 0.25, 0.25, 10.25], texture: '#0'}, - south: {uv: [5.5, 0.25, 10.5, 10.25], texture: '#0'}, - west: {uv: [5.25, 0.25, 5.5, 10.25], texture: '#0'}, - up: {uv: [5.25, 0.25, 0.25, 0], texture: '#0'}, - down: {uv: [10.25, 0, 5.25, 0.25], texture: '#0'}, + north: {uv: [0.25, 0.25, 5.25, 10.25], texture: '#0', tintindex: 0}, + east: {uv: [0, 0.25, 0.25, 10.25], texture: '#0', tintindex: 0}, + south: {uv: [5.5, 0.25, 10.5, 10.25], texture: '#0', tintindex: 0}, + west: {uv: [5.25, 0.25, 5.5, 10.25], texture: '#0', tintindex: 0}, + up: {uv: [5.25, 0.25, 0.25, 0], texture: '#0', tintindex: 0}, + down: {uv: [10.25, 0, 5.25, 0.25], texture: '#0', tintindex: 0}, }, }, { @@ -670,7 +671,7 @@ export namespace SpecialRenderers { down: {uv: [10.5, 10.5, 5.5, 11], texture: '#0'}, }, }, - ]).getMesh(atlas, Cull.none()) + ]).getMesh(atlas, Cull.none(), DyeColors[color]?.({})) } } @@ -844,41 +845,29 @@ export namespace SpecialRenderers { [`minecraft:${type}_wall_hanging_sign`, SpecialRenderers.wallHangingSignRenderer(type)] )) - const DyeColors = [ - 'white', - 'orange', - 'magenta', - 'light_blue', - 'yellow', - 'lime', - 'pink', - 'gray', - 'light_gray', - 'cyan', - 'purple', - 'blue', - 'brown', - 'green', - 'red', - 'black', - ] - - const ShulkerBoxRenderers = new Map(DyeColors.map(color => - [`minecraft:${color}_shulker_box`, SpecialRenderers.shulkerBoxRenderer(Identifier.create(`shulker_${color}`))] - )) - - const BedRenderers = new Map(DyeColors.map(color => - [`minecraft:${color}_bed`, SpecialRenderers.bedRenderer(Identifier.create(color))] - )) - - const BannerRenderers = new Map(DyeColors.map(color => - [`minecraft:${color}_banner`, SpecialRenderers.bannerRenderer(color)] - )) - - const WallBannerRenderers = new Map(DyeColors.map(color => - [`minecraft:${color}_wall_banner`, SpecialRenderers.wallBannerRenderer(color)] - )) - + const ShulkerBoxRenderers = new Map( + Object.keys(DyeColors).map(color => + [`minecraft:${color}_shulker_box`, SpecialRenderers.shulkerBoxRenderer(Identifier.create(`shulker_${color}`))] + ) + ) + + const BedRenderers = new Map( + Object.keys(DyeColors).map(color => + [`minecraft:${color}_bed`, SpecialRenderers.bedRenderer(Identifier.create(color))] + ) + ) + + const BannerRenderers = new Map( + Object.keys(DyeColors).map(color => + [`minecraft:${color}_banner`, SpecialRenderers.bannerRenderer(color)] + ) + ) + + const WallBannerRenderers = new Map( + Object.keys(DyeColors).map(color => + [`minecraft:${color}_wall_banner`, SpecialRenderers.wallBannerRenderer(color)] + ) + ) export function getBlockMesh(block: BlockState, atlas: TextureAtlasProvider, cull: Cull): Mesh { const mesh = new Mesh() From 1df2e7fc367b497362c543fc0427387f17016753 Mon Sep 17 00:00:00 2001 From: KKW557 Date: Tue, 4 Mar 2025 00:22:55 +0800 Subject: [PATCH 03/13] Add banner patterns renderer --- src/render/ChunkBuilder.ts | 2 +- src/render/SpecialRenderer.ts | 146 ++++++++++++++++++++++++---------- 2 files changed, 103 insertions(+), 45 deletions(-) diff --git a/src/render/ChunkBuilder.ts b/src/render/ChunkBuilder.ts index 82f4bbae..aea5a9c4 100644 --- a/src/render/ChunkBuilder.ts +++ b/src/render/ChunkBuilder.ts @@ -69,7 +69,7 @@ export class ChunkBuilder { if (blockDefinition) { mesh.merge(blockDefinition.getMesh(blockName, blockProps, this.resources, this.resources, cull)) } - const specialMesh = SpecialRenderers.getBlockMesh(b.state, this.resources, cull) + const specialMesh = SpecialRenderers.getBlockMesh(b, this.resources, cull) if (!specialMesh.isEmpty()) { mesh.merge(specialMesh) } diff --git a/src/render/SpecialRenderer.ts b/src/render/SpecialRenderer.ts index 59031666..fb4e8c10 100644 --- a/src/render/SpecialRenderer.ts +++ b/src/render/SpecialRenderer.ts @@ -1,5 +1,5 @@ import { mat4 } from 'gl-matrix' -import type { BlockState } from '../core/index.js' +import type { BlockState, PlacedBlock } from '../core/index.js' import { Direction, Identifier } from '../core/index.js' import { BlockColors } from './BlockColors.js' import { BlockModel } from './BlockModel.js' @@ -7,6 +7,7 @@ import { Cull } from './Cull.js' import { Mesh } from './Mesh.js' import type { TextureAtlasProvider } from './TextureAtlas.js' import { DyeColors } from './DyeColors.js' +import type { NbtCompound } from '../nbt/index.js' function liquidRenderer(type: string, level: number, atlas: TextureAtlasProvider, cull: Cull, tintindex?: number) { const y = cull['up'] ? 16 : [14.2, 12.5, 10.5, 9, 7, 5.3, 3.7, 1.9, 16, 16, 16, 16, 16, 16, 16, 16][level] @@ -598,10 +599,9 @@ export namespace SpecialRenderers { } export function bannerRenderer(color: string) { - return (atlas: TextureAtlasProvider) => { - return new BlockModel(undefined, { - 0: 'entity/banner_base', - }, [ + return (nbt: NbtCompound | undefined, atlas: TextureAtlasProvider) => { + const textures: { [key: string]: string } = { 0: 'entity/banner_base' } + const elements = [ { from: [-2, -8, 6], to: [18, 32, 7], @@ -638,15 +638,42 @@ export namespace SpecialRenderers { down: {uv: [10.5, 10.5, 5.5, 11], texture: '#0'}, }, }, - ]).getMesh(atlas, Cull.none(), DyeColors[color]?.({})) + ] + const colors: string[] = [color] + + if (nbt !== undefined) { + const patterns = nbt.getList('patterns', 10) + patterns.forEach((compound, index) => { + const pattern = Identifier.parse(compound.getString('pattern')).path + const color = compound.getString('color') + const key = index + 1 + textures[key] = `entity/banner/${pattern}` + elements.push({ + from: [-2, -8, 6], + to: [18, 32, 7], + faces: { + north: {uv: [0.25, 0.25, 5.25, 10.25], texture: `#${key}`, tintindex: key}, + east: {uv: [0, 0.25, 0.25, 10.25], texture: `#${key}`, tintindex: key}, + south: {uv: [5.5, 0.25, 10.5, 10.25], texture: `#${key}`, tintindex: key}, + west: {uv: [5.25, 0.25, 5.5, 10.25], texture: `#${key}`, tintindex: key}, + up: {uv: [5.25, 0.25, 0.25, 0], texture: `#${key}`, tintindex: key}, + down: {uv: [10.25, 0, 5.25, 0.25], texture: `#${key}`, tintindex: key}, + }, + }) + colors.push(color) + }) + } + + // @ts-ignore + return new BlockModel(undefined, textures, elements) + .getMesh(atlas, Cull.none(), (index: number) => DyeColors[colors[index]]?.({})) } } export function wallBannerRenderer(color: string) { - return (atlas: TextureAtlasProvider) => { - return new BlockModel(undefined, { - 0: 'entity/banner_base', - }, [ + return (nbt: NbtCompound | undefined, atlas: TextureAtlasProvider) => { + const textures: { [key: string]: string } = { 0: 'entity/banner_base' } + const elements = [ { from: [-2, -8, -1.5], to: [18, 32, -0.5], @@ -671,7 +698,35 @@ export namespace SpecialRenderers { down: {uv: [10.5, 10.5, 5.5, 11], texture: '#0'}, }, }, - ]).getMesh(atlas, Cull.none(), DyeColors[color]?.({})) + ] + const colors: string[] = [color] + + if (nbt !== undefined) { + const patterns = nbt.getList('patterns', 10) + patterns.forEach((compound, index) => { + const pattern = Identifier.parse(compound.getString('pattern')).path + const color = compound.getString('color') + const key = index + 1 + textures[key] = `entity/banner/${pattern}` + elements.push({ + from: [-2, -8, -1.5], + to: [18, 32, -0.5], + faces: { + north: {uv: [0.25, 0.25, 5.25, 10.25], texture: `#${key}`, tintindex: key}, + east: {uv: [0, 0.25, 0.25, 10.25], texture: `#${key}`, tintindex: key}, + south: {uv: [5.5, 0.25, 10.5, 10.25], texture: `#${key}`, tintindex: key}, + west: {uv: [5.25, 0.25, 5.5, 10.25], texture: `#${key}`, tintindex: key}, + up: {uv: [5.25, 0.25, 0.25, 0], texture: `#${key}`, tintindex: key}, + down: {uv: [10.25, 0, 5.25, 0.25], texture: `#${key}`, tintindex: key}, + }, + }) + colors.push(color) + }) + } + + // @ts-ignore + return new BlockModel(undefined, textures, elements) + .getMesh(atlas, Cull.none(), (index: number) => DyeColors[colors[index]]?.({})) } } @@ -869,38 +924,41 @@ export namespace SpecialRenderers { ) ) - export function getBlockMesh(block: BlockState, atlas: TextureAtlasProvider, cull: Cull): Mesh { + export function getBlockMesh(block: PlacedBlock, atlas: TextureAtlasProvider, cull: Cull): Mesh { + const state = block.state + const nbt = block.nbt + const mesh = new Mesh() - if (block.is('water')) { - mesh.merge(liquidRenderer('water', getInt(block, 'level'), atlas, cull, 0)) + if (state.is('water')) { + mesh.merge(liquidRenderer('water', getInt(state, 'level'), atlas, cull, 0)) } - if (block.is('lava')) { - mesh.merge(liquidRenderer('lava', getInt(block, 'level'), atlas, cull)) + if (state.is('lava')) { + mesh.merge(liquidRenderer('lava', getInt(state, 'level'), atlas, cull)) } - const chestRenderer = ChestRenderers.get(block.getName().toString()) + const chestRenderer = ChestRenderers.get(state.getName().toString()) if (chestRenderer !== undefined) { - const facing = getStr(block, 'facing', 'south') + const facing = getStr(state, 'facing', 'south') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, facing === 'west' ? Math.PI / 2 : facing === 'south' ? Math.PI : facing === 'east' ? Math.PI * 3 / 2 : 0) mat4.translate(t, t, [-8, -8, -8]) mesh.merge(chestRenderer(atlas).transform(t)) } - if (block.is('decorated_pot')) { + if (state.is('decorated_pot')) { mesh.merge(decoratedPotRenderer(atlas)) } - const skullRenderer = SkullRenderers.get(block.getName().toString()) + const skullRenderer = SkullRenderers.get(state.getName().toString()) if (skullRenderer !== undefined) { - const rotation = getInt(block, 'rotation') / 16 * Math.PI * 2 + const rotation = getInt(state, 'rotation') / 16 * Math.PI * 2 const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, rotation) mat4.translate(t, t, [-8, -8, -8]) mesh.merge(skullRenderer(atlas).transform(t)) } - const signRenderer = SignRenderers.get(block.getName().toString()) + const signRenderer = SignRenderers.get(state.getName().toString()) if (signRenderer !== undefined) { - const rotation = getInt(block, 'rotation') / 16 * Math.PI * 2 + const rotation = getInt(state, 'rotation') / 16 * Math.PI * 2 const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, rotation) @@ -908,9 +966,9 @@ export namespace SpecialRenderers { mat4.translate(t, t, [-8, -8, -8]) mesh.merge(signRenderer(atlas).transform(t)) } - const wallSignRenderer = WallSignRenderers.get(block.getName().toString()) + const wallSignRenderer = WallSignRenderers.get(state.getName().toString()) if (wallSignRenderer !== undefined) { - const facing = getStr(block, 'facing', 'south') + const facing = getStr(state, 'facing', 'south') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, facing === 'west' ? Math.PI / 2 : facing === 'south' ? Math.PI : facing === 'east' ? Math.PI * 3 / 2 : 0) @@ -918,10 +976,10 @@ export namespace SpecialRenderers { mat4.translate(t, t, [-8, -8, -8]) mesh.merge(wallSignRenderer(atlas).transform(t)) } - const hangingSignRenderer = HangingSignRenderers.get(block.getName().toString()) + const hangingSignRenderer = HangingSignRenderers.get(state.getName().toString()) if (hangingSignRenderer !== undefined) { - const attached = getStr(block, 'attached', 'false') === 'true' - const rotation = getInt(block, 'rotation') / 16 * Math.PI * 2 + const attached = getStr(state, 'attached', 'false') === 'true' + const rotation = getInt(state, 'rotation') / 16 * Math.PI * 2 const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, rotation) @@ -929,21 +987,21 @@ export namespace SpecialRenderers { mat4.translate(t, t, [-8, -8, -8]) mesh.merge(hangingSignRenderer(attached, atlas).transform(t)) } - const wallHangingSignRenderer = WallHangingSignRenderers.get(block.getName().toString()) + const wallHangingSignRenderer = WallHangingSignRenderers.get(state.getName().toString()) if (wallHangingSignRenderer !== undefined) { - const facing = getStr(block, 'facing', 'south') + const facing = getStr(state, 'facing', 'south') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, facing === 'west' ? Math.PI / 2 : facing === 'south' ? Math.PI : facing === 'east' ? Math.PI * 3 / 2 : 0) mat4.translate(t, t, [-8, -8, -8]) mesh.merge(wallHangingSignRenderer(atlas).transform(t)) } - if (block.is('conduit')) { + if (state.is('conduit')) { mesh.merge(conduitRenderer(atlas)) } - const shulkerBoxRenderer = ShulkerBoxRenderers.get(block.getName().toString()) + const shulkerBoxRenderer = ShulkerBoxRenderers.get(state.getName().toString()) if (shulkerBoxRenderer !== undefined) { - const facing = getStr(block, 'facing', 'up') + const facing = getStr(state, 'facing', 'up') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) if (facing === 'down') { @@ -955,45 +1013,45 @@ export namespace SpecialRenderers { mat4.translate(t, t, [-8, -8, -8]) mesh.merge(shulkerBoxRenderer(atlas).transform(t)) } - if (block.is('bell')) { + if (state.is('bell')) { const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.scale(t, t, [1, -1, -1]) mat4.translate(t, t, [-8, -8, -8]) mesh.merge(bellRenderer(atlas).transform(t)) } - const bedRenderer = BedRenderers.get(block.getName().toString()) + const bedRenderer = BedRenderers.get(state.getName().toString()) if (bedRenderer !== undefined) { - const part = getStr(block, 'part', 'head') - const facing = getStr(block, 'facing', 'south') + const part = getStr(state, 'part', 'head') + const facing = getStr(state, 'facing', 'south') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, facing === 'east' ? Math.PI / 2 : facing === 'north' ? Math.PI : facing === 'west' ? Math.PI * 3 / 2 : 0) mat4.translate(t, t, [-8, -8, -8]) mesh.merge(bedRenderer(part, atlas).transform(t)) } - const bannerRenderer = BannerRenderers.get(block.getName().toString()) + const bannerRenderer = BannerRenderers.get(state.getName().toString()) if (bannerRenderer !== undefined) { - const rotation = getInt(block, 'rotation') / 16 * Math.PI * 2 + const rotation = getInt(state, 'rotation') / 16 * Math.PI * 2 const t = mat4.create() mat4.translate(t, t, [8, 24, 8]) mat4.rotateY(t, t, rotation) mat4.scale(t, t, [2/3, 2/3, 2/3]) mat4.translate(t, t, [-8, -24, -8]) - mesh.merge(bannerRenderer(atlas).transform(t)) + mesh.merge(bannerRenderer(nbt, atlas).transform(t)) } - const wallBannerRenderer = WallBannerRenderers.get(block.getName().toString()) + const wallBannerRenderer = WallBannerRenderers.get(state.getName().toString()) if (wallBannerRenderer !== undefined) { - const facing = getStr(block, 'facing', 'south') + const facing = getStr(state, 'facing', 'south') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, facing === 'east' ? Math.PI / 2 : facing === 'north' ? Math.PI : facing === 'west' ? Math.PI * 3 / 2 : 0) mat4.scale(t, t, [2/3, 2/3, 2/3]) mat4.translate(t, t, [-8, -23.2, -8]) - mesh.merge(wallBannerRenderer(atlas).transform(t)) + mesh.merge(wallBannerRenderer(nbt, atlas).transform(t)) } - if (!block.is('water') && !block.is('lava') && block.isWaterlogged()) { + if (!state.is('water') && !state.is('lava') && state.isWaterlogged()) { mesh.merge(liquidRenderer('water', 0, atlas, cull, 0)) } From 848faf9b2e3230b07438410d9ae08da87b58f38e Mon Sep 17 00:00:00 2001 From: KKW557 Date: Tue, 4 Mar 2025 14:09:35 +0800 Subject: [PATCH 04/13] Reduce duplicate code --- src/render/SpecialRenderer.ts | 184 ++++++++++++++-------------------- 1 file changed, 75 insertions(+), 109 deletions(-) diff --git a/src/render/SpecialRenderer.ts b/src/render/SpecialRenderer.ts index fb4e8c10..de76ed97 100644 --- a/src/render/SpecialRenderer.ts +++ b/src/render/SpecialRenderer.ts @@ -598,137 +598,103 @@ export namespace SpecialRenderers { } } - export function bannerRenderer(color: string) { + const bannerFace = (index: number) => ({ + north: {uv: [0.25, 0.25, 5.25, 10.25], texture: `#${index}`, tintindex: index}, + east: {uv: [0, 0.25, 0.25, 10.25], texture: `#${index}`, tintindex: index}, + south: {uv: [5.5, 0.25, 10.5, 10.25], texture: `#${index}`, tintindex: index}, + west: {uv: [5.25, 0.25, 5.5, 10.25], texture: `#${index}`, tintindex: index}, + up: {uv: [5.25, 0.25, 0.25, 0], texture: `#${index}`, tintindex: index}, + down: {uv: [10.25, 0, 5.25, 0.25], texture: `#${index}`, tintindex: index}, + }) + + function createBannerRenderer(color: string, config: { base: any[], pattern: (index: number) => any }) { return (nbt: NbtCompound | undefined, atlas: TextureAtlasProvider) => { const textures: { [key: string]: string } = { 0: 'entity/banner_base' } - const elements = [ - { - from: [-2, -8, 6], - to: [18, 32, 7], - faces: { - north: {uv: [0.25, 0.25, 5.25, 10.25], texture: '#0', tintindex: 0}, - east: {uv: [0, 0.25, 0.25, 10.25], texture: '#0', tintindex: 0}, - south: {uv: [5.5, 0.25, 10.5, 10.25], texture: '#0', tintindex: 0}, - west: {uv: [5.25, 0.25, 5.5, 10.25], texture: '#0', tintindex: 0}, - up: {uv: [5.25, 0.25, 0.25, 0], texture: '#0', tintindex: 0}, - down: {uv: [10.25, 0, 5.25, 0.25], texture: '#0', tintindex: 0}, - }, - }, - { - from: [7, -12, 7], - to: [9, 30, 9], - faces: { - north: {uv: [11.5, 0.5, 12, 11], texture: '#0'}, - east: {uv: [11, 0.5, 11.5, 11], texture: '#0'}, - south: {uv: [12.5, 0.5, 13, 11], texture: '#0'}, - west: {uv: [12, 0.5, 12.5, 11], texture: '#0'}, - up: {uv: [12, 0.5, 11.5, 0], texture: '#0'}, - down: {uv: [12.5, 0, 12, 0.5], texture: '#0'}, - }, - }, - { - from: [-2, 30, 7], - to: [18, 32, 9], - faces: { - north: {uv: [0.5, 11, 5.5, 11.5], texture: '#0'}, - east: {uv: [0, 11, 0.5, 11.5], texture: '#0'}, - south: {uv: [6, 11, 11, 11.5], texture: '#0'}, - west: {uv: [5.5, 11, 6, 11.5], texture: '#0'}, - up: {uv: [5.5, 11, 0.5, 10.5], texture: '#0'}, - down: {uv: [10.5, 10.5, 5.5, 11], texture: '#0'}, - }, - }, - ] + const elements = [...config.base] const colors: string[] = [color] - if (nbt !== undefined) { + if (nbt) { const patterns = nbt.getList('patterns', 10) patterns.forEach((compound, index) => { const pattern = Identifier.parse(compound.getString('pattern')).path const color = compound.getString('color') const key = index + 1 textures[key] = `entity/banner/${pattern}` - elements.push({ - from: [-2, -8, 6], - to: [18, 32, 7], - faces: { - north: {uv: [0.25, 0.25, 5.25, 10.25], texture: `#${key}`, tintindex: key}, - east: {uv: [0, 0.25, 0.25, 10.25], texture: `#${key}`, tintindex: key}, - south: {uv: [5.5, 0.25, 10.5, 10.25], texture: `#${key}`, tintindex: key}, - west: {uv: [5.25, 0.25, 5.5, 10.25], texture: `#${key}`, tintindex: key}, - up: {uv: [5.25, 0.25, 0.25, 0], texture: `#${key}`, tintindex: key}, - down: {uv: [10.25, 0, 5.25, 0.25], texture: `#${key}`, tintindex: key}, - }, - }) + elements.push(config.pattern(key)) colors.push(color) }) } - // @ts-ignore return new BlockModel(undefined, textures, elements) .getMesh(atlas, Cull.none(), (index: number) => DyeColors[colors[index]]?.({})) } } - export function wallBannerRenderer(color: string) { - return (nbt: NbtCompound | undefined, atlas: TextureAtlasProvider) => { - const textures: { [key: string]: string } = { 0: 'entity/banner_base' } - const elements = [ - { - from: [-2, -8, -1.5], - to: [18, 32, -0.5], - faces: { - north: {uv: [0.25, 0.25, 5.25, 10.25], texture: '#0', tintindex: 0}, - east: {uv: [0, 0.25, 0.25, 10.25], texture: '#0', tintindex: 0}, - south: {uv: [5.5, 0.25, 10.5, 10.25], texture: '#0', tintindex: 0}, - west: {uv: [5.25, 0.25, 5.5, 10.25], texture: '#0', tintindex: 0}, - up: {uv: [5.25, 0.25, 0.25, 0], texture: '#0', tintindex: 0}, - down: {uv: [10.25, 0, 5.25, 0.25], texture: '#0', tintindex: 0}, - }, + export const bannerRenderer = (color: string) => createBannerRenderer(color, { + base: [ + { + from: [-2, -8, 6], + to: [18, 32, 7], + faces: bannerFace(0), + }, + { + from: [7, -12, 7], + to: [9, 30, 9], + faces: { + north: {uv: [11.5, 0.5, 12, 11], texture: '#0'}, + east: {uv: [11, 0.5, 11.5, 11], texture: '#0'}, + south: {uv: [12.5, 0.5, 13, 11], texture: '#0'}, + west: {uv: [12, 0.5, 12.5, 11], texture: '#0'}, + up: {uv: [12, 0.5, 11.5, 0], texture: '#0'}, + down: {uv: [12.5, 0, 12, 0.5], texture: '#0'}, }, - { - from: [-2, 30, -3.5], - to: [18, 32, -1.5], - faces: { - north: {uv: [0.5, 11, 5.5, 11.5], texture: '#0'}, - east: {uv: [0, 11, 0.5, 11.5], texture: '#0'}, - south: {uv: [6, 11, 11, 11.5], texture: '#0'}, - west: {uv: [5.5, 11, 6, 11.5], texture: '#0'}, - up: {uv: [5.5, 11, 0.5, 10.5], texture: '#0'}, - down: {uv: [10.5, 10.5, 5.5, 11], texture: '#0'}, - }, + }, + { + from: [-2, 30, 7], + to: [18, 32, 9], + faces: { + north: {uv: [0.5, 11, 5.5, 11.5], texture: '#0'}, + east: {uv: [0, 11, 0.5, 11.5], texture: '#0'}, + south: {uv: [6, 11, 11, 11.5], texture: '#0'}, + west: {uv: [5.5, 11, 6, 11.5], texture: '#0'}, + up: {uv: [5.5, 11, 0.5, 10.5], texture: '#0'}, + down: {uv: [10.5, 10.5, 5.5, 11], texture: '#0'}, }, - ] - const colors: string[] = [color] - - if (nbt !== undefined) { - const patterns = nbt.getList('patterns', 10) - patterns.forEach((compound, index) => { - const pattern = Identifier.parse(compound.getString('pattern')).path - const color = compound.getString('color') - const key = index + 1 - textures[key] = `entity/banner/${pattern}` - elements.push({ - from: [-2, -8, -1.5], - to: [18, 32, -0.5], - faces: { - north: {uv: [0.25, 0.25, 5.25, 10.25], texture: `#${key}`, tintindex: key}, - east: {uv: [0, 0.25, 0.25, 10.25], texture: `#${key}`, tintindex: key}, - south: {uv: [5.5, 0.25, 10.5, 10.25], texture: `#${key}`, tintindex: key}, - west: {uv: [5.25, 0.25, 5.5, 10.25], texture: `#${key}`, tintindex: key}, - up: {uv: [5.25, 0.25, 0.25, 0], texture: `#${key}`, tintindex: key}, - down: {uv: [10.25, 0, 5.25, 0.25], texture: `#${key}`, tintindex: key}, - }, - }) - colors.push(color) - }) - } + }, + ], + pattern: (index: number) => ({ + from: [-2, -8, 6], + to: [18, 32, 7], + faces: bannerFace(index), + }), + }) - // @ts-ignore - return new BlockModel(undefined, textures, elements) - .getMesh(atlas, Cull.none(), (index: number) => DyeColors[colors[index]]?.({})) - } - } + export const wallBannerRenderer = (color: string) => createBannerRenderer(color, { + base: [ + { + from: [-2, -8, -1.5], + to: [18, 32, -0.5], + faces: bannerFace(0), + }, + { + from: [-2, 30, -3.5], + to: [18, 32, -1.5], + faces: { + north: {uv: [0.5, 11, 5.5, 11.5], texture: '#0'}, + east: {uv: [0, 11, 0.5, 11.5], texture: '#0'}, + south: {uv: [6, 11, 11, 11.5], texture: '#0'}, + west: {uv: [5.5, 11, 6, 11.5], texture: '#0'}, + up: {uv: [5.5, 11, 0.5, 10.5], texture: '#0'}, + down: {uv: [10.5, 10.5, 5.5, 11], texture: '#0'}, + }, + }, + ], + pattern: (index: number) => ({ + from: [-2, -8, -1.5], + to: [18, 32, -0.5], + faces: bannerFace(index), + }), + }) export function bellRenderer(atlas: TextureAtlasProvider) { return new BlockModel(undefined, { From b31bf44ea161d5c93386a8b3c5f13598410df722 Mon Sep 17 00:00:00 2001 From: KKW557 Date: Tue, 4 Mar 2025 14:37:50 +0800 Subject: [PATCH 05/13] Fix https://github.com/misode/deepslate/actions/runs/13647649870/job/38149365256?pr=52 --- src/render/SpecialRenderer.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/render/SpecialRenderer.ts b/src/render/SpecialRenderer.ts index de76ed97..7a9807ed 100644 --- a/src/render/SpecialRenderer.ts +++ b/src/render/SpecialRenderer.ts @@ -608,7 +608,7 @@ export namespace SpecialRenderers { }) function createBannerRenderer(color: string, config: { base: any[], pattern: (index: number) => any }) { - return (nbt: NbtCompound | undefined, atlas: TextureAtlasProvider) => { + return (atlas: TextureAtlasProvider, nbt?: NbtCompound) => { const textures: { [key: string]: string } = { 0: 'entity/banner_base' } const elements = [...config.base] const colors: string[] = [color] @@ -1004,7 +1004,7 @@ export namespace SpecialRenderers { mat4.rotateY(t, t, rotation) mat4.scale(t, t, [2/3, 2/3, 2/3]) mat4.translate(t, t, [-8, -24, -8]) - mesh.merge(bannerRenderer(nbt, atlas).transform(t)) + mesh.merge(bannerRenderer(atlas, nbt).transform(t)) } const wallBannerRenderer = WallBannerRenderers.get(state.getName().toString()) if (wallBannerRenderer !== undefined) { @@ -1014,7 +1014,7 @@ export namespace SpecialRenderers { mat4.rotateY(t, t, facing === 'east' ? Math.PI / 2 : facing === 'north' ? Math.PI : facing === 'west' ? Math.PI * 3 / 2 : 0) mat4.scale(t, t, [2/3, 2/3, 2/3]) mat4.translate(t, t, [-8, -23.2, -8]) - mesh.merge(wallBannerRenderer(nbt, atlas).transform(t)) + mesh.merge(wallBannerRenderer(atlas, nbt).transform(t)) } if (!state.is('water') && !state.is('lava') && state.isWaterlogged()) { From 21d6c65e91885bdf5f9f066a4dbc87b16ac6b264 Mon Sep 17 00:00:00 2001 From: KKW557 Date: Tue, 4 Mar 2025 15:28:13 +0800 Subject: [PATCH 06/13] Add banner patterns render for item --- src/render/SpecialModel.ts | 6 ++++-- src/render/SpecialRenderer.ts | 27 ++++++++++++--------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/render/SpecialModel.ts b/src/render/SpecialModel.ts index a65eb5a2..ab30f6a3 100644 --- a/src/render/SpecialModel.ts +++ b/src/render/SpecialModel.ts @@ -1,5 +1,6 @@ import { mat4 } from 'gl-matrix' -import type { Direction, ItemStack, TextureAtlasProvider } from '../index.js' +import {Direction, ItemStack, NbtCompound, TextureAtlasProvider} from '../index.js' +import { NbtList } from '../index.js' import { Identifier, Json, SpecialRenderers } from '../index.js' import { Mesh } from './Mesh.js' @@ -73,7 +74,8 @@ export namespace SpecialModel { } public getMesh(item: ItemStack, resources: TextureAtlasProvider): Mesh { - return this.renderer(resources) + const patterns = item.getComponent('banner_patterns', undefined) + return this.renderer(resources, patterns instanceof NbtList ? patterns : undefined) } } diff --git a/src/render/SpecialRenderer.ts b/src/render/SpecialRenderer.ts index 7a9807ed..b6f8a90a 100644 --- a/src/render/SpecialRenderer.ts +++ b/src/render/SpecialRenderer.ts @@ -7,7 +7,7 @@ import { Cull } from './Cull.js' import { Mesh } from './Mesh.js' import type { TextureAtlasProvider } from './TextureAtlas.js' import { DyeColors } from './DyeColors.js' -import type { NbtCompound } from '../nbt/index.js' +import type { NbtCompound, NbtList } from '../nbt/index.js' function liquidRenderer(type: string, level: number, atlas: TextureAtlasProvider, cull: Cull, tintindex?: number) { const y = cull['up'] ? 16 : [14.2, 12.5, 10.5, 9, 7, 5.3, 3.7, 1.9, 16, 16, 16, 16, 16, 16, 16, 16][level] @@ -608,22 +608,19 @@ export namespace SpecialRenderers { }) function createBannerRenderer(color: string, config: { base: any[], pattern: (index: number) => any }) { - return (atlas: TextureAtlasProvider, nbt?: NbtCompound) => { + return (atlas: TextureAtlasProvider, patterns?: NbtList) => { const textures: { [key: string]: string } = { 0: 'entity/banner_base' } const elements = [...config.base] const colors: string[] = [color] - if (nbt) { - const patterns = nbt.getList('patterns', 10) - patterns.forEach((compound, index) => { - const pattern = Identifier.parse(compound.getString('pattern')).path - const color = compound.getString('color') - const key = index + 1 - textures[key] = `entity/banner/${pattern}` - elements.push(config.pattern(key)) - colors.push(color) - }) - } + patterns?.forEach((compound, index) => { + const pattern = Identifier.parse(compound.getString('pattern')).path + const color = compound.getString('color') + const key = index + 1 + textures[key] = `entity/banner/${pattern}` + elements.push(config.pattern(key)) + colors.push(color) + }) return new BlockModel(undefined, textures, elements) .getMesh(atlas, Cull.none(), (index: number) => DyeColors[colors[index]]?.({})) @@ -1004,7 +1001,7 @@ export namespace SpecialRenderers { mat4.rotateY(t, t, rotation) mat4.scale(t, t, [2/3, 2/3, 2/3]) mat4.translate(t, t, [-8, -24, -8]) - mesh.merge(bannerRenderer(atlas, nbt).transform(t)) + mesh.merge(bannerRenderer(atlas, nbt?.getList('patterns', 10)).transform(t)) } const wallBannerRenderer = WallBannerRenderers.get(state.getName().toString()) if (wallBannerRenderer !== undefined) { @@ -1014,7 +1011,7 @@ export namespace SpecialRenderers { mat4.rotateY(t, t, facing === 'east' ? Math.PI / 2 : facing === 'north' ? Math.PI : facing === 'west' ? Math.PI * 3 / 2 : 0) mat4.scale(t, t, [2/3, 2/3, 2/3]) mat4.translate(t, t, [-8, -23.2, -8]) - mesh.merge(wallBannerRenderer(atlas, nbt).transform(t)) + mesh.merge(wallBannerRenderer(atlas, nbt?.getList('patterns', 10)).transform(t)) } if (!state.is('water') && !state.is('lava') && state.isWaterlogged()) { From f94b810fbd048ee697e9aef2975bceda943ff7b0 Mon Sep 17 00:00:00 2001 From: KKW557 Date: Tue, 4 Mar 2025 15:37:20 +0800 Subject: [PATCH 07/13] Fix item model reverse --- src/render/SpecialModel.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/render/SpecialModel.ts b/src/render/SpecialModel.ts index ab30f6a3..4760c5e6 100644 --- a/src/render/SpecialModel.ts +++ b/src/render/SpecialModel.ts @@ -75,7 +75,12 @@ export namespace SpecialModel { public getMesh(item: ItemStack, resources: TextureAtlasProvider): Mesh { const patterns = item.getComponent('banner_patterns', undefined) - return this.renderer(resources, patterns instanceof NbtList ? patterns : undefined) + const t = mat4.create() + mat4.translate(t, t, [8, 24, 8]) + mat4.rotateY(t, t, Math.PI) + mat4.scale(t, t, [2/3, 2/3, 2/3]) + mat4.translate(t, t, [-8, -24, -8]) + return this.renderer(resources, patterns instanceof NbtList ? patterns : undefined).transform(t) } } From b95118255440b9b01c1afe9b039a9b2c7d3c73fe Mon Sep 17 00:00:00 2001 From: KKW557 Date: Tue, 4 Mar 2025 15:49:45 +0800 Subject: [PATCH 08/13] Fix import --- src/render/SpecialModel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/SpecialModel.ts b/src/render/SpecialModel.ts index 4760c5e6..cf310c8e 100644 --- a/src/render/SpecialModel.ts +++ b/src/render/SpecialModel.ts @@ -1,5 +1,5 @@ import { mat4 } from 'gl-matrix' -import {Direction, ItemStack, NbtCompound, TextureAtlasProvider} from '../index.js' +import type {Direction, ItemStack, NbtCompound, TextureAtlasProvider} from '../index.js' import { NbtList } from '../index.js' import { Identifier, Json, SpecialRenderers } from '../index.js' import { Mesh } from './Mesh.js' From fbd2437ded6ccd544d2c8b9c4d0bb794432fef12 Mon Sep 17 00:00:00 2001 From: KKW557 Date: Tue, 4 Mar 2025 21:51:41 +0800 Subject: [PATCH 09/13] Add inline index --- src/render/SpecialRenderer.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/render/SpecialRenderer.ts b/src/render/SpecialRenderer.ts index b6f8a90a..261c20b9 100644 --- a/src/render/SpecialRenderer.ts +++ b/src/render/SpecialRenderer.ts @@ -616,9 +616,9 @@ export namespace SpecialRenderers { patterns?.forEach((compound, index) => { const pattern = Identifier.parse(compound.getString('pattern')).path const color = compound.getString('color') - const key = index + 1 - textures[key] = `entity/banner/${pattern}` - elements.push(config.pattern(key)) + index++ + textures[index] = `entity/banner/${pattern}` + elements.push(config.pattern(index)) colors.push(color) }) From 9dd8ca9fe4a99deb81f0e9b834ef5f9967ede9c4 Mon Sep 17 00:00:00 2001 From: KKW557 Date: Wed, 5 Mar 2025 22:59:27 +0800 Subject: [PATCH 10/13] Remove hard code --- src/render/SpecialRenderer.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/render/SpecialRenderer.ts b/src/render/SpecialRenderer.ts index 261c20b9..8510e4c6 100644 --- a/src/render/SpecialRenderer.ts +++ b/src/render/SpecialRenderer.ts @@ -8,6 +8,7 @@ import { Mesh } from './Mesh.js' import type { TextureAtlasProvider } from './TextureAtlas.js' import { DyeColors } from './DyeColors.js' import type { NbtCompound, NbtList } from '../nbt/index.js' +import { NbtType } from '../nbt/index.js' function liquidRenderer(type: string, level: number, atlas: TextureAtlasProvider, cull: Cull, tintindex?: number) { const y = cull['up'] ? 16 : [14.2, 12.5, 10.5, 9, 7, 5.3, 3.7, 1.9, 16, 16, 16, 16, 16, 16, 16, 16][level] @@ -1001,7 +1002,7 @@ export namespace SpecialRenderers { mat4.rotateY(t, t, rotation) mat4.scale(t, t, [2/3, 2/3, 2/3]) mat4.translate(t, t, [-8, -24, -8]) - mesh.merge(bannerRenderer(atlas, nbt?.getList('patterns', 10)).transform(t)) + mesh.merge(bannerRenderer(atlas, nbt?.getList('patterns', NbtType.Compound)).transform(t)) } const wallBannerRenderer = WallBannerRenderers.get(state.getName().toString()) if (wallBannerRenderer !== undefined) { @@ -1011,7 +1012,7 @@ export namespace SpecialRenderers { mat4.rotateY(t, t, facing === 'east' ? Math.PI / 2 : facing === 'north' ? Math.PI : facing === 'west' ? Math.PI * 3 / 2 : 0) mat4.scale(t, t, [2/3, 2/3, 2/3]) mat4.translate(t, t, [-8, -23.2, -8]) - mesh.merge(wallBannerRenderer(atlas, nbt?.getList('patterns', 10)).transform(t)) + mesh.merge(wallBannerRenderer(atlas, nbt?.getList('patterns', NbtType.Compound)).transform(t)) } if (!state.is('water') && !state.is('lava') && state.isWaterlogged()) { From 27e4ad4fd9553438d6a8fcad842b011a284ae2b6 Mon Sep 17 00:00:00 2001 From: Misode Date: Sat, 12 Apr 2025 17:39:32 +0200 Subject: [PATCH 11/13] Don't use PlacedBlock in special renderer --- src/render/ChunkBuilder.ts | 2 +- src/render/SpecialRenderer.ts | 73 +++++++++++++++++------------------ 2 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/render/ChunkBuilder.ts b/src/render/ChunkBuilder.ts index aea5a9c4..b231a36f 100644 --- a/src/render/ChunkBuilder.ts +++ b/src/render/ChunkBuilder.ts @@ -69,7 +69,7 @@ export class ChunkBuilder { if (blockDefinition) { mesh.merge(blockDefinition.getMesh(blockName, blockProps, this.resources, this.resources, cull)) } - const specialMesh = SpecialRenderers.getBlockMesh(b, this.resources, cull) + const specialMesh = SpecialRenderers.getBlockMesh(b.state, b.nbt, this.resources, cull) if (!specialMesh.isEmpty()) { mesh.merge(specialMesh) } diff --git a/src/render/SpecialRenderer.ts b/src/render/SpecialRenderer.ts index 8510e4c6..ca487572 100644 --- a/src/render/SpecialRenderer.ts +++ b/src/render/SpecialRenderer.ts @@ -1,14 +1,14 @@ import { mat4 } from 'gl-matrix' -import type { BlockState, PlacedBlock } from '../core/index.js' +import type { BlockState } from '../core/index.js' import { Direction, Identifier } from '../core/index.js' +import type { NbtCompound, NbtList } from '../nbt/index.js' +import { NbtType } from '../nbt/index.js' import { BlockColors } from './BlockColors.js' import { BlockModel } from './BlockModel.js' import { Cull } from './Cull.js' +import { DyeColors } from './DyeColors.js' import { Mesh } from './Mesh.js' import type { TextureAtlasProvider } from './TextureAtlas.js' -import { DyeColors } from './DyeColors.js' -import type { NbtCompound, NbtList } from '../nbt/index.js' -import { NbtType } from '../nbt/index.js' function liquidRenderer(type: string, level: number, atlas: TextureAtlasProvider, cull: Cull, tintindex?: number) { const y = cull['up'] ? 16 : [14.2, 12.5, 10.5, 9, 7, 5.3, 3.7, 1.9, 16, 16, 16, 16, 16, 16, 16, 16][level] @@ -888,41 +888,38 @@ export namespace SpecialRenderers { ) ) - export function getBlockMesh(block: PlacedBlock, atlas: TextureAtlasProvider, cull: Cull): Mesh { - const state = block.state - const nbt = block.nbt - + export function getBlockMesh(block: BlockState, nbt: NbtCompound, atlas: TextureAtlasProvider, cull: Cull): Mesh { const mesh = new Mesh() - if (state.is('water')) { - mesh.merge(liquidRenderer('water', getInt(state, 'level'), atlas, cull, 0)) + if (block.is('water')) { + mesh.merge(liquidRenderer('water', getInt(block, 'level'), atlas, cull, 0)) } - if (state.is('lava')) { - mesh.merge(liquidRenderer('lava', getInt(state, 'level'), atlas, cull)) + if (block.is('lava')) { + mesh.merge(liquidRenderer('lava', getInt(block, 'level'), atlas, cull)) } - const chestRenderer = ChestRenderers.get(state.getName().toString()) + const chestRenderer = ChestRenderers.get(block.getName().toString()) if (chestRenderer !== undefined) { - const facing = getStr(state, 'facing', 'south') + const facing = getStr(block, 'facing', 'south') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, facing === 'west' ? Math.PI / 2 : facing === 'south' ? Math.PI : facing === 'east' ? Math.PI * 3 / 2 : 0) mat4.translate(t, t, [-8, -8, -8]) mesh.merge(chestRenderer(atlas).transform(t)) } - if (state.is('decorated_pot')) { + if (block.is('decorated_pot')) { mesh.merge(decoratedPotRenderer(atlas)) } - const skullRenderer = SkullRenderers.get(state.getName().toString()) + const skullRenderer = SkullRenderers.get(block.getName().toString()) if (skullRenderer !== undefined) { - const rotation = getInt(state, 'rotation') / 16 * Math.PI * 2 + const rotation = getInt(block, 'rotation') / 16 * Math.PI * 2 const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, rotation) mat4.translate(t, t, [-8, -8, -8]) mesh.merge(skullRenderer(atlas).transform(t)) } - const signRenderer = SignRenderers.get(state.getName().toString()) + const signRenderer = SignRenderers.get(block.getName().toString()) if (signRenderer !== undefined) { - const rotation = getInt(state, 'rotation') / 16 * Math.PI * 2 + const rotation = getInt(block, 'rotation') / 16 * Math.PI * 2 const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, rotation) @@ -930,9 +927,9 @@ export namespace SpecialRenderers { mat4.translate(t, t, [-8, -8, -8]) mesh.merge(signRenderer(atlas).transform(t)) } - const wallSignRenderer = WallSignRenderers.get(state.getName().toString()) + const wallSignRenderer = WallSignRenderers.get(block.getName().toString()) if (wallSignRenderer !== undefined) { - const facing = getStr(state, 'facing', 'south') + const facing = getStr(block, 'facing', 'south') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, facing === 'west' ? Math.PI / 2 : facing === 'south' ? Math.PI : facing === 'east' ? Math.PI * 3 / 2 : 0) @@ -940,10 +937,10 @@ export namespace SpecialRenderers { mat4.translate(t, t, [-8, -8, -8]) mesh.merge(wallSignRenderer(atlas).transform(t)) } - const hangingSignRenderer = HangingSignRenderers.get(state.getName().toString()) + const hangingSignRenderer = HangingSignRenderers.get(block.getName().toString()) if (hangingSignRenderer !== undefined) { - const attached = getStr(state, 'attached', 'false') === 'true' - const rotation = getInt(state, 'rotation') / 16 * Math.PI * 2 + const attached = getStr(block, 'attached', 'false') === 'true' + const rotation = getInt(block, 'rotation') / 16 * Math.PI * 2 const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, rotation) @@ -951,21 +948,21 @@ export namespace SpecialRenderers { mat4.translate(t, t, [-8, -8, -8]) mesh.merge(hangingSignRenderer(attached, atlas).transform(t)) } - const wallHangingSignRenderer = WallHangingSignRenderers.get(state.getName().toString()) + const wallHangingSignRenderer = WallHangingSignRenderers.get(block.getName().toString()) if (wallHangingSignRenderer !== undefined) { - const facing = getStr(state, 'facing', 'south') + const facing = getStr(block, 'facing', 'south') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, facing === 'west' ? Math.PI / 2 : facing === 'south' ? Math.PI : facing === 'east' ? Math.PI * 3 / 2 : 0) mat4.translate(t, t, [-8, -8, -8]) mesh.merge(wallHangingSignRenderer(atlas).transform(t)) } - if (state.is('conduit')) { + if (block.is('conduit')) { mesh.merge(conduitRenderer(atlas)) } - const shulkerBoxRenderer = ShulkerBoxRenderers.get(state.getName().toString()) + const shulkerBoxRenderer = ShulkerBoxRenderers.get(block.getName().toString()) if (shulkerBoxRenderer !== undefined) { - const facing = getStr(state, 'facing', 'up') + const facing = getStr(block, 'facing', 'up') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) if (facing === 'down') { @@ -977,26 +974,26 @@ export namespace SpecialRenderers { mat4.translate(t, t, [-8, -8, -8]) mesh.merge(shulkerBoxRenderer(atlas).transform(t)) } - if (state.is('bell')) { + if (block.is('bell')) { const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.scale(t, t, [1, -1, -1]) mat4.translate(t, t, [-8, -8, -8]) mesh.merge(bellRenderer(atlas).transform(t)) } - const bedRenderer = BedRenderers.get(state.getName().toString()) + const bedRenderer = BedRenderers.get(block.getName().toString()) if (bedRenderer !== undefined) { - const part = getStr(state, 'part', 'head') - const facing = getStr(state, 'facing', 'south') + const part = getStr(block, 'part', 'head') + const facing = getStr(block, 'facing', 'south') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, facing === 'east' ? Math.PI / 2 : facing === 'north' ? Math.PI : facing === 'west' ? Math.PI * 3 / 2 : 0) mat4.translate(t, t, [-8, -8, -8]) mesh.merge(bedRenderer(part, atlas).transform(t)) } - const bannerRenderer = BannerRenderers.get(state.getName().toString()) + const bannerRenderer = BannerRenderers.get(block.getName().toString()) if (bannerRenderer !== undefined) { - const rotation = getInt(state, 'rotation') / 16 * Math.PI * 2 + const rotation = getInt(block, 'rotation') / 16 * Math.PI * 2 const t = mat4.create() mat4.translate(t, t, [8, 24, 8]) mat4.rotateY(t, t, rotation) @@ -1004,9 +1001,9 @@ export namespace SpecialRenderers { mat4.translate(t, t, [-8, -24, -8]) mesh.merge(bannerRenderer(atlas, nbt?.getList('patterns', NbtType.Compound)).transform(t)) } - const wallBannerRenderer = WallBannerRenderers.get(state.getName().toString()) + const wallBannerRenderer = WallBannerRenderers.get(block.getName().toString()) if (wallBannerRenderer !== undefined) { - const facing = getStr(state, 'facing', 'south') + const facing = getStr(block, 'facing', 'south') const t = mat4.create() mat4.translate(t, t, [8, 8, 8]) mat4.rotateY(t, t, facing === 'east' ? Math.PI / 2 : facing === 'north' ? Math.PI : facing === 'west' ? Math.PI * 3 / 2 : 0) @@ -1015,7 +1012,7 @@ export namespace SpecialRenderers { mesh.merge(wallBannerRenderer(atlas, nbt?.getList('patterns', NbtType.Compound)).transform(t)) } - if (!state.is('water') && !state.is('lava') && state.isWaterlogged()) { + if (!block.is('water') && !block.is('lava') && block.isWaterlogged()) { mesh.merge(liquidRenderer('water', 0, atlas, cull, 0)) } From 378c105da3f6440ef2fa2cde5303535f830fc030 Mon Sep 17 00:00:00 2001 From: Misode Date: Sat, 12 Apr 2025 17:43:14 +0200 Subject: [PATCH 12/13] Simplify DyeColors --- src/render/DyeColors.ts | 39 ----------------------------------- src/render/SpecialRenderer.ts | 24 ++++++++++++++++++--- 2 files changed, 21 insertions(+), 42 deletions(-) delete mode 100644 src/render/DyeColors.ts diff --git a/src/render/DyeColors.ts b/src/render/DyeColors.ts deleted file mode 100644 index bbac2d11..00000000 --- a/src/render/DyeColors.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Color } from '../util/index.js' - -const white = Color.intToRgb(16383998) -const orange = Color.intToRgb(16351261) -const magenta = Color.intToRgb(13061821) -const light_blue = Color.intToRgb(3847130) -const yellow = Color.intToRgb(16701501) -const lime = Color.intToRgb(8439583) -const pink = Color.intToRgb(15961002) -const gray = Color.intToRgb(4673362) -const light_gray = Color.intToRgb(10329495) -const cyan = Color.intToRgb(1481884) -const purple = Color.intToRgb(8991416) -const blue = Color.intToRgb(3949738) -const brown = Color.intToRgb(8606770) -const green = Color.intToRgb(6192150) -const red = Color.intToRgb(11546150) -const black = Color.intToRgb(1908001) - -export const DyeColors: { - [key: string]: (props: { [key: string]: string }) => Color, -} = { - white: () => white, - orange: () => orange, - magenta: () => magenta, - light_blue: () => light_blue, - yellow: () => yellow, - lime: () => lime, - pink: () => pink, - gray: () => gray, - light_gray: () => light_gray, - cyan: () => cyan, - purple: () => purple, - blue: () => blue, - brown: () => brown, - green: () => green, - red: () => red, - black: () => black, -} diff --git a/src/render/SpecialRenderer.ts b/src/render/SpecialRenderer.ts index ca487572..7e081dca 100644 --- a/src/render/SpecialRenderer.ts +++ b/src/render/SpecialRenderer.ts @@ -3,10 +3,10 @@ import type { BlockState } from '../core/index.js' import { Direction, Identifier } from '../core/index.js' import type { NbtCompound, NbtList } from '../nbt/index.js' import { NbtType } from '../nbt/index.js' +import { Color } from '../util/index.js' import { BlockColors } from './BlockColors.js' import { BlockModel } from './BlockModel.js' import { Cull } from './Cull.js' -import { DyeColors } from './DyeColors.js' import { Mesh } from './Mesh.js' import type { TextureAtlasProvider } from './TextureAtlas.js' @@ -29,6 +29,24 @@ function liquidRenderer(type: string, level: number, atlas: TextureAtlasProvider }]).getMesh(atlas, cull, BlockColors[type]?.({})) } +const DyeColors: Record = { + white: Color.intToRgb(16383998), + orange: Color.intToRgb(16351261), + magenta: Color.intToRgb(13061821), + light_blue: Color.intToRgb(3847130), + yellow: Color.intToRgb(16701501), + lime: Color.intToRgb(8439583), + pink: Color.intToRgb(15961002), + gray: Color.intToRgb(4673362), + light_gray: Color.intToRgb(10329495), + cyan: Color.intToRgb(1481884), + purple: Color.intToRgb(8991416), + blue: Color.intToRgb(3949738), + brown: Color.intToRgb(8606770), + green: Color.intToRgb(6192150), + red: Color.intToRgb(11546150), + black: Color.intToRgb(1908001), +} export namespace SpecialRenderers { export function chestRenderer(texture: Identifier) { @@ -624,7 +642,7 @@ export namespace SpecialRenderers { }) return new BlockModel(undefined, textures, elements) - .getMesh(atlas, Cull.none(), (index: number) => DyeColors[colors[index]]?.({})) + .getMesh(atlas, Cull.none(), (index: number) => DyeColors[colors[index]]) } } @@ -888,7 +906,7 @@ export namespace SpecialRenderers { ) ) - export function getBlockMesh(block: BlockState, nbt: NbtCompound, atlas: TextureAtlasProvider, cull: Cull): Mesh { + export function getBlockMesh(block: BlockState, nbt: NbtCompound | undefined, atlas: TextureAtlasProvider, cull: Cull): Mesh { const mesh = new Mesh() if (block.is('water')) { mesh.merge(liquidRenderer('water', getInt(block, 'level'), atlas, cull, 0)) From 0b04c7d417c2100553f5159f010fa1f4e9d8a038 Mon Sep 17 00:00:00 2001 From: Misode Date: Sat, 12 Apr 2025 17:49:12 +0200 Subject: [PATCH 13/13] Allow whitespace in ItemStack string parser --- src/core/ItemStack.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/ItemStack.ts b/src/core/ItemStack.ts index c70d8595..6b21283b 100644 --- a/src/core/ItemStack.ts +++ b/src/core/ItemStack.ts @@ -120,22 +120,26 @@ export class ItemStack { do{ if (reader.peek() === '!'){ reader.skip() + reader.skipWhitespace() const start = reader.cursor while (reader.canRead() && reader.peek() !== ']' && reader.peek() !== ',') { reader.skip() } - components.set('!' + Identifier.parse(reader.getRead(start)).toString(), new NbtCompound()) + components.set('!' + Identifier.parse(reader.getRead(start).trim()).toString(), new NbtCompound()) } else { + reader.skipWhitespace() const start = reader.cursor while (reader.canRead() && reader.peek() !== '=') { reader.skip() } - const component = Identifier.parse(reader.getRead(start)).toString() + const component = Identifier.parse(reader.getRead(start).trim()).toString() if (!reader.canRead()) break reader.skip() + reader.skipWhitespace() const tag = NbtParser.readTag(reader) components.set(component, tag) } + reader.skipWhitespace() if (!reader.canRead()) break if (reader.peek() === ']'){ return new ItemStack(itemId, 1, components)