diff --git a/.env.example b/.env.example index 64f1746..c290a95 100644 --- a/.env.example +++ b/.env.example @@ -1,30 +1,30 @@ # ============================================================================ -# rublox-player environment variables +# Переменные окружения rublox-player # ============================================================================ -# Copy this file to .env (`cp .env.example .env`), then edit if needed. -# Defaults below point at the public staging environment so you can run the -# player out of the box without setting up your own backend. +# Скопируй этот файл в .env (`cp .env.example .env`) и поправь при необходимости. +# Дефолты ниже указывают на публичный staging — плеер заработает сразу, без +# настройки своего бэкенда. -# Backend base URL (HTTP API). -# Leave empty to use vite-proxy in dev (http://localhost:5173 → staging). -# In production set to your origin if frontend & backend are on different hosts. +# Базовый URL HTTP-API. +# Оставь пустым чтобы использовать vite-proxy в dev (http://localhost:5173 → staging). +# В проде укажи свой origin если фронтенд и бэкенд на разных хостах. VITE_API_BASE= -# Colyseus realtime (multiplayer) endpoints. -# These DO need to be configured for multiplayer to work. -# Public staging: +# Colyseus realtime (мультиплеер) эндпоинты. +# Эти нужно настроить чтобы мультиплеер работал. +# Публичный staging: VITE_REALTIME_HTTP=https://dev-api.rublox.pro/api-game VITE_REALTIME_WS=wss://dev-api.rublox.pro/api-game -# Rublox main site — where players are redirected if no auth ticket present. +# Главный сайт Рублокса — куда редиректим игроков без auth-ticket'а. VITE_RUBLOX_HOME=https://rublox.pro/app -# Standalone mode — load a built-in sample game instead of fetching from API. -# Useful for first-run / dogfood / when backend is unreachable. -# Values: "true" | "false" +# Standalone-режим — загружает встроенный демо-проект вместо запроса к API. +# Полезно для первого запуска / разработки / когда бэкенд недоступен. +# Значения: "true" | "false" VITE_STANDALONE=false -# Asset CDN base URL (optional). When set, .glb/.png/.mp3 are loaded from -# this URL instead of the local public/ folder. Useful in production to -# offload bandwidth to Cloudflare R2 or similar. +# CDN для ассетов (опционально). Если задан, .glb/.png/.mp3 загружаются с +# этого URL вместо локальной папки public/. Полезно в проде чтобы разгрузить +# bandwidth через Cloudflare R2 или подобное. # VITE_ASSETS_CDN=https://cdn.rublox.pro/assets diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 598d964..2259a4a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,81 +1,81 @@ -# Architecture — Rublox Player +# Архитектура плеера Рублокса -How a 3D game is loaded, rendered, and synced. ~5 minutes read. +Как 3D-игра загружается, рендерится и синхронизируется. Чтение ~5 минут. -## Top-level flow +## Общий поток ``` -URL = / e.g. /265 +URL = / например /265 │ ▼ -PlayerAuthProvider checks JWT in localStorage["player_jwt"] - │ OR exchanges URL #ticket=... for JWT +PlayerAuthProvider проверяет JWT в localStorage["player_jwt"] + │ ИЛИ обменивает URL #ticket=... на JWT ▼ useAuth().isAuthenticated │ ▼ -KubikonPlayer.jsx main container, gets {projectId} from useParams +KubikonPlayer.jsx главный контейнер, читает {projectId} из useParams │ ├── GET /api-storys/kubikon3d/projects/{id} → project_data (JSON) │ ▼ -BabylonScene.create() construct Babylon engine, scene, lights, skybox +BabylonScene.create() создание движка Babylon, сцены, света, неба │ ▼ -GameRuntime.loadProject() parse project_data, instantiate everything: - │ - BlockManager.placeBlock() × N (Minecraft-style blocks) - │ - ModelManager.spawnModel() × N (Kenney prop GLBs) - │ - DecoManager.placeDeco() × N (terrain decorations) - │ - PrimitiveManager.add() × N (cubes/spheres/cylinders) - │ - PlayerController.spawn() (R15 character + camera) +GameRuntime.loadProject() парсинг project_data, инстанциация всего: + │ - BlockManager.placeBlock() × N (Minecraft-блоки) + │ - ModelManager.spawnModel() × N (Kenney GLB) + │ - DecoManager.placeDeco() × N (декор ландшафта) + │ - PrimitiveManager.add() × N (кубы/сферы/цилиндры) + │ - PlayerController.spawn() (R15-персонаж + камера) │ ▼ -ScriptSandboxWorker user JS scripts run in a Web Worker sandbox. - │ Exposed API: game.player, scene, ui, broadcast. +ScriptSandboxWorker пользовательские JS-скрипты в Web Worker-песочнице. + │ Доступный API: game.player, scene, ui, broadcast. │ ▼ -MultiplayerSync optional. Colyseus room joins, syncs positions. +MultiplayerSync опционально. Колyseus-комната, синк позиций. │ ▼ -RENDER LOOP (60 fps) scene.render() each frame +ЦИКЛ РЕНДЕРА (60 fps) scene.render() каждый кадр ``` -## Key modules +## Ключевые модули ### `engine/BabylonScene.js` -Wraps Babylon `Engine` + `Scene`. Creates lighting (HemisphericLight + DirectionalLight + shadow generator), skybox, fog. Single source of truth for `scene` reference. +Обёртка над `Engine` + `Scene` из Babylon. Создаёт освещение (HemisphericLight + DirectionalLight + теневой генератор), скайбокс, туман. Единый источник правды для ссылки на `scene`. ### `engine/GameRuntime.js` -Orchestrator. Reads `project_data` (the JSON saved by the studio editor) and dispatches each item to the right manager. Has lifecycle hooks: `loadProject()`, `start()`, `pause()`, `dispose()`. +Оркестратор. Читает `project_data` (JSON, сохранённый редактором студии) и направляет каждый элемент в соответствующий менеджер. Lifecycle-хуки: `loadProject()`, `start()`, `pause()`, `dispose()`. -Also handles "external URL" resolution (`_resolveExternalUrl`) — game scripts can call `game.openUrl('/kubikon/play/12')` and it correctly resolves to the player itself or the main Rublox site. +Также обрабатывает «external URL» резолвинг (`_resolveExternalUrl`) — скрипты игры могут вызвать `game.openUrl('/kubikon/play/12')`, и URL корректно резолвится в сам плеер или на главный сайт. ### `engine/PlayerController.js` -R15 character (15-bone Mixamo rig). First-person and third-person cameras. WASD/touch input. Jumping, gravity, collision against block grid + AABB models. Spawning/respawning. +R15-персонаж (15-костный Mixamo-rig). Камеры от первого и третьего лица. Управление WASD/тач. Прыжки, гравитация, столкновения с воксельным гридом + AABB-моделями. Спавн/респавн. -Special GD modes: `setAutoRun(true)`, `setShipMode(true)` — used by Geometry Dash gamemodes (cube/ship/wave/UFO/ball/spider). +Спец-режимы для GD: `setAutoRun(true)`, `setShipMode(true)` — используются гейммодами Geometry Dash (куб/корабль/волна/НЛО/мяч/паук). ### `engine/BlockManager.js` / `TerrainVoxelBuilder.js` -Voxel terrain. Blocks are uint16 type IDs in chunked arrays. `rebuildChunk(chunkId)` does greedy meshing → single mesh per material per chunk (~40-100× fewer draw calls than naive). +Воксельный ландшафт. Блоки — uint16 type-id'ы в чанковых массивах. `rebuildChunk(chunkId)` делает greedy meshing → один меш на материал на чанк (~40-100× меньше draw call'ов чем наивно). ### `engine/ModelManager.js` -Loads `.glb` Kenney models (or designer-uploaded GLBs from `/api-storys/assets/rublox-designer/models/...`). Caches `AssetContainer` per `modelTypeId`, instantiates clones per spawn. +Загрузка `.glb`-моделей Kenney (или загруженных дизайнерами GLB из `/api-storys/assets/rublox-designer/models/...`). Кеширует `AssetContainer` по `modelTypeId`, инстанциирует клоны при каждом спавне. ### `engine/DecoManager.js` -Lightweight decorative props (rocks, plants, signs). Uses `ThinInstanceCount` for massive performance (thousands of instances → single draw call per type). +Лёгкие декоративные пропсы (камни, растения, знаки). Использует `ThinInstanceCount` для огромного перфоманса (тысячи инстансов → один draw call на тип). ### `engine/scripts/ScriptSandboxWorker.js` -User-uploaded JS scripts run in a separate Web Worker. Exposed API surface (read-only): +Пользовательские JS-скрипты выполняются в отдельном Web Worker. Доступная API-поверхность (только чтение): ```js -// In a user script: +// В скрипте игрока: game.onTick((dt) => { ... }); game.onKey('space', () => { player.jump(); }); game.broadcast('event', payload); @@ -84,62 +84,62 @@ scene.findOne('Cube1').rotateY(0.1); ui.set({ score: 42 }); ``` -Scripts CANNOT access `window`, `document`, `fetch`, `localStorage`, network. They run isolated in a Worker with a strict postMessage bridge. +Скрипты **НЕ имеют** доступа к `window`, `document`, `fetch`, `localStorage`, сети. Запускаются изолированно в Worker'е через строгий postMessage-мост. ### `engine/multiplayer/MultiplayerSync.js` -Colyseus 0.16 client. Joins a room per `gameId` if multiplayer is enabled. Syncs player positions/rotations/animations at 20 Hz. Server is at `VITE_REALTIME_WS`. +Colyseus 0.16 клиент. Подключается к комнате per `gameId` если мультиплеер включён. Синхронизирует позиции/повороты/анимации игроков на 20 Hz. Сервер по `VITE_REALTIME_WS`. -### `engine/gd/*` (Geometry Dash modules) +### `engine/gd/*` (модули Geometry Dash) -30+ classes implementing GD-style 2D autorunner gamemodes within a 3D world: -- `GdCube.js` — basic jump -- `GdShip.js` — gravity-flip flight -- `GdWave.js` — sine-wave dash -- `GdBall.js` — flip-jump ball -- `GdUfo.js` — multi-tap jumps -- `GdSpider.js` — instant teleport -- + portals, speedpads, spikes, finish lines, trail effects, checkpoint music +30+ классов реализующих GD-стиль 2D-автораннер-гейммоды в 3D-мире: +- `GdCube.js` — обычный прыжок +- `GdShip.js` — гравитация-флип, полёт +- `GdWave.js` — синусоида-дэш +- `GdBall.js` — флип-прыжок мячом +- `GdUfo.js` — мульти-тап прыжки +- `GdSpider.js` — мгновенный телепорт +- + порталы, ускорители, шипы, финишные линии, трейлы, чекпойнт-музыка -Factories for each (`GdSpikeFactory`, `GdPortalFactory`, `GdMusicFactory`, ...) live under `AdminPreview/gd*/`. +Фабрики для каждого (`GdSpikeFactory`, `GdPortalFactory`, `GdMusicFactory`...) живут в `AdminPreview/gd*/`. -## Data flow (single frame) +## Поток данных (один кадр) ``` -1. INPUT keyboard/touch/gamepad → PlayerController.onInput() -2. PHYSICS gravity + velocity + collision against blocks/models -3. SCRIPTS user script onTick(dt) callbacks (in worker, asynchronous) -4. MULTIPLAYER read remote positions, lerp other players -5. RENDER Babylon scene.render() → WebGL2 draw calls -6. UI React re-renders only if game.ui.set() called (throttled 250ms) +1. ВВОД клавиатура/тач/геймпад → PlayerController.onInput() +2. ФИЗИКА гравитация + скорость + столкновения с блоками/моделями +3. СКРИПТЫ onTick(dt) колбэки пользовательских скриптов (в Worker'е, асинхронно) +4. МУЛЬТИПЛЕЕР читаем удалённые позиции, lerp других игроков +5. РЕНДЕР Babylon scene.render() → WebGL2 draw calls +6. UI React ре-рендерится только если вызвали game.ui.set() (throttle 250мс) ``` -## What's NOT in the player +## Чего НЕТ в плеере -- **Editing** — that lives in [Studio](https://git.rublox.pro/rublox/studio). -- **Project listing / search / publishing** — handled by main site (`rublox.pro/app`). -- **Authentication UI** — players arrive with JWT/ticket. The player only consumes them. -- **Admin / moderation** — moved out to private repo (`disaster-recovery/` for owner). +- **Редактирование** — это в [Студии](https://git.rublox.pro/rublox/studio). +- **Лента игр / поиск / публикация** — это на главном сайте (`rublox.pro/app`). +- **Авторизация-UI** — игроки приходят с JWT/ticket. Плеер только читает их. +- **Админка / модерация** — вынесены в приватный репозиторий (`disaster-recovery/` для мейнтейнера). -## Performance hotspots (places to look first when laggy) +## Узкие места по производительности (что смотреть первым делом если тормозит) -1. **`game.ui.set()` called every frame** — React setState 60Hz tanks FPS. Throttle to 250ms with a diff check. -2. **`scene.findOne()` on init** — `sceneSnapshot` arrives via rAF; reference is null. Move into `onTick` or `setTimeout(0)`. -3. **Babylon's `blockMaterialDirtyMechanism=true`** — DON'T enable. Breaks new mesh rendering (debris, tracers). -4. **`createOrUpdateSelectionOctree()`** — same. Breaks editor preview ghosts. -5. **GLB load via `SceneLoader` instead of `AssetContainer`** — leaks materials. Use `AssetContainer` + `instantiateModelsToScene()`. +1. **`game.ui.set()` вызывается каждый кадр** — React setState 60Hz убивает FPS. Дросселируй до 250мс с diff-проверкой. +2. **`scene.findOne()` на старте** — `sceneSnapshot` приходит через rAF; ссылка будет null. Перенеси в `onTick` или `setTimeout(0)`. +3. **`blockMaterialDirtyMechanism=true` в Babylon** — НЕ включать. Ломает рендер новых мешей (debris, трейсеры). +4. **`createOrUpdateSelectionOctree()`** — то же. Ломает превью-призраки редактора. +5. **GLB-загрузка через `SceneLoader` вместо `AssetContainer`** — течёт материалами. Используй `AssetContainer` + `instantiateModelsToScene()`. -## Where to start a feature +## С чего начать новую фичу -| What you want to add | Start here | +| Что хочешь добавить | Начни здесь | |---|---| -| New block type | `engine/CONST/blockTypes.js` + texture in `public/kubikon-assets/blocks/` | -| New scripting API | `engine/scripts/ScriptSandboxAPI.js` (add to `apiSurface`) | -| New GD gamemode | Copy `engine/gd/GdBall.js`, register in `GdGameModeRegistry.js` | -| New HUD widget | `editor-shared/GameHud.jsx` | -| New preview route for designer | `AdminPreview/` (e.g. `gdSkins/PreviewGdSkins.jsx`) | -| Multiplayer event | Colyseus schema in `engine/multiplayer/schemas/` + handler in `MultiplayerSync.js` | +| Новый тип блока | `engine/CONST/blockTypes.js` + текстура в `public/kubikon-assets/blocks/` | +| Новое API для скриптов | `engine/scripts/ScriptSandboxAPI.js` (добавь в `apiSurface`) | +| Новый GD-гейммод | Скопируй `engine/gd/GdBall.js`, зарегистрируй в `GdGameModeRegistry.js` | +| Новый HUD-виджет | `editor-shared/GameHud.jsx` | +| Превью-роут для дизайнера | `AdminPreview/` (например `gdSkins/PreviewGdSkins.jsx`) | +| Мультиплеер-событие | Colyseus-схема в `engine/multiplayer/schemas/` + хендлер в `MultiplayerSync.js` | -## License notes for contributors +## Лицензионные заметки для контрибьюторов -By contributing you agree to license your changes under AGPL-3.0 AND grant the project maintainer a non-exclusive irrevocable license to sublicense (see [CLA.md](./CLA.md)). This is required so we can offer commercial licenses to enterprises. +Контрибьютя, ты соглашаешься лицензировать свои изменения под AGPL-3.0 И предоставляешь мейнтейнеру неисключительную безотзывную лицензию на сублицензирование (см. [CLA.md](./CLA.md)). Это нужно чтобы проект мог продавать коммерческие лицензии корпорациям. diff --git a/CHANGELOG.md b/CHANGELOG.md index 27898e8..c5520f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,31 +1,31 @@ # Changelog -All notable changes will be documented here. +Все значимые изменения документируются здесь. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/). ## [Unreleased] -### Added -- Open-source release: AGPL-3.0 + Commercial dual license. -- Standalone mode (`VITE_STANDALONE=true`) with bundled `sample-game.json`. -- Configurable backend via `VITE_API_BASE`, `VITE_RUBLOX_HOME`, `VITE_REALTIME_*`. -- Issue & PR templates under `.gitea/`. +### Добавлено +- Open-source релиз: двойная лицензия AGPL-3.0 + Коммерческая. +- Standalone-режим (`VITE_STANDALONE=true`) с встроенным `sample-game.json`. +- Конфигурируемый бэкенд через `VITE_API_BASE`, `VITE_RUBLOX_HOME`, `VITE_REALTIME_*`. +- Шаблоны Issue и PR в `.gitea/`. - `CONTRIBUTING.md`, `SECURITY.md`, `ARCHITECTURE.md`, `CLA.md`. - ESLint + Prettier + EditorConfig. -### Removed -- Hard-coded URLs to `minecraftia-school.ru` (all are now env-configurable). -- Internal server IPs (`85.175.x.x`, `192.168.x.x`) from comments. -- Admin endpoints (`adminPatchProjectScript`, `adminBanPublish`, etc.) — moved to private repo. -- `frontend_deploy.py` (contained SSH credentials). +### Удалено +- Захардкоженные URL `minecraftia-school.ru` (все теперь через env). +- Внутренние IP серверов (`85.175.x.x`, `192.168.x.x`) из комментариев. +- Admin-эндпоинты (`adminPatchProjectScript`, `adminBanPublish` и т.д.) — вынесены в приватный репо. +- `frontend_deploy.py` (содержал SSH-креды). -### Security -- New `git init` removes previous commit history (which contained credentials). -- Pre-commit hook blocks pushing files with detected secret patterns. +### Безопасность +- Новый `git init` удаляет предыдущую историю коммитов (где были креды). +- Pre-commit hook блокирует пуш файлов с обнаруженными паттернами секретов. -## [0.1.0] — initial private build (pre-public) +## [0.1.0] — начальный приватный билд (до публикации) -- Vite + React 18 + Babylon 7.54.3 baseline. -- R15 character, GD gamemodes, multiplayer via Colyseus 0.16. -- Plays projects from `rublox.pro` and `player.rublox.pro`. +- Vite + React 18 + Babylon 7.54.3 базовая сборка. +- R15-персонаж, GD-гейммоды, мультиплеер через Colyseus 0.16. +- Запуск проектов с `rublox.pro` и `player.rublox.pro`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20f78da..b4df933 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,150 +1,150 @@ -# Contributing to Rublox Player +# Контрибьютинг в плеер Рублокса -Thanks for your interest! Here's everything you need to know. +Спасибо за интерес! Всё что нужно знать. -## Before your first PR +## Перед первым PR -1. **Sign the [CLA](./CLA.md)** — open `https://team.rublox.pro/developer/cla` (you need a `developer` role; ask the maintainer) OR comment `/sign-cla` on your PR. -2. **Have a Gitea account** linked via OAuth to team.rublox.pro. -3. **Add your SSH key** to Gitea profile (otherwise you push by HTTPS + password). +1. **Подпиши [CLA](./CLA.md)** — открой `https://team.rublox.pro/developer/cla` (нужна роль `developer` — попроси у мейнтейнера) ИЛИ комментарий `/sign-cla` на PR. +2. **Заведи Gitea-аккаунт** через OAuth-привязку к team.rublox.pro. +3. **Добавь SSH-ключ** в профиль Gitea (иначе пуш по HTTPS + пароль). ## Workflow ```bash -# 1. Fork or clone (you can push to a feature branch directly if you have access) +# 1. Клонируем (или форкаем — если есть доступ, можно сразу пушить в feature-ветку) git clone ssh://git@git.rublox.pro:2222/rublox/player.git cd player npm install cp .env.example .env -# 2. Create a feature branch -git checkout -b feature/short-description +# 2. Создаём feature-ветку +git checkout -b feature/короткое-описание -# 3. Make changes -npm run dev # test locally -npm run lint # check ESLint -npm run format # apply Prettier +# 3. Делаем изменения +npm run dev # проверяем локально +npm run lint # ESLint +npm run format # Prettier -# 4. Commit (Conventional Commits) -git commit -m "feat: add jump animation to GdBall" -# Other prefixes: fix:, chore:, docs:, refactor:, test:, perf:, ci: +# 4. Коммитим (Conventional Commits) +git commit -m "feat: добавить анимацию прыжка для GdBall" +# Другие префиксы: fix:, chore:, docs:, refactor:, test:, perf:, ci: -# 5. Push and open PR -git push origin feature/short-description -# Open PR via https://git.rublox.pro/rublox/player +# 5. Пушим и открываем PR +git push origin feature/короткое-описание +# Открыть PR через https://git.rublox.pro/rublox/player ``` -## Code style +## Стиль кода -We use **Prettier** (auto-format) + **ESLint** (lint). The config is committed in `.prettierrc` and `.eslintrc.json`. +Используем **Prettier** (авто-формат) + **ESLint** (линт). Конфиги закоммичены в `.prettierrc` и `.eslintrc.json`. -Key rules: -- 2-space indent -- Single quotes (`'foo'`, not `"foo"`) -- Semicolons required -- Trailing comma in multi-line literals -- 100-char line width -- No `eval`, no `new Function`, no `innerHTML = ...` -- React: hooks rules enforced (`react-hooks/rules-of-hooks`) +Главные правила: +- 2-space отступ +- Одинарные кавычки (`'foo'`, не `"foo"`) +- Точки с запятой обязательны +- Trailing comma в многострочных литералах +- Ширина строки 100 символов +- Никаких `eval`, `new Function`, `innerHTML = ...` +- React: hooks-правила обязательны (`react-hooks/rules-of-hooks`) -Run before commit: +Запускай перед коммитом: ```bash -npm run format # auto-fixes most things -npm run lint # warns about the rest +npm run format # авто-фикс большинства +npm run lint # предупреждения для остального ``` -A pre-commit hook (Husky, if installed) will block you if Prettier check fails. +Pre-commit-хук (Husky, если установлен) заблокирует если Prettier-чек провален. -## Branch naming +## Именование веток -| Prefix | Use for | +| Префикс | Использовать для | |---|---| -| `feature/...` | New features | -| `fix/...` | Bug fixes | -| `chore/...` | Refactoring, deps, tooling | -| `docs/...` | Documentation only | -| `perf/...` | Performance improvements | +| `feature/...` | Новые фичи | +| `fix/...` | Багфиксы | +| `chore/...` | Рефакторинг, зависимости, тулинг | +| `docs/...` | Только документация | +| `perf/...` | Улучшения производительности | -## Commit messages (Conventional Commits) +## Commit-сообщения (Conventional Commits) ``` -: +<тип>: <короткое описание> -[optional body] +[опционально тело] -[optional footer: BREAKING CHANGE / Closes #N] +[опционально футер: BREAKING CHANGE / Closes #N] ``` -Types: `feat`, `fix`, `chore`, `docs`, `refactor`, `test`, `perf`, `ci`, `style`. +Типы: `feat`, `fix`, `chore`, `docs`, `refactor`, `test`, `perf`, `ci`, `style`. -**Good:** -- `feat: add WaveMode to GdGameModeRegistry` -- `fix: ScriptSandbox crashes on Worker timeout` -- `perf: throttle ui.set() to 250ms with diff check` +**Хорошо:** +- `feat: добавить WaveMode в GdGameModeRegistry` +- `fix: ScriptSandbox падает при таймауте Worker` +- `perf: дросселировать ui.set() до 250мс с diff-проверкой` -**Bad:** +**Плохо:** - `update code` - `wip` -- `fixed stuff` +- `пофиксил всякое` -## PR template +## Шаблон PR -When you open a PR, fill in: +При открытии PR заполни: ```markdown -## What +## Что -(1-2 sentences: what does this PR do?) +(1-2 предложения: что делает этот PR?) -## Why +## Зачем -(motivation: bug report, feature request, related issue #N) +(мотивация: репорт бага, фича-реквест, связанный issue #N) -## How to test +## Как протестить -(reproducible steps a reviewer can run) +(воспроизводимые шаги для ревьюера) -## Screenshots / video (if UI change) +## Скриншоты / видео (если UI-изменение) -## Checklist +## Чек-лист -- [ ] `npm run lint` passes -- [ ] `npm run format:check` passes -- [ ] `npm run build` succeeds -- [ ] Tested locally with `npm run dev` -- [ ] Updated relevant docs (README / ARCHITECTURE / CHANGELOG) -- [ ] CLA signed +- [ ] `npm run lint` проходит +- [ ] `npm run format:check` проходит +- [ ] `npm run build` собирается +- [ ] Протестил локально через `npm run dev` +- [ ] Обновил соответствующие доки (README / ARCHITECTURE / CHANGELOG) +- [ ] CLA подписан ``` -## Review process +## Процесс ревью -- The repo maintainer (МИН) reviews every PR. -- Expect feedback within **48 hours** (often same day). -- Small PRs (<300 lines changed) get reviewed fast. PRs >1000 lines will be asked to split. -- After approval, **maintainer merges** (only the maintainer has merge permission). -- After merge, an automated webhook triggers production deploy. +- Мейнтейнер репо (МИН) ревьюит каждый PR. +- Ожидай фидбек в течение **48 часов** (часто в тот же день). +- Маленькие PR (<300 строк) ревьюятся быстро. PR'ы >1000 строк попросят раздробить. +- После approval **мерджит мейнтейнер** (право merge только у него). +- После merge автоматический webhook запускает деплой в прод. -## What we won't merge +## Что не смерджим -- PRs that add new external dependencies without discussion -- PRs that touch sensitive paths (`engine/scripts/ScriptSandbox*.js`, `engine/multiplayer/*`) without security review -- PRs that break the build or lint -- PRs from contributors who haven't signed the CLA -- Massive refactors without a tracking issue discussed beforehand +- PR с новыми внешними зависимостями без обсуждения +- PR трогающие чувствительные пути (`engine/scripts/ScriptSandbox*.js`, `engine/multiplayer/*`) без security-ревью +- PR ломающие сборку или линт +- PR от контрибьюторов без подписанного CLA +- Массивные рефакторинги без заранее обсуждённого tracking-issue -## What we love +## Что любим -- Bug fixes with reproducible test cases -- Performance improvements with before/after metrics -- New `engine/gd/Gd*.js` gamemodes -- New script API additions (in `ScriptSandboxAPI.js`) -- Documentation improvements (especially examples) +- Багфиксы с воспроизводимыми тест-кейсами +- Улучшения производительности с before/after метриками +- Новые `engine/gd/Gd*.js` гейммоды +- Новые API для скриптов (в `ScriptSandboxAPI.js`) +- Улучшения документации (особенно с примерами) -## Security +## Безопасность -Found a vulnerability? **Don't open a public issue.** Email `security@rublox.pro` directly. See [SECURITY.md](./SECURITY.md). +Нашёл уязвимость? **Не открывай публичный issue.** Пиши на `security@rublox.pro` напрямую. См. [SECURITY.md](./SECURITY.md). -## Questions? +## Вопросы? -- Open an issue with the **Question** label -- Or hop into the `#разработка` channel at https://team.rublox.pro/chat +- Открой issue с лейблом **Question** +- Или приходи в канал `#разработка` на https://team.rublox.pro/chat diff --git a/README.md b/README.md index 296a8e7..8c07281 100644 --- a/README.md +++ b/README.md @@ -1,160 +1,164 @@ -# Rublox Player +# Плеер Рублокса -Open-source web player for Rublox games — a Roblox-like creator platform. +Open-source веб-плеер игр Рублокса — платформы для создания 3D-игр в стиле Roblox. -Built with **Babylon.js 7** + **React 18** + **Vite 5**. Plays user-created 3D games published from [Rublox Studio](https://git.rublox.pro/rublox/studio) (separate repo). +Построен на **Babylon.js 7** + **React 18** + **Vite 5**. Запускает пользовательские игры, опубликованные из [Студии Рублокса](https://git.rublox.pro/rublox/studio) (отдельный репозиторий). -[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](./LICENSE) -[![Commercial license available](https://img.shields.io/badge/Commercial-License--available-green.svg)](./LICENSE-COMMERCIAL.md) +[![Лицензия: AGPL-3.0](https://img.shields.io/badge/%D0%9B%D0%B8%D1%86%D0%B5%D0%BD%D0%B7%D0%B8%D1%8F-AGPL--3.0-blue.svg)](./LICENSE) +[![Коммерческая лицензия](https://img.shields.io/badge/%D0%9A%D0%BE%D0%BC%D0%BC%D0%B5%D1%80%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F-%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%BD%D0%B0-green.svg)](./LICENSE-COMMERCIAL.md) --- -## Quick start (5 minutes) +## Быстрый старт (5 минут) -**Requirements:** -- Node.js 18+ and npm 10+ -- A WebGL2-capable browser (Chrome 90+ / Firefox 90+ / Safari 15+) -- 4 GB RAM free (Babylon scenes are heavy) +**Требования:** +- Node.js 18+ и npm 10+ +- Браузер с WebGL2 (Chrome 90+ / Firefox 90+ / Safari 15+) +- 4 ГБ свободной памяти (Babylon-сцены тяжёлые) -**Install:** +**Установка:** ```bash git clone ssh://git@git.rublox.pro:2222/rublox/player.git cd player npm install -cp .env.example .env # defaults point at public staging — works out of the box +cp .env.example .env # дефолты указывают на публичный staging — работает сразу npm run dev ``` -Open `http://localhost:5173/` — for example `http://localhost:5173/265` for our GD demo level. +Открой `http://localhost:5173/` — например `http://localhost:5173/265` для нашего демо-уровня. -**Without a JWT** you'll see an auth-redirect screen. To bypass for local development: -1. Get a 90-day test JWT from a project maintainer (or use your own from rublox.pro). -2. In browser DevTools console: +**Без JWT** ты увидишь экран авторизации. Чтобы обойти его для локальной разработки: +1. Получи 90-дневный test-JWT у мейнтейнера (или используй свой с rublox.pro). +2. В DevTools браузера: ```js - localStorage.setItem('player_jwt', ''); + localStorage.setItem('player_jwt', '<вставь-сюда-свой-jwt>'); location.reload(); ``` --- -## Assets (GLB models / textures / sounds) +## Ассеты (GLB-модели / текстуры / звуки) -The `public/kubikon-assets/` folder (~106 MB) is **not stored in git** to keep the repo small. Download it separately: +Папка `public/kubikon-assets/` (~106 МБ) **не хранится в git** чтобы репозиторий был лёгким. Скачать отдельно: ```bash -# Download assets bundle from the latest release: +# Скачать последнюю версию ассетов из релиза: curl -L -o assets.zip https://git.rublox.pro/rublox/player/releases/download/latest/kubikon-assets.zip unzip assets.zip -d public/ ``` -In standalone mode (see below) you don't need the assets — only the bundled sample game runs. +В standalone-режиме (см. ниже) ассеты не нужны — там работает только встроенная демо-игра. --- -## Standalone mode (no backend needed) +## Standalone-режим (без бэкенда) -Don't have a JWT? Want to try the player without any auth? +Нет JWT? Хочешь попробовать плеер без авторизации? ```bash echo "VITE_STANDALONE=true" >> .env npm run dev ``` -Open `http://localhost:5173/sample` — loads a bundled demo project (`src/fixtures/sample-game.json`). All save/leaderboard/chat actions are no-ops. +Открой `http://localhost:5173/sample` — загрузится встроенный демо-проект (`src/fixtures/sample-game.json`). Все save/leaderboard/chat действия игнорируются. --- -## Project structure +## Структура проекта ``` src/ -├── engine/ # Babylon.js engine — 81 files, ~46k lines. -│ # Self-contained: BabylonScene, GameRuntime, MultiplayerSync, -│ # PlayerController, BlockManager, DecoManager, ScriptSandbox, -│ # 30+ GD (Geometry Dash) gamemode classes. -├── KubikonPlayer/ # Player container UI: menu, chat, comments, mobile controls. -├── editor-shared/ # HUD components shared with editor: hotbar, healthbar, GUI overlay. -├── AdminPreview/ # Preview routes for designer team (skins / music / portals catalogs). -├── PreviewSkin/ # Routes /_preview-skin/ etc. used by team.rublox.pro 3D previews. -├── components/ # Shared UI: EmailConfirmNotice, KubikonBugReport, Leaderboard. -├── api/ # API.js (config) + Kubikon3DService.js (endpoint wrappers). +├── engine/ # Движок Babylon.js — 81 файл, ~46k строк. +│ # Самодостаточный: BabylonScene, GameRuntime, +│ # MultiplayerSync, PlayerController, BlockManager, +│ # DecoManager, ScriptSandbox, 30+ классов GD-гейммодов. +├── KubikonPlayer/ # UI-контейнер плеера: меню, чат, комменты, моб. контролы. +├── editor-shared/ # HUD-компоненты общие с редактором: хотбар, healthbar, +│ # GUI-оверлей. +├── AdminPreview/ # Превью-роуты для команды дизайнеров (каталоги скинов, +│ # музыки, порталов). +├── PreviewSkin/ # Роуты /_preview-skin/ и т.д. — для 3D-превью на +│ # team.rublox.pro. +├── components/ # Общий UI: EmailConfirmNotice, KubikonBugReport, +│ # Leaderboard. +├── api/ # API.js (конфиг) + Kubikon3DService.js (обёртки эндпоинтов). ├── auth/ # PlayerAuth.jsx (JWT/ticket flow), ticketExchange.js. -├── hooks/ # useDeviceType.js (mobile/tablet detection). -├── utils/ # kubikonTime.js (relative time formatting). +├── hooks/ # useDeviceType.js (детект моб./планшет). +├── utils/ # kubikonTime.js (форматирование времени). ├── App.jsx, main.jsx, LoadingScreen.jsx -└── fixtures/ # sample-game.json for VITE_STANDALONE=true +└── fixtures/ # sample-game.json для VITE_STANDALONE=true ``` -For deep architecture, see [ARCHITECTURE.md](./ARCHITECTURE.md). +Подробнее об архитектуре — в [ARCHITECTURE.md](./ARCHITECTURE.md). --- -## Environment variables +## Переменные окружения -Copy `.env.example` to `.env` and edit: +Скопируй `.env.example` в `.env` и поправь: -| Variable | Default | Description | +| Переменная | Дефолт | Что означает | |---|---|---| -| `VITE_API_BASE` | _(empty)_ | HTTP API base URL. Empty = use vite proxy (dev). | -| `VITE_REALTIME_HTTP` | `https://dev-api.rublox.pro/api-game` | Colyseus HTTP endpoint (multiplayer matchmaking). | -| `VITE_REALTIME_WS` | `wss://dev-api.rublox.pro/api-game` | Colyseus WebSocket endpoint. | -| `VITE_RUBLOX_HOME` | `https://rublox.pro/app` | Where to redirect users with no auth. | -| `VITE_STANDALONE` | `false` | Skip API, load `sample-game.json`. | -| `VITE_API_PROXY_TARGET` | `https://dev-api.rublox.pro` | (dev only) vite-proxy target for `/api-*`. | +| `VITE_API_BASE` | _(пустая)_ | Базовый URL HTTP-API. Пустой = vite-proxy (для dev). | +| `VITE_REALTIME_HTTP` | `https://dev-api.rublox.pro/api-game` | Colyseus HTTP-эндпоинт (мультиплеер-матчмейкинг). | +| `VITE_REALTIME_WS` | `wss://dev-api.rublox.pro/api-game` | Colyseus WebSocket-эндпоинт. | +| `VITE_RUBLOX_HOME` | `https://rublox.pro/app` | Куда редиректить юзеров без авторизации. | +| `VITE_STANDALONE` | `false` | Пропустить API, загрузить `sample-game.json`. | +| `VITE_API_PROXY_TARGET` | `https://dev-api.rublox.pro` | (только dev) куда vite-proxy шлёт `/api-*`. | --- -## Contributing +## Контрибьютинг -We welcome PRs! Before your first contribution: +Мы рады PR'ам! Прежде чем впервые что-то контрибьютить: -1. Read [CONTRIBUTING.md](./CONTRIBUTING.md) for code style, branch naming, PR template. -2. Sign our [CLA](./CLA.md) — required before any merge (we use a CLA bot in Gitea). -3. Open issues for bugs / feature requests via the templates in `.gitea/ISSUE_TEMPLATE/`. +1. Прочитай [CONTRIBUTING.md](./CONTRIBUTING.md) — стиль кода, именование веток, шаблон PR. +2. Подпиши [CLA](./CLA.md) — обязательно перед первым merge (в Gitea стоит CLA-бот). +3. Открывай issues для багов/предложений через шаблоны в `.gitea/ISSUE_TEMPLATE/`. -**Quick PR cycle:** +**Быстрый цикл PR:** ```bash -git checkout -b feature/your-feature -# ...code... +git checkout -b feature/моя-фича +# ...пишешь код... npm run lint npm run format -git commit -m "feat: add foo" -git push origin feature/your-feature -# Open PR at https://git.rublox.pro/rublox/player +git commit -m "feat: добавил фичу" +git push origin feature/моя-фича +# Открой PR на https://git.rublox.pro/rublox/player ``` --- -## Common tasks +## Команды ```bash -npm run dev # Start dev server (vite, port 5173) -npm run build # Production build → build/ -npm run preview # Preview production build locally +npm run dev # Dev-сервер (vite, порт 5173) +npm run build # Прод-билд → build/ +npm run preview # Превью прод-билда локально npm run lint # ESLint -npm run format # Prettier (write) -npm run format:check # Prettier (check only — used in CI) +npm run format # Prettier (записать) +npm run format:check # Prettier (только проверить — используется в CI) ``` --- -## License +## Лицензия -Dual-licensed: +Двойная лицензия: -- **[AGPL-3.0-or-later](./LICENSE)** for open-source use. Forks and derivative works (including network-distributed services) MUST publish their source under the same license. -- **[Commercial License](./LICENSE-COMMERCIAL.md)** for proprietary use. Contact `maksimivankov26@yandex.ru`. +- **[AGPL-3.0-or-later](./LICENSE)** — для open-source использования. Форки и производные работы (включая сетевые сервисы) обязаны публиковать свой исходник под той же лицензией. +- **[Коммерческая лицензия](./LICENSE-COMMERCIAL.md)** — для проприетарных продуктов. Контакт: `maksimivankov26@yandex.ru`. -All contributors must sign the [CLA](./CLA.md) before their first merge. +Все контрибьюторы обязаны подписать [CLA](./CLA.md) перед первым merge. -© 2026 Иванкова Виктория Сергеевна (ИП). All rights reserved. +© 2026 Иванкова Виктория Сергеевна (ИП). Все права защищены. --- -## Links +## Ссылки -- Main site: https://rublox.pro -- Player demo: https://player.rublox.pro -- Studio (separate repo): https://git.rublox.pro/rublox/studio -- Issues & PRs: https://git.rublox.pro/rublox/player -- Security: see [SECURITY.md](./SECURITY.md) +- Главный сайт: https://rublox.pro +- Демо плеера: https://player.rublox.pro +- Студия (отдельный репо): https://git.rublox.pro/rublox/studio +- Issues и PR: https://git.rublox.pro/rublox/player +- Безопасность: см. [SECURITY.md](./SECURITY.md) diff --git a/SECURITY.md b/SECURITY.md index ba7fd73..9c960c9 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,64 +1,64 @@ -# Security Policy +# Политика безопасности -## Supported versions +## Поддерживаемые версии -Only the `main` branch receives security updates. Tagged releases (`v0.x`) are best-effort. +Только ветка `main` получает security-обновления. Тегированные релизы (`v0.x`) — best-effort. -## Reporting a vulnerability +## Сообщение об уязвимости -**Do NOT open a public issue for security vulnerabilities.** +**НЕ открывай публичный issue для уязвимостей безопасности.** -Vulnerabilities in this player can directly impact our production service at `player.rublox.pro` and the games that users have published. Public disclosure before a patch can lead to real harm to real users (including minors who play our games). +Уязвимости в этом плеере могут напрямую повлиять на наш продакшен `player.rublox.pro` и игры, опубликованные юзерами. Публичное раскрытие до выпуска патча может привести к реальному вреду реальным пользователям (включая несовершеннолетних, играющих в наши игры). -Please email: **`security@rublox.pro`** (read only by the project maintainer) +Пиши на: **`security@rublox.pro`** (читает только мейнтейнер проекта) -Include: +Включи в письмо: -1. A description of the issue -2. Steps to reproduce (or a proof-of-concept) -3. Affected versions / files -4. Your impact assessment (XSS / RCE / IDOR / sandbox escape / etc.) -5. Your contact for follow-up -6. Whether you want public credit after the fix (we'll add you to a Hall of Fame in CHANGELOG) +1. Описание проблемы +2. Шаги воспроизведения (или proof-of-concept) +3. Затронутые версии / файлы +4. Твою оценку воздействия (XSS / RCE / IDOR / побег из песочницы / и т.д.) +5. Твой контакт для уточнений +6. Хочешь ли публичное упоминание после фикса (добавим в Hall of Fame в CHANGELOG) -## What to expect +## Что ожидать -| Step | Time | +| Шаг | Сроки | |---|---| -| Acknowledgement | within 24 hours | -| Severity assessment | within 3 business days | -| Fix in private branch | within 7 days for critical | -| Public patch release | when ready, with credit | +| Подтверждение получения | в течение 24 часов | +| Оценка серьёзности | в течение 3 рабочих дней | +| Фикс в приватной ветке | в течение 7 дней для критичных | +| Публичный релиз патча | когда готов, с благодарностью | -## Especially welcome +## Особенно ценные находки -The following classes of bugs are highly valued (because they can compromise users): +Следующие классы багов **высоко ценятся** (потому что могут скомпрометировать пользователей): -- **Script sandbox escape** (`engine/scripts/ScriptSandbox*.js`) — a user-uploaded game script gaining access to `window`, `document`, `fetch`, `localStorage`, or hijacking other players' sessions. -- **XSS in game-content rendering** — game titles, chat messages, comment bodies that get rendered as HTML. -- **Multiplayer message-injection** — crafted Colyseus messages causing other clients to crash or execute attacker code. -- **Auth-token leakage** — JWT or ticket appearing in URLs, query strings, console logs, error pages, or analytics events. -- **Asset-URL injection** — `url:...` prefixes (designer-uploaded models) that load arbitrary files from outside our asset bucket. +- **Побег из script-песочницы** (`engine/scripts/ScriptSandbox*.js`) — скрипт юзера получает доступ к `window`, `document`, `fetch`, `localStorage`, либо угоняет сессии других игроков. +- **XSS в рендере контента игр** — названия игр, чат-сообщения, тексты комментов рендерятся как HTML. +- **Инъекция мультиплеер-сообщений** — кастомные Colyseus-сообщения роняют других клиентов или выполняют код атакующего. +- **Утечка auth-токена** — JWT или ticket появляется в URL, query-string, console-логах, error-страницах или analytics-событиях. +- **Инъекция в asset-URL** — префиксы `url:...` (модели от дизайнеров) загружают произвольные файлы вне нашего asset-бакета. -## Things that are NOT vulnerabilities +## Что НЕ является уязвимостью -(Save your and our time — these get rejected.) +(Не теряй своё и наше время — эти отчёты отклоняются.) -- Missing `X-Frame-Options` or `Content-Security-Policy` (we know, working on it server-side). -- Self-XSS (user pasting JS into their own DevTools). -- Outdated `npm audit` warnings without a working exploit. -- Information disclosure of files in the repo (it's open-source!). -- Reports generated by automated scanners with no manual verification. +- Отсутствующий `X-Frame-Options` или `Content-Security-Policy` (знаем, работаем над этим на стороне сервера). +- Self-XSS (юзер сам вставляет JS в свой DevTools). +- Устаревшие `npm audit` warning'и без рабочего эксплойта. +- Раскрытие информации о файлах в репо (это же open-source!). +- Отчёты от автоматических сканеров без ручной проверки. -## Reward +## Награда -We're a small project. We can't pay bounties, but for any genuine vulnerability: +Мы маленький проект и не можем платить bounty, но за любую настоящую уязвимость: -- Public credit in `CHANGELOG.md` (if you want) -- Inclusion in a "Hall of Fame" section in this file -- Personal thank-you from the maintainer -- For high-impact reports: a one-time financial gift at the maintainer's discretion (rare, but possible) +- Публичное упоминание в `CHANGELOG.md` (если хочешь) +- Включение в раздел «Hall of Fame» этого файла +- Личное спасибо от мейнтейнера +- За high-impact-репорты: разовый денежный подарок по усмотрению мейнтейнера (редко, но возможно) ## Hall of Fame -_Empty so far — be the first!_ +_Пока пусто — стань первым!_ diff --git a/package.json b/package.json index 3fdda20..1cac6c0 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "rublox-player", "version": "1.0.0", "type": "module", - "description": "Open-source web player for Rublox games — a Roblox-like creator platform. Babylon.js 7 + React 18 + Vite 5.", + "description": "Open-source веб-плеер игр Рублокса — платформы создания 3D-игр в стиле Roblox. Babylon.js 7 + React 18 + Vite 5.", "keywords": [ "rublox", "game-player",