studio/src/editor/engine/DecoModels.js
МИН 31adbf151b Initial public release: Студия Рублокса v1.0
Open-source веб-студия для создания игр Рублокса, двойная лицензия
AGPL-3.0 + Коммерческая.

Главное:
- Vite 5 + React 18 + Babylon 7.54.3 + Monaco Editor + Colyseus 0.16
- Самодостаточный движок ~28к строк (66 файлов): BlockManager,
  TerrainVoxelBuilder, ModelManager, DecoManager, PlayerController,
  ScriptSandboxWorker, MultiplayerSync, 30+ GD-гейммодов
- Главный редактор KubikonEditor (~37к строк) + панели, ScriptEditor (Monaco)
- Витрина игр (KubikonFeed, KubikonStudio, KubikonDocs, KubikonLearn)
- Geometry Dash sub-app (GdMenu, GdShop, GdRules, GdCoverArt)
- 10 admin-preview каталогов для дизайнеров (скины, музыка, порталы и т.д.)
- Конфигурируемый бэкенд через VITE_API_BASE — работает со staging
  (dev-api.rublox.pro) без настройки
- Standalone-режим (VITE_STANDALONE=true) — открыть пустой редактор без бэка
- Полная документация (на русском): README, ARCHITECTURE, CONTRIBUTING,
  SECURITY, CHANGELOG
- ESLint + Prettier + EditorConfig
- Legal: LICENSE (AGPL-3.0), LICENSE-COMMERCIAL.md, CLA.md, COPYRIGHT.md
- Issue templates: bug_report, feature_request, security_disclosure

Перед публикацией:
- Все импорты из minecraftia заменены на локальные
- Все хардкоды URL (minecraftia-school.ru) и внутренних IP убраны → env
- Admin-эндпоинты Kubikon3DService вырезаны (остаются в приватном репо)
- AdminKubikonModeration не публикуется (модерация — в team.rublox.pro)
- 93 МБ ассетов public/kubikon-assets вынесены в .gitignore
  (раздаются через release artifact)
2026-05-27 23:41:10 +03:00

