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)
387 lines
16 KiB
JavaScript
387 lines
16 KiB
JavaScript
/**
|
||
* 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: [],
|
||
};
|