player/src/engine/GdStartArch.js
МИН 87444ee2c8 Initial public release: Rublox Player v1.0
Open-source web player for Rublox games, dual-licensed under
AGPL-3.0 + Commercial.

Highlights:
- Babylon.js 7 + React 18 + Vite 5 stack
- Self-contained engine (~46k lines): BlockManager, ModelManager,
  PlayerController, ScriptSandboxWorker, MultiplayerSync, 30+ GD
  gamemodes
- Configurable backend via VITE_API_BASE and friends — works against
  staging (dev-api.rublox.pro) out of the box
- Standalone mode (VITE_STANDALONE=true) loads a bundled sample game
  for first-run without any backend
- Full docs: README, ARCHITECTURE, CONTRIBUTING, SECURITY, CHANGELOG
- Lint + format scaffolding (ESLint + Prettier + EditorConfig)
- Legal: LICENSE (AGPL-3.0), LICENSE-COMMERCIAL.md, CLA.md, COPYRIGHT.md
- Issue templates: bug_report, feature_request, security_disclosure

Removed before public release:
- frontend_deploy.py (contained production SSH credentials)
- ~27 admin endpoints (kept in private repo)
- Hard-coded internal URLs and IPs
- All previous git history (clean repo init)
2026-05-27 23:04:04 +03:00

95 lines
3.6 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.

/**
* GdStartArch — стартовая арка в начале GD-уровня (этап G4).
*
* Берёт выбранную юзером арку (по эпохе → ARCH_CATALOG.id) или дефолтную
* для текущей эпохи, ставит её в (x=ARCH_X, y=0, z=0) лицом к камере (-Z).
*
* При желании скрипт уровня может вызвать gdStartArch.celebrate() —
* лёгкая пульсация по высоте на первые ~1.5с.
*/
import { Vector3, TransformNode } from '@babylonjs/core';
import { ARCH_CATALOG } from '../AdminPreview/gdArches/archFactories';
// Дефолтный выбор арки по эпохе (выбор юзера сохранён в gd_arch_choices).
const DEFAULT_ARCH_BY_EPOCH = {
1: 'a1_v5', // Рустик
2: 'a2_v3', // Ледяная
3: 'a3_v5',
4: 'a4_v1',
5: 'a5_v1',
6: 'a6_v5',
7: 'a7_v1',
8: 'a8_v5',
9: 'a9_v2',
10: 'a10_v1',
};
// Позиция арки — чуть до x=0, чтобы куб стартовал ВНУТРИ неё.
const ARCH_X = -2;
export class GdStartArch {
constructor() {
this.scene = null;
this._handle = null;
this._root = null;
this._t = 0;
this._onBeforeRender = null;
this._celebrating = false;
this._celebrateStart = 0;
}
attach(scene, epoch = 1, archId = null) {
if (!scene) return;
this.scene = scene;
const id = archId || DEFAULT_ARCH_BY_EPOCH[epoch] || 'a1_v4';
const factory = ARCH_CATALOG.find(a => a.id === id);
if (!factory) {
console.warn('[GdStartArch] фабрика не найдена:', id);
return;
}
const h = factory.make(scene, `gd_arch_inst`);
if (!h || !h.root) return;
this._handle = h;
this._root = h.root;
this._root.position = new Vector3(ARCH_X, 1, 0); // низ арки = верх пола (y=1)
// Поворот на 90° по Y: фабрики строят арку ширнной по X, лицом в +Z.
// Куб бежит по +X — арка должна стоять поперёк трассы, проёмом вдоль X.
// Значит колонны должны быть на ±Z, балка вдоль Z. Поворот = π/2.
this._root.rotation.y = Math.PI / 2;
this._onBeforeRender = () => {
this._t += 0.01;
// Если был празднички — лёгкая пульсация
if (this._celebrating) {
const elapsed = this._t - this._celebrateStart;
if (elapsed > 1.5) {
this._celebrating = false;
this._root.scaling.set(1, 1, 1);
} else {
const s = 1 + Math.sin(elapsed * 12) * 0.04 * (1 - elapsed / 1.5);
this._root.scaling.set(s, s, s);
}
}
};
scene.onBeforeRenderObservable.add(this._onBeforeRender);
}
celebrate() {
this._celebrating = true;
this._celebrateStart = this._t;
}
dispose() {
if (!this.scene) return;
try {
if (this._onBeforeRender) {
this.scene.onBeforeRenderObservable.removeCallback(this._onBeforeRender);
this._onBeforeRender = null;
}
} catch (e) {}
try { this._handle && this._handle.dispose && this._handle.dispose(); } catch (e) {}
this._handle = null;
this._root = null;
this.scene = null;
}
}