/** * BlockTypes — реестр voxel-блоков для Рублокс-редактора. * * Используем Kenney Voxel Pack (CC0) — текстуры 32×32, лежат в * /public/kubikon-assets/textures/. * * Каждый блок может иметь: * texture — одна текстура на все 6 граней (простые кубы) * ИЛИ * top/side/bottom — три текстуры для верха, боков, низа (трава, тыква, бревно) * * BlockManager автоматически выберет правильный материал. */ const TEX = '/kubikon-assets/textures'; /** * Создать описание простого куба с одной текстурой. */ const cube = (id, name, category, texture, opts = {}) => ({ id, name, category, texture, ...opts, }); /** * Создать описание мульти-материал куба (разные текстуры на гранях). * top/side/bottom могут быть отдельными или одинаковыми (если совпадают — куб с side="top"). */ const multiCube = (id, name, category, top, side, bottom, opts = {}) => ({ id, name, category, top, side, bottom, ...opts, }); /** * Полный список блоков. * Цвет fallback в swatch — берётся из категории. */ export const BLOCK_TYPES = [ // === ЗЕМЛЯ === multiCube('grass', 'Трава', 'Земля', `${TEX}/grass_top.png`, `${TEX}/dirt_grass.png`, `${TEX}/dirt.png`), cube('dirt', 'Земля', 'Земля', `${TEX}/dirt.png`), cube('sand', 'Песок', 'Земля', `${TEX}/sand.png`), cube('redsand', 'Красный песок', 'Земля', `${TEX}/redsand.png`), cube('greysand', 'Серый песок', 'Земля', `${TEX}/greysand.png`), cube('snow', 'Снег', 'Земля', `${TEX}/snow.png`), multiCube('grass-snow', 'Снежная трава', 'Земля', `${TEX}/snow.png`, `${TEX}/dirt_snow.png`, `${TEX}/dirt.png`), multiCube('grass-sand', 'Песочная трава','Земля', `${TEX}/sand.png`, `${TEX}/dirt_sand.png`, `${TEX}/dirt.png`), cube('gravel-stone', 'Гравий', 'Земля', `${TEX}/gravel_stone.png`), cube('gravel-dirt', 'Земляной гравий','Земля', `${TEX}/gravel_dirt.png`), cube('ice', 'Лёд', 'Земля', `${TEX}/ice.png`, { alpha: 0.85 }), // === КАМЕНЬ === // ВАЖНО: rock.png / rock_moss.png / stone_sand.png / greystone_sand.png — это // спрайты-полублоки (камень в центре или песок сверху), не tile-able. // На обычном кубе они выглядят как чёрный фон + камешек. Поэтому: // - 'rock' → используем плиточную greystone.png // - 'rock-moss' → greystone.png + лёгкий зелёный tint через emissive // - 'stone-sand' / 'greystone-sand' оставляем без halfblock-текстур, // используем обычные tile + цветовая схема cube('rock', 'Камень', 'Камень', `${TEX}/greystone.png`), cube('rock-moss', 'Замшелый камень', 'Камень', `${TEX}/greystone.png`, { emissive: [0.05, 0.18, 0.05] }), cube('greystone', 'Серый камень', 'Камень', `${TEX}/greystone.png`), cube('stone', 'Тёмный камень', 'Камень', `${TEX}/stone.png`), cube('redstone', 'Редстоун', 'Камень', `${TEX}/redstone.png`), // === РУДЫ (тёмный камень с вкраплениями) === cube('ore-coal', 'Уголь', 'Руда', `${TEX}/stone_coal.png`), cube('ore-iron', 'Железная руда', 'Руда', `${TEX}/stone_iron.png`), cube('ore-gold', 'Золотая руда', 'Руда', `${TEX}/stone_gold.png`), cube('ore-diamond', 'Алмазная руда', 'Руда', `${TEX}/stone_diamond.png`), cube('ore-silver', 'Серебряная руда', 'Руда', `${TEX}/stone_silver.png`), cube('ore-browniron', 'Медная руда', 'Руда', `${TEX}/stone_browniron.png`), cube('ore-ruby', 'Рубиновая руда', 'Руда', `${TEX}/greystone_ruby.png`), cube('ore-emerald', 'Изумрудная руда', 'Руда', `${TEX}/redstone_emerald.png`), // === ДЕРЕВО === cube('wood', 'Бревно', 'Дерево', `${TEX}/wood.png`), cube('wood-red', 'Красное бревно', 'Дерево', `${TEX}/wood_red.png`), // === ХЛОПОК / ШЕРСТЬ === cube('cotton-blue', 'Хлопок синий', 'Шерсть', `${TEX}/cotton_blue.png`), cube('cotton-green', 'Хлопок зелёный', 'Шерсть', `${TEX}/cotton_green.png`), cube('cotton-red', 'Хлопок красный', 'Шерсть', `${TEX}/cotton_red.png`), cube('cotton-tan', 'Хлопок бежевый', 'Шерсть', `${TEX}/cotton_tan.png`), // === КИРПИЧИ === cube('brick-red', 'Кирпич красный', 'Кирпич', `${TEX}/brick_red.png`), cube('brick-grey', 'Кирпич серый', 'Кирпич', `${TEX}/brick_grey.png`), // === СТЕКЛО === cube('glass', 'Стекло', 'Особые', `${TEX}/glass.png`, { alpha: 0.6 }), cube('glass-frame', 'Стекло в раме', 'Особые', `${TEX}/glass_frame.png`, { alpha: 0.7 }), // === ЛИСТВА === cube('leaves', 'Листва', 'Природа', `${TEX}/leaves.png`), cube('leaves-orange', 'Жёлтая листва', 'Природа', `${TEX}/leaves_orange.png`), cube('leaves-trans', 'Прозр. листва', 'Природа', `${TEX}/leaves_transparent.png`, { alpha: 0.9 }), cube('leaves-orange-trans', 'Прозр.жёлт.листва', 'Природа', `${TEX}/leaves_orange_transparent.png`, { alpha: 0.9 }), // === ЖИДКОСТИ И СПЕЦБЛОКИ === cube('water', 'Вода', 'Особые', `${TEX}/water.png`, { alpha: 0.75, isWater: true, animate: 'water' }), cube('lava', 'Лава', 'Особые', `${TEX}/lava.png`, { emissive: [0.6, 0.2, 0], isLava: true, animate: 'lava' }), // === КАКТУС / ПЕЧЬ (мульти-материал) === multiCube('cactus', 'Кактус', 'Природа', `${TEX}/cactus_top.png`, `${TEX}/cactus_side.png`, `${TEX}/cactus_inside.png`), // Печь: только oven.png это «фасад» (дверца), остальное — серый камень. // top = stone, side = oven (4 стороны с дверцей — лучше чем раньше), // bottom = stone. В будущем для одной двери понадобится 6-face формат. multiCube('oven', 'Печь', 'Особые', `${TEX}/stone.png`, `${TEX}/oven.png`, `${TEX}/stone.png`), // === ОКРАШИВАЕМЫЕ (задача 09) — паритет со студией === cube('studs-block', 'Лего-кирпич', 'Окрашиваемые', '/kubikon-assets/materials/studs_v4_diffuse.png', { colorable: true, normal: '/kubikon-assets/materials/studs_v4_normal.png', defaultColor: '#3a7aff' }), ]; /** Все доступные категории в порядке появления. */ export const BLOCK_CATEGORIES = Array.from(new Set(BLOCK_TYPES.map(b => b.category))); /** Цвет для swatch'а в палитре, fallback по категории. */ export const CATEGORY_COLORS = { 'Земля': '#8b6f4e', 'Камень': '#7a7a7a', 'Руда': '#c9a04e', 'Дерево': '#a8743f', 'Шерсть': '#e8dcc4', 'Кирпич': '#9d4a3a', 'Особые': '#9966ff', 'Природа': '#5a8c3e', 'Окрашиваемые': '#3a7aff', }; /** Найти описание блока по id. */ export function getBlockType(id) { return BLOCK_TYPES.find(b => b.id === id) || BLOCK_TYPES[0]; } /** Картинка-превью для палитры — для мульти-куба показываем верхнюю грань. */ export function blockPreview(b) { return b.top || b.texture; }