rm blocks hardcode
This commit is contained in:
parent
561a18527f
commit
a19d459e8a
7 changed files with 298 additions and 311 deletions
|
|
@ -99,7 +99,7 @@ const handleMessage = data => {
|
|||
allDataReady = true
|
||||
workerIndex = data.workerIndex
|
||||
world.instancedBlocks = data.instancedBlocks
|
||||
world.instancedBlockIds = data.instancedBlockIds || new Map()
|
||||
world.instancedBlockIds = data.instancedBlockIds || {}
|
||||
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,140 +7,6 @@ import { BlockElement, buildRotationMatrix, elemFaces, matmul3, matmulmat3, veca
|
|||
import { INVISIBLE_BLOCKS } from './worldConstants'
|
||||
import { MesherGeometryOutput, HighestBlockInfo, InstancedBlockEntry, InstancingMode } from './shared'
|
||||
|
||||
// Hardcoded list of full blocks that can use instancing
|
||||
export const INSTANCEABLE_BLOCKS = new Set([
|
||||
'grass_block',
|
||||
'dirt',
|
||||
'stone',
|
||||
'cobblestone',
|
||||
'mossy_cobblestone',
|
||||
'clay',
|
||||
'moss_block',
|
||||
'spawner',
|
||||
'sand',
|
||||
'gravel',
|
||||
'oak_planks',
|
||||
'birch_planks',
|
||||
'spruce_planks',
|
||||
'jungle_planks',
|
||||
'acacia_planks',
|
||||
'dark_oak_planks',
|
||||
'mangrove_planks',
|
||||
'cherry_planks',
|
||||
'bamboo_planks',
|
||||
'crimson_planks',
|
||||
'warped_planks',
|
||||
'iron_block',
|
||||
'gold_block',
|
||||
'diamond_block',
|
||||
'emerald_block',
|
||||
'netherite_block',
|
||||
'coal_block',
|
||||
'redstone_block',
|
||||
'lapis_block',
|
||||
'copper_block',
|
||||
'exposed_copper',
|
||||
'weathered_copper',
|
||||
'oxidized_copper',
|
||||
'cut_copper',
|
||||
'exposed_cut_copper',
|
||||
'weathered_cut_copper',
|
||||
'oxidized_cut_copper',
|
||||
'waxed_copper_block',
|
||||
'waxed_exposed_copper',
|
||||
'waxed_weathered_copper',
|
||||
'waxed_oxidized_copper',
|
||||
'raw_iron_block',
|
||||
'raw_copper_block',
|
||||
'raw_gold_block',
|
||||
'smooth_stone',
|
||||
'cobbled_deepslate',
|
||||
'deepslate',
|
||||
'calcite',
|
||||
'tuff',
|
||||
'dripstone_block',
|
||||
'amethyst_block',
|
||||
'budding_amethyst',
|
||||
'obsidian',
|
||||
'crying_obsidian',
|
||||
'bedrock',
|
||||
'end_stone',
|
||||
'purpur_block',
|
||||
'quartz_block',
|
||||
'smooth_quartz',
|
||||
'nether_bricks',
|
||||
'red_nether_bricks',
|
||||
'blackstone',
|
||||
'gilded_blackstone',
|
||||
'polished_blackstone',
|
||||
'chiseled_nether_bricks',
|
||||
'cracked_nether_bricks',
|
||||
'basalt',
|
||||
'smooth_basalt',
|
||||
'polished_basalt',
|
||||
'netherrack',
|
||||
'magma_block',
|
||||
'soul_sand',
|
||||
'soul_soil',
|
||||
'ancient_debris',
|
||||
'bone_block',
|
||||
'packed_ice',
|
||||
'blue_ice',
|
||||
'ice',
|
||||
'snow_block',
|
||||
'powder_snow',
|
||||
'white_wool',
|
||||
'orange_wool',
|
||||
'magenta_wool',
|
||||
'light_blue_wool',
|
||||
'yellow_wool',
|
||||
'lime_wool',
|
||||
'pink_wool',
|
||||
'gray_wool',
|
||||
'light_gray_wool',
|
||||
'cyan_wool',
|
||||
'purple_wool',
|
||||
'blue_wool',
|
||||
'brown_wool',
|
||||
'green_wool',
|
||||
'red_wool',
|
||||
'black_wool',
|
||||
'white_concrete',
|
||||
'orange_concrete',
|
||||
'magenta_concrete',
|
||||
'light_blue_concrete',
|
||||
'yellow_concrete',
|
||||
'lime_concrete',
|
||||
'pink_concrete',
|
||||
'gray_concrete',
|
||||
'light_gray_concrete',
|
||||
'cyan_concrete',
|
||||
'purple_concrete',
|
||||
'blue_concrete',
|
||||
'brown_concrete',
|
||||
'green_concrete',
|
||||
'red_concrete',
|
||||
'black_concrete',
|
||||
'white_terracotta',
|
||||
'orange_terracotta',
|
||||
'magenta_terracotta',
|
||||
'light_blue_terracotta',
|
||||
'yellow_terracotta',
|
||||
'lime_terracotta',
|
||||
'pink_terracotta',
|
||||
'gray_terracotta',
|
||||
'light_gray_terracotta',
|
||||
'cyan_terracotta',
|
||||
'purple_terracotta',
|
||||
'blue_terracotta',
|
||||
'brown_terracotta',
|
||||
'green_terracotta',
|
||||
'red_terracotta',
|
||||
'black_terracotta',
|
||||
'terracotta',
|
||||
'glazed_terracotta',
|
||||
])
|
||||
|
||||
let blockProvider: WorldBlockProvider
|
||||
|
||||
const tints: any = {}
|
||||
|
|
@ -720,9 +586,14 @@ const getInstancedBlockTextureInfo = (block: Block) => {
|
|||
return textureInfo
|
||||
}
|
||||
|
||||
const isBlockInstanceable = (block: Block): boolean => {
|
||||
// Only instanceable if it's a full cube block without complex geometry
|
||||
if (!INSTANCEABLE_BLOCKS.has(block.name)) return false
|
||||
const isBlockInstanceable = (world: World, block: Block): boolean => {
|
||||
// Use dynamic instanceable blocks data if available
|
||||
const instancedBlocks = world?.instancedBlocks
|
||||
if (Array.isArray(instancedBlocks)) {
|
||||
if (!instancedBlocks.includes(block.name)) return false
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if it's actually a full cube (no rotations, no complex models)
|
||||
if (!block.models || block.models.length !== 1) return false
|
||||
|
|
@ -839,7 +710,7 @@ export function getSectionGeometry (sx: number, sy: number, sz: number, world: W
|
|||
}
|
||||
if (block.name !== 'water' && block.name !== 'lava' && !INVISIBLE_BLOCKS.has(block.name)) {
|
||||
// Check if this block can use instanced rendering
|
||||
if (enableInstancedRendering && isBlockInstanceable(block)) {
|
||||
if (enableInstancedRendering && isBlockInstanceable(world, block)) {
|
||||
// Check if block should be culled (all faces hidden by neighbors)
|
||||
if (shouldCullInstancedBlock(world, cursor, block)) {
|
||||
// Block is completely surrounded, skip rendering
|
||||
|
|
@ -850,18 +721,16 @@ export function getSectionGeometry (sx: number, sy: number, sz: number, world: W
|
|||
if (!attr.instancedBlocks[blockKey]) {
|
||||
const textureInfo = getInstancedBlockTextureInfo(block)
|
||||
// Get or create block ID
|
||||
let blockId = world.instancedBlockIds.get(block.name)
|
||||
if (blockId === undefined) {
|
||||
blockId = world.instancedBlockIds.size
|
||||
world.instancedBlockIds.set(block.name, blockId)
|
||||
}
|
||||
const blockId = world.instancedBlockIds[block.stateId]
|
||||
|
||||
attr.instancedBlocks[blockKey] = {
|
||||
blockId,
|
||||
blockName: block.name,
|
||||
stateId: block.stateId,
|
||||
textureInfo,
|
||||
positions: []
|
||||
if (blockId !== undefined) {
|
||||
attr.instancedBlocks[blockKey] = {
|
||||
blockId,
|
||||
blockName: block.name,
|
||||
stateId: block.stateId,
|
||||
textureInfo,
|
||||
positions: []
|
||||
}
|
||||
}
|
||||
}
|
||||
attr.instancedBlocks[blockKey].positions.push({
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ export class World {
|
|||
sentBlockStateModels = new Set<string>()
|
||||
blockStateModelInfo = new Map<string, BlockStateModelInfo>()
|
||||
instancedBlocks: Record<string, any> = {}
|
||||
instancedBlockIds = new Map<string, number>()
|
||||
instancedBlockIds = {} as Record<string, number>
|
||||
|
||||
constructor (version: string) {
|
||||
this.Chunk = Chunks(version) as any
|
||||
|
|
@ -123,7 +123,6 @@ export class World {
|
|||
if (!(pos instanceof Vec3)) pos = new Vec3(...pos as [number, number, number])
|
||||
const key = columnKey(Math.floor(pos.x / 16) * 16, Math.floor(pos.z / 16) * 16)
|
||||
const blockPosKey = `${pos.x},${pos.y},${pos.z}`
|
||||
const modelOverride = this.customBlockModels.get(key)?.[blockPosKey]
|
||||
|
||||
const column = this.columns[key]
|
||||
// null column means chunk not loaded
|
||||
|
|
@ -133,6 +132,7 @@ export class World {
|
|||
const locInChunk = posInChunk(loc)
|
||||
const stateId = column.getBlockStateId(locInChunk)
|
||||
|
||||
const modelOverride = stateId ? this.customBlockModels.get(key)?.[blockPosKey] : undefined
|
||||
const cacheKey = getBlockAssetsCacheKey(stateId, modelOverride)
|
||||
|
||||
if (!this.blockCache[cacheKey]) {
|
||||
|
|
|
|||
|
|
@ -160,6 +160,9 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|||
|
||||
abstract changeBackgroundColor (color: [number, number, number]): void
|
||||
|
||||
// Optional method for getting instanced blocks data (implemented by Three.js renderer)
|
||||
getInstancedBlocksData? (): { instanceableBlocks: Set<string>, allBlocksStateIdToModelIdMap: Record<number, number> } | undefined
|
||||
|
||||
worldRendererConfig: WorldRendererConfig
|
||||
playerStateReactive: PlayerStateReactive
|
||||
playerStateUtils: PlayerStateUtils
|
||||
|
|
@ -596,6 +599,10 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|||
const resources = this.resourcesManager.currentResources
|
||||
|
||||
if (this.workers.length === 0) throw new Error('workers not initialized yet')
|
||||
|
||||
// Get instanceable blocks data if available (Three.js specific)
|
||||
const instancedBlocksData = this.getInstancedBlocksData?.()
|
||||
|
||||
for (const [i, worker] of this.workers.entries()) {
|
||||
const { blockstatesModels } = resources
|
||||
|
||||
|
|
@ -607,6 +614,8 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|||
},
|
||||
blockstatesModels,
|
||||
config: this.getMesherConfig(),
|
||||
instancedBlocks: instancedBlocksData?.instanceableBlocks ? [...instancedBlocksData.instanceableBlocks] : [],
|
||||
instancedBlockIds: instancedBlocksData?.allBlocksStateIdToModelIdMap || {}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
30
renderer/viewer/three/getPreflatBlock.ts
Normal file
30
renderer/viewer/three/getPreflatBlock.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import legacyJson from '../../../src/preflatMap.json'
|
||||
|
||||
export const getPreflatBlock = (block, reportIssue?: () => void) => {
|
||||
const b = block
|
||||
b._properties = {}
|
||||
|
||||
const namePropsStr = legacyJson.blocks[b.type + ':' + b.metadata] || findClosestLegacyBlockFallback(b.type, b.metadata, reportIssue)
|
||||
if (namePropsStr) {
|
||||
b.name = namePropsStr.split('[')[0]
|
||||
const propsStr = namePropsStr.split('[')?.[1]?.split(']')
|
||||
if (propsStr) {
|
||||
const newProperties = Object.fromEntries(propsStr.join('').split(',').map(x => {
|
||||
let [key, val] = x.split('=')
|
||||
if (!isNaN(val)) val = parseInt(val, 10)
|
||||
return [key, val]
|
||||
}))
|
||||
b._properties = newProperties
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
const findClosestLegacyBlockFallback = (id, metadata, reportIssue) => {
|
||||
reportIssue?.()
|
||||
for (const [key, value] of Object.entries(legacyJson.blocks)) {
|
||||
const [idKey, meta] = key.split(':')
|
||||
if (idKey === id) return value
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
|
@ -1,142 +1,12 @@
|
|||
import * as THREE from 'three'
|
||||
import { Vec3 } from 'vec3'
|
||||
import { versionToNumber } from 'flying-squid/dist/utils'
|
||||
import PrismarineBlock, { Block } from 'prismarine-block'
|
||||
import { IndexedBlock } from 'minecraft-data'
|
||||
import moreBlockData from '../lib/moreBlockDataGenerated.json'
|
||||
import { getPreflatBlock } from './getPreflatBlock'
|
||||
import { WorldRendererThree } from './worldrendererThree'
|
||||
|
||||
// Hardcoded list of full blocks that can use instancing
|
||||
export const INSTANCEABLE_BLOCKS = new Set([
|
||||
'grass_block',
|
||||
'dirt',
|
||||
'stone',
|
||||
'cobblestone',
|
||||
'mossy_cobblestone',
|
||||
'clay',
|
||||
'moss_block',
|
||||
'spawner',
|
||||
'sand',
|
||||
'gravel',
|
||||
'oak_planks',
|
||||
'birch_planks',
|
||||
'spruce_planks',
|
||||
'jungle_planks',
|
||||
'acacia_planks',
|
||||
'dark_oak_planks',
|
||||
'mangrove_planks',
|
||||
'cherry_planks',
|
||||
'bamboo_planks',
|
||||
'crimson_planks',
|
||||
'warped_planks',
|
||||
'iron_block',
|
||||
'gold_block',
|
||||
'diamond_block',
|
||||
'emerald_block',
|
||||
'netherite_block',
|
||||
'coal_block',
|
||||
'redstone_block',
|
||||
'lapis_block',
|
||||
'copper_block',
|
||||
'exposed_copper',
|
||||
'weathered_copper',
|
||||
'oxidized_copper',
|
||||
'cut_copper',
|
||||
'exposed_cut_copper',
|
||||
'weathered_cut_copper',
|
||||
'oxidized_cut_copper',
|
||||
'waxed_copper_block',
|
||||
'waxed_exposed_copper',
|
||||
'waxed_weathered_copper',
|
||||
'waxed_oxidized_copper',
|
||||
'raw_iron_block',
|
||||
'raw_copper_block',
|
||||
'raw_gold_block',
|
||||
'smooth_stone',
|
||||
'cobbled_deepslate',
|
||||
'deepslate',
|
||||
'calcite',
|
||||
'tuff',
|
||||
'dripstone_block',
|
||||
'amethyst_block',
|
||||
'budding_amethyst',
|
||||
'obsidian',
|
||||
'crying_obsidian',
|
||||
'bedrock',
|
||||
'end_stone',
|
||||
'purpur_block',
|
||||
'quartz_block',
|
||||
'smooth_quartz',
|
||||
'nether_bricks',
|
||||
'red_nether_bricks',
|
||||
'blackstone',
|
||||
'gilded_blackstone',
|
||||
'polished_blackstone',
|
||||
'chiseled_nether_bricks',
|
||||
'cracked_nether_bricks',
|
||||
'basalt',
|
||||
'smooth_basalt',
|
||||
'polished_basalt',
|
||||
'netherrack',
|
||||
'magma_block',
|
||||
'soul_sand',
|
||||
'soul_soil',
|
||||
'ancient_debris',
|
||||
'bone_block',
|
||||
'packed_ice',
|
||||
'blue_ice',
|
||||
'ice',
|
||||
'snow_block',
|
||||
'powder_snow',
|
||||
'white_wool',
|
||||
'orange_wool',
|
||||
'magenta_wool',
|
||||
'light_blue_wool',
|
||||
'yellow_wool',
|
||||
'lime_wool',
|
||||
'pink_wool',
|
||||
'gray_wool',
|
||||
'light_gray_wool',
|
||||
'cyan_wool',
|
||||
'purple_wool',
|
||||
'blue_wool',
|
||||
'brown_wool',
|
||||
'green_wool',
|
||||
'red_wool',
|
||||
'black_wool',
|
||||
'white_concrete',
|
||||
'orange_concrete',
|
||||
'magenta_concrete',
|
||||
'light_blue_concrete',
|
||||
'yellow_concrete',
|
||||
'lime_concrete',
|
||||
'pink_concrete',
|
||||
'gray_concrete',
|
||||
'light_gray_concrete',
|
||||
'cyan_concrete',
|
||||
'purple_concrete',
|
||||
'blue_concrete',
|
||||
'brown_concrete',
|
||||
'green_concrete',
|
||||
'red_concrete',
|
||||
'black_concrete',
|
||||
'white_terracotta',
|
||||
'orange_terracotta',
|
||||
'magenta_terracotta',
|
||||
'light_blue_terracotta',
|
||||
'yellow_terracotta',
|
||||
'lime_terracotta',
|
||||
'pink_terracotta',
|
||||
'gray_terracotta',
|
||||
'light_gray_terracotta',
|
||||
'cyan_terracotta',
|
||||
'purple_terracotta',
|
||||
'blue_terracotta',
|
||||
'brown_terracotta',
|
||||
'green_terracotta',
|
||||
'red_terracotta',
|
||||
'black_terracotta',
|
||||
'terracotta',
|
||||
'glazed_terracotta',
|
||||
])
|
||||
|
||||
// Helper function to parse RGB color strings from moreBlockDataGenerated.json
|
||||
function parseRgbColor (rgbString: string): number {
|
||||
const match = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/.exec(rgbString)
|
||||
|
|
@ -162,6 +32,21 @@ export interface InstancedSectionData {
|
|||
shouldUseInstancedOnly: boolean
|
||||
}
|
||||
|
||||
export interface InstancedBlockModelData {
|
||||
textures: number[]
|
||||
rotation: number[]
|
||||
transparent?: boolean
|
||||
emitLight?: number
|
||||
filterLight?: number
|
||||
}
|
||||
|
||||
export interface InstancedBlocksConfig {
|
||||
instanceableBlocks: Set<string>
|
||||
blocksDataModel: Record<string, InstancedBlockModelData>
|
||||
allBlocksStateIdToModelIdMap: Record<number, number>
|
||||
interestedTextureTiles: Set<string>
|
||||
}
|
||||
|
||||
export class InstancedRenderer {
|
||||
private readonly instancedMeshes = new Map<number, THREE.InstancedMesh>()
|
||||
private readonly blockCounts = new Map<number, number>()
|
||||
|
|
@ -173,9 +58,191 @@ export class InstancedRenderer {
|
|||
private readonly blockNameToId = new Map<string, number>()
|
||||
private nextBlockId = 0
|
||||
|
||||
// New properties for dynamic block detection
|
||||
private instancedBlocksConfig: InstancedBlocksConfig | null = null
|
||||
|
||||
constructor (private readonly worldRenderer: WorldRendererThree) {
|
||||
this.cubeGeometry = this.createCubeGeometry()
|
||||
this.initInstancedMeshes()
|
||||
}
|
||||
|
||||
prepareInstancedBlocksData (): InstancedBlocksConfig {
|
||||
const blocksMap = {
|
||||
'double_stone_slab': 'stone',
|
||||
'stone_slab': 'stone',
|
||||
'oak_stairs': 'planks',
|
||||
'stone_stairs': 'stone',
|
||||
'glass_pane': 'stained_glass',
|
||||
'brick_stairs': 'brick_block',
|
||||
'stone_brick_stairs': 'stonebrick',
|
||||
'nether_brick_stairs': 'nether_brick',
|
||||
'double_wooden_slab': 'planks',
|
||||
'wooden_slab': 'planks',
|
||||
'sandstone_stairs': 'sandstone',
|
||||
'cobblestone_wall': 'cobblestone',
|
||||
'quartz_stairs': 'quartz_block',
|
||||
'stained_glass_pane': 'stained_glass',
|
||||
'red_sandstone_stairs': 'red_sandstone',
|
||||
'stone_slab2': 'stone_slab',
|
||||
'purpur_stairs': 'purpur_block',
|
||||
'purpur_slab': 'purpur_block',
|
||||
}
|
||||
|
||||
const isPreflat = versionToNumber(this.worldRenderer.version) < versionToNumber('1.13')
|
||||
const PBlockOriginal = PrismarineBlock(this.worldRenderer.version)
|
||||
|
||||
const instanceableBlocks = new Set<string>()
|
||||
const blocksDataModel = {} as Record<string, InstancedBlockModelData>
|
||||
const interestedTextureTiles = new Set<string>()
|
||||
const blocksProcessed = {} as Record<string, boolean>
|
||||
let i = 0
|
||||
const allBlocksStateIdToModelIdMap = {} as Record<number, number>
|
||||
|
||||
const addBlockModel = (state: number, name: string, props: Record<string, any>, mcBlockData?: IndexedBlock, defaultState = false) => {
|
||||
const possibleIssues = [] as string[]
|
||||
const { currentResources } = this.worldRenderer.resourcesManager
|
||||
if (!currentResources?.worldBlockProvider) return
|
||||
|
||||
const models = currentResources.worldBlockProvider.getAllResolvedModels0_1({
|
||||
name,
|
||||
properties: props
|
||||
}, isPreflat, possibleIssues, [], [], true)
|
||||
|
||||
// skipping composite blocks
|
||||
if (models.length !== 1 || !models[0]![0].elements) {
|
||||
return
|
||||
}
|
||||
const elements = models[0]![0]?.elements
|
||||
if (!elements || (elements.length !== 1 && name !== 'grass_block')) {
|
||||
return
|
||||
}
|
||||
const elem = elements[0]
|
||||
if (elem.from[0] !== 0 || elem.from[1] !== 0 || elem.from[2] !== 0 || elem.to[0] !== 16 || elem.to[1] !== 16 || elem.to[2] !== 16) {
|
||||
// not full block
|
||||
return
|
||||
}
|
||||
|
||||
const facesMapping = [
|
||||
['front', 'south'],
|
||||
['bottom', 'down'],
|
||||
['top', 'up'],
|
||||
['right', 'east'],
|
||||
['left', 'west'],
|
||||
['back', 'north'],
|
||||
]
|
||||
|
||||
const blockData: InstancedBlockModelData = {
|
||||
textures: [0, 0, 0, 0, 0, 0],
|
||||
rotation: [0, 0, 0, 0, 0, 0]
|
||||
}
|
||||
|
||||
for (const [face, { texture, cullface, rotation = 0 }] of Object.entries(elem.faces)) {
|
||||
const faceIndex = facesMapping.findIndex(x => x.includes(face))
|
||||
if (faceIndex === -1) {
|
||||
throw new Error(`Unknown face ${face}`)
|
||||
}
|
||||
|
||||
blockData.textures[faceIndex] = texture.tileIndex
|
||||
blockData.rotation[faceIndex] = rotation / 90
|
||||
if (Math.floor(blockData.rotation[faceIndex]) !== blockData.rotation[faceIndex]) {
|
||||
throw new Error(`Invalid rotation ${rotation} ${name}`)
|
||||
}
|
||||
interestedTextureTiles.add(texture.debugName)
|
||||
}
|
||||
|
||||
const k = i++
|
||||
allBlocksStateIdToModelIdMap[state] = k
|
||||
blocksDataModel[k] = blockData
|
||||
instanceableBlocks.add(name)
|
||||
blocksProcessed[name] = true
|
||||
|
||||
if (mcBlockData) {
|
||||
blockData.transparent = mcBlockData.transparent
|
||||
blockData.emitLight = mcBlockData.emitLight
|
||||
blockData.filterLight = mcBlockData.filterLight
|
||||
}
|
||||
}
|
||||
|
||||
// Add unknown block model
|
||||
addBlockModel(-1, 'unknown', {})
|
||||
|
||||
// Handle texture overrides for special blocks
|
||||
const textureOverrideFullBlocks = {
|
||||
water: 'water_still',
|
||||
lava: 'lava_still',
|
||||
}
|
||||
|
||||
// Process all blocks to find instanceable ones
|
||||
for (const b of (globalThis as any).loadedData.blocksArray) {
|
||||
for (let state = b.minStateId; state <= b.maxStateId; state++) {
|
||||
const mapping = blocksMap[b.name]
|
||||
const block = PBlockOriginal.fromStateId(mapping && (globalThis as any).loadedData.blocksByName[mapping] ? (globalThis as any).loadedData.blocksByName[mapping].defaultState : state, 0)
|
||||
if (isPreflat) {
|
||||
getPreflatBlock(block)
|
||||
}
|
||||
|
||||
const textureOverride = textureOverrideFullBlocks[block.name] as string | undefined
|
||||
if (textureOverride) {
|
||||
const k = i++
|
||||
const { currentResources } = this.worldRenderer.resourcesManager
|
||||
if (!currentResources?.worldBlockProvider) continue
|
||||
const texture = currentResources.worldBlockProvider.getTextureInfo(textureOverride)
|
||||
if (!texture) {
|
||||
console.warn('Missing texture override for', block.name)
|
||||
continue
|
||||
}
|
||||
const texIndex = texture.tileIndex
|
||||
allBlocksStateIdToModelIdMap[state] = k
|
||||
const blockData: InstancedBlockModelData = {
|
||||
textures: [texIndex, texIndex, texIndex, texIndex, texIndex, texIndex],
|
||||
rotation: [0, 0, 0, 0, 0, 0],
|
||||
filterLight: b.filterLight
|
||||
}
|
||||
blocksDataModel[k] = blockData
|
||||
instanceableBlocks.add(block.name)
|
||||
interestedTextureTiles.add(textureOverride)
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if block is a full cube
|
||||
if (block.shapes.length === 0 || !block.shapes.every(shape => {
|
||||
return shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1
|
||||
})) {
|
||||
continue
|
||||
}
|
||||
|
||||
addBlockModel(state, block.name, block.getProperties(), b, state === b.defaultState)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
instanceableBlocks,
|
||||
blocksDataModel,
|
||||
allBlocksStateIdToModelIdMap,
|
||||
interestedTextureTiles
|
||||
}
|
||||
}
|
||||
|
||||
initializeInstancedMeshes () {
|
||||
if (!this.instancedBlocksConfig) {
|
||||
console.warn('Instanced blocks config not prepared')
|
||||
return
|
||||
}
|
||||
|
||||
// Create InstancedMesh for each instanceable block type
|
||||
for (const blockName of this.instancedBlocksConfig.instanceableBlocks) {
|
||||
const material = this.createBlockMaterial(blockName)
|
||||
const mesh = new THREE.InstancedMesh(
|
||||
this.cubeGeometry,
|
||||
material,
|
||||
this.maxInstancesPerBlock
|
||||
)
|
||||
mesh.name = `instanced_${blockName}`
|
||||
mesh.frustumCulled = false // Important for performance
|
||||
mesh.count = 0 // Start with 0 instances
|
||||
|
||||
this.instancedMeshes.set(this.getBlockId(blockName), mesh)
|
||||
this.worldRenderer.scene.add(mesh)
|
||||
}
|
||||
}
|
||||
|
||||
private createCubeGeometry (): THREE.BoxGeometry {
|
||||
|
|
@ -210,24 +277,6 @@ export class InstancedRenderer {
|
|||
return geometry
|
||||
}
|
||||
|
||||
private initInstancedMeshes () {
|
||||
// Create InstancedMesh for each instanceable block type
|
||||
for (const blockName of INSTANCEABLE_BLOCKS) {
|
||||
const material = this.createBlockMaterial(blockName)
|
||||
const mesh = new THREE.InstancedMesh(
|
||||
this.cubeGeometry,
|
||||
material,
|
||||
this.maxInstancesPerBlock
|
||||
)
|
||||
mesh.name = `instanced_${blockName}`
|
||||
mesh.frustumCulled = false // Important for performance
|
||||
mesh.count = 0 // Start with 0 instances
|
||||
|
||||
this.instancedMeshes.set(this.getBlockId(blockName), mesh)
|
||||
this.worldRenderer.scene.add(mesh)
|
||||
}
|
||||
}
|
||||
|
||||
private createBlockMaterial (blockName: string, textureInfo?: { u: number, v: number, su: number, sv: number }): THREE.Material {
|
||||
const { enableSingleColorMode } = this.worldRenderer.worldRendererConfig
|
||||
|
||||
|
|
@ -270,7 +319,7 @@ export class InstancedRenderer {
|
|||
|
||||
// Add new instances
|
||||
for (const [blockName, blockData] of instancedBlocks) {
|
||||
if (!INSTANCEABLE_BLOCKS.has(blockName)) continue
|
||||
if (!this.isBlockInstanceable(blockName)) continue
|
||||
|
||||
const mesh = this.instancedMeshes.get(this.getBlockId(blockName))
|
||||
if (!mesh) continue
|
||||
|
|
@ -442,7 +491,7 @@ export class InstancedRenderer {
|
|||
}
|
||||
|
||||
isBlockInstanceable (blockName: string): boolean {
|
||||
return INSTANCEABLE_BLOCKS.has(blockName)
|
||||
return this.instancedBlocksConfig?.instanceableBlocks.has(blockName) ?? false
|
||||
}
|
||||
|
||||
updateMaterials () {
|
||||
|
|
@ -508,4 +557,20 @@ export class InstancedRenderer {
|
|||
}
|
||||
return blockId
|
||||
}
|
||||
|
||||
// New method to prepare and initialize everything
|
||||
prepareAndInitialize () {
|
||||
console.log('Preparing instanced blocks data...')
|
||||
this.instancedBlocksConfig = this.prepareInstancedBlocksData()
|
||||
console.log(`Found ${this.instancedBlocksConfig.instanceableBlocks.size} instanceable blocks:`,
|
||||
[...this.instancedBlocksConfig.instanceableBlocks].slice(0, 10).join(', '),
|
||||
this.instancedBlocksConfig.instanceableBlocks.size > 10 ? '...' : '')
|
||||
|
||||
this.initializeInstancedMeshes()
|
||||
}
|
||||
|
||||
// Method to get the current configuration
|
||||
getInstancedBlocksConfig (): InstancedBlocksConfig | null {
|
||||
return this.instancedBlocksConfig
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import { ThreeJsSound } from './threeJsSound'
|
|||
import { CameraShake } from './cameraShake'
|
||||
import { ThreeJsMedia } from './threeJsMedia'
|
||||
import { Fountain } from './threeJsParticles'
|
||||
import { InstancedRenderer, INSTANCEABLE_BLOCKS } from './instancedRenderer'
|
||||
import { InstancedRenderer } from './instancedRenderer'
|
||||
|
||||
type SectionKey = string
|
||||
|
||||
|
|
@ -97,8 +97,6 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|||
|
||||
this.addDebugOverlay()
|
||||
this.resetScene()
|
||||
void this.init()
|
||||
|
||||
this.soundSystem = new ThreeJsSound(this)
|
||||
this.cameraShake = new CameraShake(this, this.onRender)
|
||||
this.media = new ThreeJsMedia(this)
|
||||
|
|
@ -111,6 +109,8 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|||
this.finishChunk(chunkKey)
|
||||
})
|
||||
this.worldSwitchActions()
|
||||
|
||||
void this.init()
|
||||
}
|
||||
|
||||
get cameraObject () {
|
||||
|
|
@ -143,6 +143,16 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|||
}
|
||||
}
|
||||
|
||||
getInstancedBlocksData () {
|
||||
const config = this.instancedRenderer.getInstancedBlocksConfig()
|
||||
if (!config) return undefined
|
||||
|
||||
return {
|
||||
instanceableBlocks: config.instanceableBlocks,
|
||||
allBlocksStateIdToModelIdMap: config.allBlocksStateIdToModelIdMap
|
||||
}
|
||||
}
|
||||
|
||||
updatePlayerEntity (e: any) {
|
||||
this.entities.handlePlayerEntity(e)
|
||||
}
|
||||
|
|
@ -228,8 +238,12 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|||
oldItemsTexture.dispose()
|
||||
}
|
||||
|
||||
// Prepare and initialize instanced renderer with dynamic block detection
|
||||
this.instancedRenderer.prepareAndInitialize()
|
||||
|
||||
await super.updateAssetsData()
|
||||
this.onAllTexturesLoaded()
|
||||
|
||||
// Update instanced renderer materials when textures change
|
||||
this.instancedRenderer.updateMaterials()
|
||||
if (Object.keys(this.loadedChunks).length > 0) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue