From e3b49683388e84a64cc89401a54c32f8cc1393eb Mon Sep 17 00:00:00 2001 From: min Date: Mon, 15 Jun 2026 11:46:02 +0300 Subject: [PATCH] =?UTF-8?q?fix(skin):=20=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D1=81=D0=BA=D0=B8=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=B2=20Play-=D1=80=D0=B5=D0=B6=D0=B8=D0=BC=D0=B5=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B4=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B0=20(legacy=20ba?= =?UTF-8?q?con=20=E2=86=92=20y-bot)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KubikonEditor подмешивал skin_folder из БД в hash без проверки. Для ~22 legacy-юзеров БД отдаёт skin_bacon-hair (модель удалена) → в Play-режиме студии играл бекон. Теперь невалидный скин (не в MIXAMO_SKINS и не customskin:) подменяется на skin_y-bot, как в плеере (KubikonPlayer/GameMenu) и кабинете. Дефолты bacon → y-bot. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/editor/KubikonEditor.jsx | 18 ++++++++++++++---- src/editor/engine/PlayerController.js | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/editor/KubikonEditor.jsx b/src/editor/KubikonEditor.jsx index 2d1cacc..f234316 100644 --- a/src/editor/KubikonEditor.jsx +++ b/src/editor/KubikonEditor.jsx @@ -4,6 +4,7 @@ import { jwtDecode } from 'jwt-decode'; import { useAuth, redirectToLogin } from '../auth/AuthContext.jsx'; import { useSanctions } from '../auth/SanctionsContext.jsx'; import { BabylonScene } from './engine/BabylonScene'; +import { MIXAMO_SKINS } from './engine/PlayerController'; import { StudioCollab } from './engine/StudioCollab'; import { CollabOverlay } from './engine/CollabOverlay'; import { BLOCK_TYPES, BLOCK_CATEGORIES, blockPreview, registerCustomBlockType } from './engine/BlockTypes'; @@ -938,7 +939,7 @@ const KubikonEditor = () => { // === Game settings inline в TopRibbon (вкладка Тест) === // Дефолт — R15-скин bacon-hair (классический Roblox-вид). - const [playerModelType, setPlayerModelTypeUI] = useState('skin_bacon-hair'); + const [playerModelType, setPlayerModelTypeUI] = useState('skin_y-bot'); const [envPreset, setEnvPresetUI] = useState('day'); const [dayDurationMin, setDayDurationMinUI] = useState(5); const [nightDurationMin, setNightDurationMinUI] = useState(3); @@ -964,7 +965,7 @@ const KubikonEditor = () => { genre: 'other', thumbnail: '', is_public: false, - player_model_type: 'skin_bacon-hair', + player_model_type: 'skin_y-bot', }); const projectNameRef = useRef(projectName); useEffect(() => { projectNameRef.current = projectName; metaRef.current.title = projectName; }, [projectName]); @@ -1782,7 +1783,7 @@ const KubikonEditor = () => { sceneRef.current.history?.initialize(); // Синхронизируем UI-state TopRibbon из загруженной сцены try { - setPlayerModelTypeUI(sceneRef.current.getPlayerModelType?.() || 'skin_bacon-hair'); + setPlayerModelTypeUI(sceneRef.current.getPlayerModelType?.() || 'skin_y-bot'); const env = sceneRef.current.getEnvironmentState?.(); if (env?.preset) setEnvPresetUI(env.preset); if (env?.dayDurationMin) setDayDurationMinUI(env.dayDurationMin); @@ -2093,7 +2094,16 @@ const KubikonEditor = () => { const uid = getCurrentUserId(); if (uid) { const r = await Kubikon3DApi.getEquippedSkin(uid); - const sf = r?.data?.skin_folder; + let sf = r?.data?.skin_folder; + // ВАЛИДАЦИЯ: legacy R15-скины (bacon-hair и пр.) больше + // не существуют. Если БД отдала невалидный — подменяем + // на skin_y-bot (как в плеере и кабинете). + if (sf && typeof sf === 'string' + && !MIXAMO_SKINS.has(sf) + && !sf.startsWith('customskin:')) { + console.log('[KubikonEditor] skin', sf, 'не валиден → skin_y-bot'); + sf = 'skin_y-bot'; + } if (sf && typeof sf === 'string') { // Подмешиваем в hash так чтобы не сломать ticket=... const cur = window.location.hash || ''; diff --git a/src/editor/engine/PlayerController.js b/src/editor/engine/PlayerController.js index 682ff86..77fa4b9 100644 --- a/src/editor/engine/PlayerController.js +++ b/src/editor/engine/PlayerController.js @@ -32,7 +32,7 @@ import { MixamoAnimator, loadMixamoAnimations } from './MixamoAnimator'; // Список всех Mixamo-скинов. Должен совпадать со списком в плеере и // каталоге сайта (rublox-site/src/data/skinsCatalog.js). -const MIXAMO_SKINS = new Set([ +export const MIXAMO_SKINS = new Set([ 'skin_aj', 'skin_akai', 'skin_arissa', 'skin_big-vegas', 'skin_castle-guard-1', 'skin_castle-guard-2', 'skin_ch01', 'skin_ch02', 'skin_ch03', 'skin_ch04', 'skin_ch07', 'skin_ch08',