diff --git a/src/engine/BabylonScene.js b/src/engine/BabylonScene.js index 4855a81..0d3b9a1 100644 --- a/src/engine/BabylonScene.js +++ b/src/engine/BabylonScene.js @@ -7154,6 +7154,35 @@ export class BabylonScene { this._syncUserModelColliders(); } + // === Тип модели персонажа — РЕШАЕМ ДО предзагрузки/плеера === + // ВАЖНО: должно стоять ВЫШЕ _loadPrototype и до enterPlayMode, иначе + // PlayerController прочитает старый _playerModelType (баг: пончик 2046 + // не ставился — skins.default применялся ниже, после предзагрузки). + // Миграция: старые проекты сохраняли Kenney-модель ('character-a..g'); + // форсим R15 bacon-hair. Явно выбранные 'skin_*' не трогаем. + if (state.scene.playerModelType) { + const pmt = state.scene.playerModelType; + this._playerModelType = pmt.startsWith('character-') ? 'skin_bacon-hair' : pmt; + } + // Задача 07: конфиг скинов { default, unlocked, shopVisible, coins, customGlbs }. + if (state.scene.skins && typeof state.scene.skins === 'object') { + this._skinsConfig = { + default: state.scene.skins.default || null, + unlocked: Array.isArray(state.scene.skins.unlocked) ? state.scene.skins.unlocked.slice() : [], + shopVisible: state.scene.skins.shopVisible !== false, + coins: Number.isFinite(state.scene.skins.coins) ? state.scene.skins.coins : 0, + customGlbs: Array.isArray(state.scene.skins.customGlbs) ? state.scene.skins.customGlbs.slice() : [], + }; + // Стартовый скин из skins.default имеет приоритет над playerModelType. + if (this._skinsConfig.default) { + const d = this._skinsConfig.default; + this._playerModelType = (d.startsWith('character-') || d.startsWith('skin_') || d.startsWith('customskin:')) + ? d : ('skin_' + d); + } + } else { + this._skinsConfig = null; + } + // ОПТИМИЗАЦИЯ: предзагружаем модель ИГРОКА (character) тоже — // PlayerController.start() её ждёт, но если предзагрузить сейчас, // на enterPlayMode она будет в кэше Babylon и стартует мгновенно. @@ -7251,36 +7280,7 @@ export class BabylonScene { } } } catch (e) { console.warn('[BabylonScene] spawn auto-lift failed:', e); } - // Тип модели персонажа. - // Миграция: старые проекты сохраняли Kenney-модель ('character-a..g'). - // Теперь стандарт — R15-скин bacon-hair. Если в проекте старая - // Kenney-модель — форсим bacon-hair. Явно выбранные 'skin_*' не трогаем. - if (state.scene.playerModelType) { - const pmt = state.scene.playerModelType; - if (pmt.startsWith('character-')) { - this._playerModelType = 'skin_bacon-hair'; - } else { - this._playerModelType = pmt; - } - } - // Задача 07: конфиг скинов проекта { default, unlocked, shopVisible, coins, customGlbs }. - if (state.scene.skins && typeof state.scene.skins === 'object') { - this._skinsConfig = { - default: state.scene.skins.default || null, - unlocked: Array.isArray(state.scene.skins.unlocked) ? state.scene.skins.unlocked.slice() : [], - shopVisible: state.scene.skins.shopVisible !== false, - coins: Number.isFinite(state.scene.skins.coins) ? state.scene.skins.coins : 0, - customGlbs: Array.isArray(state.scene.skins.customGlbs) ? state.scene.skins.customGlbs.slice() : [], - }; - // Стартовый скин из skins.default имеет приоритет над playerModelType. - if (this._skinsConfig.default) { - const d = this._skinsConfig.default; - this._playerModelType = d.startsWith('character-') || d.startsWith('skin_') || d.startsWith('customskin:') - ? d : ('skin_' + d); - } - } else { - this._skinsConfig = null; - } + // (Тип модели персонажа и skins решены выше — до предзагрузки модели.) // Пользовательские скрипты if (Array.isArray(state.scene.scripts)) { this._scripts = state.scene.scripts