Files
Emil c7e86663d8
MVP checks / mvp (push) Canceled after 0s
Expand voxel gameplay, lighting, full-height streaming and world imports
Add shared Rust/WASM physics, worker meshing and diagnostics, 64-chunk full-height streaming, atlas texture support, and baseline world import. Document the current implementation and include the supplied in-game lobby screenshot.
2026-09-17 02:10:53 +03:00

55 lines
3.2 KiB
JavaScript

import { SectionVoxelMap } from './section-voxel-map.js';
import { attachBlockLightSamplers } from './block-light.js';
import { applyLightProperties } from './light-properties.js';
import { buildSectionMesh } from './mesh-geometry.js';
import { textureSubset } from './texture-pack.js';
/** Copy only the edited section's sampling neighborhood, independent of view radius. */
export function captureEditMesh(id, blocks, materials, textures, field) {
const base=id.split(',').map(v=>Number(v)*16);
let pad=2;
for(const mat of materials.values()) for(const box of mat.render || [])
for(let axis=0;axis<3;axis++) pad=Math.max(pad,Math.ceil(-box.min[axis])+2,Math.ceil(box.max[axis]-1)+2);
const min=base.map(v=>v-pad),size=Array(3).fill(16+pad*2),sections=[];
for(let x=Math.floor(min[0]/16);x<=Math.floor((min[0]+size[0]-1)/16);x++)
for(let y=Math.floor(min[1]/16);y<=Math.floor((min[1]+size[1]-1)/16);y++)
for(let z=Math.floor(min[2]/16);z<=Math.floor((min[2]+size[2]-1)/16);z++) {
const section=`${x},${y},${z}`;
if(blocks.getSectionCells) {
const cells=blocks.getSectionCells(section);
if(cells) sections.push({section,cells:cells.slice()});
} else {
const cells=new Uint32Array(4096);
for(const key of (blocks.keysInSection ? blocks.keysInSection(section) : [...blocks.keys()].filter(key=>key.split(",").map(v=>Math.floor(Number(v)/16)).join(",")===section))) {
const p=key.split(',').map(Number);
cells[SectionVoxelMap.index(...p)]=blocks.get(key);
}
sections.push({section,cells});
}
}
let light=null;
if(field) {
const count=size[0]*size[1]*size[2];
light={min,size,data:new Uint8Array(count*4),blockLevels:new Uint8Array(count),skyLevels:new Uint8Array(count)};
const lo=min.map((v,i)=>Math.max(v,field.min[i])),hi=min.map((v,i)=>Math.min(v+size[i],field.min[i]+field.size[i]));
if(hi[0]>lo[0]) for(let z=lo[2];z<hi[2];z++)for(let y=lo[1];y<hi[1];y++) {
const src=lo[0]-field.min[0]+field.size[0]*(y-field.min[1]+field.size[1]*(z-field.min[2]));
const dst=lo[0]-min[0]+size[0]*(y-min[1]+size[1]*(z-min[2])),length=hi[0]-lo[0];
light.data.set(field.data.subarray(src*4,(src+length)*4),dst*4);
light.blockLevels.set(field.blockLevels.subarray(src,src+length),dst);
light.skyLevels.set(field.skyLevels.subarray(src,src+length),dst);
}
}
const used = new Set();
for (const {cells} of sections) for (const block of cells) if (block) used.add(block);
const nearbyMaterials = new Map([...materials].filter(([id]) => used.has(id)));
return {id,sections,materials:[...nearbyMaterials],textures:[...textureSubset(textures, nearbyMaterials)],light};
}
export function buildEditMesh(packet, properties) {
const blocks=new SectionVoxelMap();
for(const {section,cells} of packet.sections) blocks.setSection(section,cells);
const materials=new Map(packet.materials.map(([id,mat])=>[id,applyLightProperties(mat,properties)]));
const field=packet.light ? attachBlockLightSamplers(packet.light,blocks,materials) : null;
return buildSectionMesh({id:packet.id,blocks,materials,textureLayers:new Map(packet.textures),blockLightField:field,localCoordinates:true});
}