387 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* DecoModels — воксельные модели декораций (цветы, грибы, кустики травы).
*
* Каждая модель — массив мини-вокселей размером DECO_VOXEL_SIZE метров.
* Координаты voxel'ов в локальной системе модели (0..N в каждом измерении).
*
* Цвет хранится как [r, g, b] в 0..1 (Babylon.Color3).
*
* Применение: DecoManager берёт модель + позицию в мире + поворот, добавляет
* voxel'и как thin-instances одной геометрии (один куб 0.05м).
*/
/** Размер одного deco-voxel'а в мире (метров). */
export const DECO_VOXEL_SIZE = 0.05;
// ============================================================================
// Палитра цветов для декораций
// Каждый цвет — Color3-совместимый массив [r, g, b] в [0..1].
// ============================================================================
export const DECO_PALETTE = {
// Стебли и листва
stemGreen: [0.20, 0.50, 0.15],
stemLight: [0.40, 0.65, 0.20],
leafDark: [0.15, 0.40, 0.12],
leafGrass: [0.35, 0.70, 0.25],
// Палитра травы — 4 оттенка зелёного для разнообразия
grass1: [0.32, 0.62, 0.20], // основной
grass2: [0.22, 0.52, 0.15], // тёмный
grass3: [0.45, 0.72, 0.25], // светлый
grass4: [0.38, 0.65, 0.18], // желтоватый
grassYellow: [0.55, 0.65, 0.20], // сухой
grassRed: [0.40, 0.45, 0.15], // увядший
// Цветы — лепестки
petalRed: [0.85, 0.20, 0.20],
petalPink: [1.00, 0.55, 0.70],
petalYellow: [1.00, 0.85, 0.20],
petalWhite: [0.95, 0.95, 0.90],
petalBlue: [0.30, 0.50, 0.85],
petalPurple: [0.65, 0.30, 0.80],
petalOrange: [1.00, 0.55, 0.15],
// Центры цветов (тычинки)
centerYellow: [0.95, 0.75, 0.10],
centerOrange: [0.90, 0.55, 0.10],
centerBlack: [0.15, 0.10, 0.05],
// Грибы
capRed: [0.80, 0.15, 0.15],
capWhite: [0.95, 0.95, 0.90],
capBrown: [0.55, 0.35, 0.20],
capDots: [0.95, 0.95, 0.90],
mushroomStem: [0.92, 0.88, 0.75],
};
// ============================================================================
// Воксельные модели декораций
//
// Формат: voxels[] = [{ x, y, z, c }]
// - x, y, z — целые координаты в локальной системе модели (0..)
// - c — ключ из DECO_PALETTE
// - y = 0 — основание (касается земли)
//
// При размере 0.05м, модель 10 voxel = 0.5м реального мира.
// ============================================================================
/**
* Ромашка — стебель 5 voxel + шапка 3×3 белых лепестка с жёлтым центром.
* Высота ~10 voxel = 50см.
*/
export const FLOWER_DAISY = {
name: 'daisy',
voxels: [
// Стебель — 5 voxel вверх по центру (x=2, z=2 в 5x5 модели)
{ x: 2, y: 0, z: 2, c: 'stemGreen' },
{ x: 2, y: 1, z: 2, c: 'stemGreen' },
{ x: 2, y: 2, z: 2, c: 'stemGreen' },
{ x: 2, y: 3, z: 2, c: 'stemGreen' },
{ x: 2, y: 4, z: 2, c: 'stemLight' },
// Лист сбоку на высоте 2
{ x: 3, y: 2, z: 2, c: 'leafGrass' },
// Шапка на Y=5: лепестки 3×3 крест
{ x: 1, y: 5, z: 2, c: 'petalWhite' },
{ x: 3, y: 5, z: 2, c: 'petalWhite' },
{ x: 2, y: 5, z: 1, c: 'petalWhite' },
{ x: 2, y: 5, z: 3, c: 'petalWhite' },
// Центр — жёлтый
{ x: 2, y: 5, z: 2, c: 'centerYellow' },
// Верхушка
{ x: 2, y: 6, z: 2, c: 'centerYellow' },
],
};
/**
* Василёк — синий объёмный цветок-шар.
* Лепестки расходятся в стороны и вверх — как настоящий бутон.
*/
export const FLOWER_CORNFLOWER = {
name: 'cornflower',
voxels: [
// Стебель 5 voxel
{ x: 2, y: 0, z: 2, c: 'stemGreen' },
{ x: 2, y: 1, z: 2, c: 'stemGreen' },
{ x: 2, y: 2, z: 2, c: 'stemGreen' },
{ x: 2, y: 3, z: 2, c: 'stemGreen' },
// Лист сбоку
{ x: 3, y: 2, z: 2, c: 'leafGrass' },
// Объёмный бутон на Y=4..6
// Нижний слой (Y=4) — 4 «нижних» лепестка крестом
{ x: 1, y: 4, z: 2, c: 'petalBlue' },
{ x: 3, y: 4, z: 2, c: 'petalBlue' },
{ x: 2, y: 4, z: 1, c: 'petalBlue' },
{ x: 2, y: 4, z: 3, c: 'petalBlue' },
// Средний слой (Y=5) — заполненный 3×3 квадрат
{ x: 1, y: 5, z: 1, c: 'petalBlue' },
{ x: 2, y: 5, z: 1, c: 'petalBlue' },
{ x: 3, y: 5, z: 1, c: 'petalBlue' },
{ x: 1, y: 5, z: 2, c: 'petalBlue' },
{ x: 2, y: 5, z: 2, c: 'centerYellow' }, // центр (тычинки)
{ x: 3, y: 5, z: 2, c: 'petalBlue' },
{ x: 1, y: 5, z: 3, c: 'petalBlue' },
{ x: 2, y: 5, z: 3, c: 'petalBlue' },
{ x: 3, y: 5, z: 3, c: 'petalBlue' },
// Верхний слой (Y=6) — пирамидка крестом
{ x: 2, y: 6, z: 1, c: 'petalBlue' },
{ x: 1, y: 6, z: 2, c: 'petalBlue' },
{ x: 2, y: 6, z: 2, c: 'petalBlue' },
{ x: 3, y: 6, z: 2, c: 'petalBlue' },
{ x: 2, y: 6, z: 3, c: 'petalBlue' },
],
};
/**
* Красный мак — крупные красные лепестки.
*/
export const FLOWER_POPPY = {
name: 'poppy',
voxels: [
{ x: 2, y: 0, z: 2, c: 'stemGreen' },
{ x: 2, y: 1, z: 2, c: 'stemGreen' },
{ x: 2, y: 2, z: 2, c: 'stemGreen' },
{ x: 2, y: 3, z: 2, c: 'stemGreen' },
// Большой бутон 3×3
{ x: 1, y: 4, z: 1, c: 'petalRed' },
{ x: 2, y: 4, z: 1, c: 'petalRed' },
{ x: 3, y: 4, z: 1, c: 'petalRed' },
{ x: 1, y: 4, z: 2, c: 'petalRed' },
{ x: 2, y: 4, z: 2, c: 'centerBlack' },
{ x: 3, y: 4, z: 2, c: 'petalRed' },
{ x: 1, y: 4, z: 3, c: 'petalRed' },
{ x: 2, y: 4, z: 3, c: 'petalRed' },
{ x: 3, y: 4, z: 3, c: 'petalRed' },
],
};
/**
* Жёлтый одуванчик — объёмный пушистый шар (как реальный цветок).
*/
export const FLOWER_DANDELION = {
name: 'dandelion',
voxels: [
// Стебель
{ x: 2, y: 0, z: 2, c: 'stemGreen' },
{ x: 2, y: 1, z: 2, c: 'stemGreen' },
{ x: 2, y: 2, z: 2, c: 'stemGreen' },
{ x: 2, y: 3, z: 2, c: 'stemGreen' },
// Лист
{ x: 1, y: 1, z: 2, c: 'leafGrass' },
// Объёмный пушистый бутон на Y=4..6
// Нижний слой Y=4 — нижние лепестки крест
{ x: 1, y: 4, z: 2, c: 'petalYellow' },
{ x: 3, y: 4, z: 2, c: 'petalYellow' },
{ x: 2, y: 4, z: 1, c: 'petalYellow' },
{ x: 2, y: 4, z: 3, c: 'petalYellow' },
// Средний слой Y=5 — 3×3 квадрат
{ x: 1, y: 5, z: 1, c: 'petalYellow' },
{ x: 2, y: 5, z: 1, c: 'petalYellow' },
{ x: 3, y: 5, z: 1, c: 'petalYellow' },
{ x: 1, y: 5, z: 2, c: 'petalYellow' },
{ x: 2, y: 5, z: 2, c: 'centerOrange' },
{ x: 3, y: 5, z: 2, c: 'petalYellow' },
{ x: 1, y: 5, z: 3, c: 'petalYellow' },
{ x: 2, y: 5, z: 3, c: 'petalYellow' },
{ x: 3, y: 5, z: 3, c: 'petalYellow' },
// Верхний слой Y=6 — пирамидка
{ x: 2, y: 6, z: 1, c: 'petalYellow' },
{ x: 1, y: 6, z: 2, c: 'petalYellow' },
{ x: 2, y: 6, z: 2, c: 'petalYellow' },
{ x: 3, y: 6, z: 2, c: 'petalYellow' },
{ x: 2, y: 6, z: 3, c: 'petalYellow' },
// Верхушка
{ x: 2, y: 7, z: 2, c: 'petalYellow' },
],
};
/**
* Мухомор — красная шляпка с белыми точками + белая ножка.
*/
export const MUSHROOM_FLY = {
name: 'fly_mushroom',
voxels: [
// Белая ножка 3 voxel
{ x: 2, y: 0, z: 2, c: 'mushroomStem' },
{ x: 2, y: 1, z: 2, c: 'mushroomStem' },
{ x: 2, y: 2, z: 2, c: 'mushroomStem' },
// Красная шляпка 3×3
{ x: 1, y: 3, z: 1, c: 'capRed' },
{ x: 2, y: 3, z: 1, c: 'capDots' }, // белая точка
{ x: 3, y: 3, z: 1, c: 'capRed' },
{ x: 1, y: 3, z: 2, c: 'capDots' }, // белая точка
{ x: 2, y: 3, z: 2, c: 'capRed' },
{ x: 3, y: 3, z: 2, c: 'capDots' }, // белая точка
{ x: 1, y: 3, z: 3, c: 'capRed' },
{ x: 2, y: 3, z: 3, c: 'capRed' },
{ x: 3, y: 3, z: 3, c: 'capDots' }, // белая точка
// Верхушка шляпки
{ x: 2, y: 4, z: 2, c: 'capRed' },
],
};
/**
* Коричневый гриб — простая шляпка.
*/
export const MUSHROOM_BROWN = {
name: 'brown_mushroom',
voxels: [
{ x: 2, y: 0, z: 2, c: 'mushroomStem' },
{ x: 2, y: 1, z: 2, c: 'mushroomStem' },
// Шляпка
{ x: 1, y: 2, z: 1, c: 'capBrown' },
{ x: 2, y: 2, z: 1, c: 'capBrown' },
{ x: 3, y: 2, z: 1, c: 'capBrown' },
{ x: 1, y: 2, z: 2, c: 'capBrown' },
{ x: 2, y: 2, z: 2, c: 'capBrown' },
{ x: 3, y: 2, z: 2, c: 'capBrown' },
{ x: 1, y: 2, z: 3, c: 'capBrown' },
{ x: 2, y: 2, z: 3, c: 'capBrown' },
{ x: 3, y: 2, z: 3, c: 'capBrown' },
],
};
/**
* Трава — 7 РАЗНЫХ моделей. WorldGenerator выбирает случайно при размещении,
* + случайный scale и rotation. Это даёт хаотичный, естественный вид:
*
* grass_short — короткие отростки (2-3 voxel'а высотой, маленький пучок)
* grass_tuft — обычный пучок (5-7 voxel'ов крестом)
* grass_tall — высокая трава (5+ voxel'ов вверх стеблем)
* grass_wide — широкий пучок (расходится в стороны)
* grass_clump — кустистый клумб
* grass_blade — отдельная травинка с листом
* grass_dry — сухая, желтоватая
*
* Все используют разные оттенки grass1..4 + редкий grassYellow для разнообразия.
*/
/** Короткие отростки — самая мелкая трава, чаще всего. */
export const GRASS_SHORT = {
name: 'grass_short',
voxels: [
{ x: 2, y: 0, z: 2, c: 'grass1' },
{ x: 2, y: 1, z: 2, c: 'grass1' },
{ x: 1, y: 0, z: 2, c: 'grass3' },
{ x: 3, y: 0, z: 2, c: 'grass2' },
],
};
/** Обычный пучок — крестом, средняя высота. */
export const GRASS_TUFT = {
name: 'grass_tuft',
voxels: [
{ x: 2, y: 0, z: 2, c: 'grass1' },
{ x: 2, y: 1, z: 2, c: 'grass1' },
{ x: 1, y: 1, z: 2, c: 'grass2' },
{ x: 3, y: 1, z: 2, c: 'grass3' },
{ x: 2, y: 2, z: 2, c: 'grass2' },
],
};
/** Высокая трава — столбик 4 voxel + 1 ветка. */
export const GRASS_TALL = {
name: 'grass_tall',
voxels: [
{ x: 2, y: 0, z: 2, c: 'grass2' },
{ x: 2, y: 1, z: 2, c: 'grass1' },
{ x: 2, y: 2, z: 2, c: 'grass3' },
{ x: 2, y: 3, z: 2, c: 'grass4' },
{ x: 3, y: 2, z: 2, c: 'grass3' },
],
};
/** Широкий пучок — расходится в стороны, низкий. */
export const GRASS_WIDE = {
name: 'grass_wide',
voxels: [
{ x: 2, y: 0, z: 2, c: 'grass2' },
{ x: 1, y: 0, z: 2, c: 'grass1' },
{ x: 3, y: 0, z: 2, c: 'grass1' },
{ x: 2, y: 0, z: 1, c: 'grass1' },
{ x: 2, y: 0, z: 3, c: 'grass1' },
{ x: 2, y: 1, z: 2, c: 'grass3' },
],
};
/** Кустистый клумб — компактный куст. */
export const GRASS_CLUMP = {
name: 'grass_clump',
voxels: [
{ x: 2, y: 0, z: 2, c: 'grass2' },
{ x: 1, y: 0, z: 2, c: 'grass2' },
{ x: 3, y: 0, z: 2, c: 'grass2' },
{ x: 2, y: 0, z: 1, c: 'grass2' },
{ x: 2, y: 0, z: 3, c: 'grass2' },
{ x: 2, y: 1, z: 2, c: 'grass1' },
{ x: 2, y: 2, z: 2, c: 'grass3' },
],
};
/** Отдельная травинка с листом — тонкая. */
export const GRASS_BLADE = {
name: 'grass_blade',
voxels: [
{ x: 2, y: 0, z: 2, c: 'grass2' },
{ x: 2, y: 1, z: 2, c: 'grass1' },
{ x: 2, y: 2, z: 2, c: 'grass3' },
],
};
/** Сухая трава — желтовато-зелёная, низкая. */
export const GRASS_DRY = {
name: 'grass_dry',
voxels: [
{ x: 2, y: 0, z: 2, c: 'grassYellow' },
{ x: 1, y: 0, z: 2, c: 'grassYellow' },
{ x: 3, y: 0, z: 2, c: 'grassRed' },
{ x: 2, y: 1, z: 2, c: 'grassYellow' },
],
};
/**
* Все доступные модели — упорядоченный список.
*/
export const DECO_MODELS = {
daisy: FLOWER_DAISY,
cornflower: FLOWER_CORNFLOWER,
poppy: FLOWER_POPPY,
dandelion: FLOWER_DANDELION,
fly_mushroom: MUSHROOM_FLY,
brown_mushroom: MUSHROOM_BROWN,
// 7 разных моделей травы — генератор выбирает случайно
grass_short: GRASS_SHORT,
grass_tuft: GRASS_TUFT,
grass_tall: GRASS_TALL,
grass_wide: GRASS_WIDE,
grass_clump: GRASS_CLUMP,
grass_blade: GRASS_BLADE,
grass_dry: GRASS_DRY,
};
/**
* Пул моделей травы для генератора — с весами для частоты появления.
* Чем больше повторений, тем чаще встречается.
*/
export const GRASS_MODELS_POOL = [
// Самые дешёвые модели (3-4 voxel) — основная масса травы
'grass_short', 'grass_short', 'grass_short', 'grass_short', 'grass_short', 'grass_short', // ×6
'grass_blade', 'grass_blade', 'grass_blade', 'grass_blade', // ×4
// Средние (5-6 voxel) — для разнообразия
'grass_tuft', 'grass_tuft', // ×2
'grass_wide', // ×1
'grass_tall', // ×1
'grass_clump', // ×1
'grass_dry', // ×1
];
/**
* Группы декораций по биому. Используется при процедурном размещении.
*/
export const DECO_BY_BIOME = {
grass: ['daisy', 'cornflower', 'poppy', 'dandelion', 'grass_tuft', 'grass_tuft', 'grass_tuft'],
forest: ['daisy', 'fly_mushroom', 'brown_mushroom', 'grass_tuft', 'grass_tuft'],
plain: ['dandelion', 'cornflower', 'grass_tuft', 'grass_tuft'],
desert: [], // в пустыне декораций нет
snow: [],
mountain: [],
};