import test from 'node:test'; import assert from 'node:assert/strict'; import {prepareTexturePack, textureSubset, BLOCK_FACES} from '../texture-pack.js'; import {getBlockFaceTextures, getFaceUV} from '../block-textures.js'; import {buildSectionMesh} from '../mesh-geometry.js'; const limits = {layers:256, size:2048}; const files = new Map([['atlas.png', {}]]); const descriptor = () => ({pixel_size:32, atlas:{path:'atlas.png', columns:40, rows:32}, textures:Array.from({length:1269}, (_,i)=>({name:`tile_${i}`}))}); test('atlas supports the full catalog on a GPU with only 256 array layers', () => { const result = prepareTexturePack(descriptor(), files, limits); assert.deepEqual([result.width,result.height,result.layers.size],[1280,1024,1269]); assert.equal(result.layers.get('tile_1268'),1268); const regular = {...descriptor(),atlas:undefined}; assert.throws(()=>prepareTexturePack(regular,files,limits),/размер/); }); test('atlas bounds, verified resources, and names are validated before allocating GPU memory', () => { assert.throws(()=>prepareTexturePack(descriptor(),new Map(),limits),/атлас/); assert.throws(()=>prepareTexturePack(descriptor(),files,{...limits,size:1024}),/видеокарты/); for(const atlas of [{path:'atlas.png',columns:1,rows:1},{path:'atlas.png',columns:40.5,rows:32}]) assert.throws(()=>prepareTexturePack({...descriptor(),atlas},files,limits),/атлас/); for(const textures of [[{name:'same'},{name:'same'}],[{}],[{name:'../escape'}]]) assert.throws(()=>prepareTexturePack({...descriptor(),textures},files,limits),/ресурс/); }); test('state faces and UV transforms survive worker transfer and reach section geometry', () => { const d=descriptor(); const face={texture:'tile_1268',tint:[.4,.7,.3],cutout:true,uv:[0,0,1,0,0,-1,0,1]}; d.block_faces={sets:[Array(6).fill(face),Array(6).fill(null)], states:{'minecraft:test[facing=east,half=top]':0},defaults:{'minecraft:test':1}}; const {layers}=prepareTexturePack(d,files,limits); const cloned=new Map(structuredClone([...layers])); const state='minecraft:test[half=top,facing=east]'; const faces=getBlockFaceTextures(state,cloned); assert.equal(faces[0].layer,1268); assert.deepEqual(getFaceUV(0,[.25,.5,.75],state,faces[0]),[.75,.5]); assert.deepEqual(getBlockFaceTextures('minecraft:test',cloned),Array(6).fill(null)); const mesh=buildSectionMesh({id:'0,0,0',blocks:new Map([['0,0,0',1]]), materials:new Map([[1,{state,color:[255,255,255],render:[{min:[0,0,0],max:[1,1,1]}]}]]),textureLayers:cloned}); for(let i=0;i { for(const face of [{texture:'missing'},{texture:'tile_0',tint:[NaN,1,1]}, {texture:'tile_0',uv:Array(8).fill(Infinity)}]){ const d=descriptor();d.block_faces={sets:[Array(6).fill(face)],states:{},defaults:{}}; assert.throws(()=>prepareTexturePack(d,files,limits),/гран/); } const d=descriptor();d.block_faces={sets:[Array(6).fill(null)],states:{'minecraft:stone':9},defaults:{}}; assert.throws(()=>prepareTexturePack(d,files,limits),/состояние/); }); test('edit snapshots send only nearby state mappings from a large texture catalog',()=>{ const d=descriptor(); d.block_faces={sets:[Array(6).fill({texture:'tile_0'}),Array(6).fill({texture:'tile_1'})], states:{'minecraft:stone':0,'minecraft:dirt':1},defaults:{'minecraft:stone':0,'minecraft:dirt':1}}; const {layers}=prepareTexturePack(d,files,limits); const subset=textureSubset(layers,new Map([[1,{state:'minecraft:dirt'}]])); assert.equal(subset.get(BLOCK_FACES).sets.length,1); assert.deepEqual(Object.keys(subset.get(BLOCK_FACES).states),['minecraft:dirt']); assert.equal(getBlockFaceTextures('minecraft:dirt',subset)[0].layer,1); assert.equal(layers.get(BLOCK_FACES).sets.length,2); });