diff --git a/rbxl-importer/src/__pycache__/converter.cpython-314.pyc b/rbxl-importer/src/__pycache__/converter.cpython-314.pyc index 85731e3..052a1c9 100644 Binary files a/rbxl-importer/src/__pycache__/converter.cpython-314.pyc and b/rbxl-importer/src/__pycache__/converter.cpython-314.pyc differ diff --git a/rbxl-importer/src/app.py b/rbxl-importer/src/app.py index 4e31893..9da2929 100644 --- a/rbxl-importer/src/app.py +++ b/rbxl-importer/src/app.py @@ -216,6 +216,10 @@ def create(): scripts_mode = data.get('scripts_mode', 'disabled') if scripts_mode not in ('disabled', 'enabled', 'skip'): scripts_mode = 'disabled' + # gui_mode: 'all' / 'screen-only' (только ScreenGui-HUD) / 'skip' (без GUI) + gui_mode = data.get('gui_mode', 'all') + if gui_mode not in ('all', 'screen-only', 'skip'): + gui_mode = 'all' if not preview_hash: return jsonify({'error': 'preview_hash required'}), 400 @@ -284,6 +288,10 @@ def create(): # либо удаляем все скрипты полностью. _apply_scripts_mode(project_data, scripts_mode) + # Применяем gui_mode: удаляем 3D-GUI (BillboardGui/SurfaceGui) или вообще + # всё, если выбрано 'skip'. + _apply_gui_mode(project_data, gui_mode) + # Создаём проект в kubikon3d_projects # Используем bridge на user-service / storys API, ИЛИ напрямую в storys_db. # Прямой INSERT — проще для MVP. id автогенерируется. @@ -345,6 +353,26 @@ def _resolve_asset_urls(project_data: dict, asset_map: dict) -> None: snd['url'] = asset_map[rid] +def _apply_gui_mode(project_data: dict, mode: str) -> None: + """Фильтрует scene.gui[] по режиму. + + 'all' — оставить всё (default). + 'screen-only' — оставить только ScreenGui-HUD, удалить billboard/surface. + Карты с 200+ BillboardGui (Robloxity) перестают тормозить. + 'skip' — удалить gui[] совсем. + """ + scene = project_data.get('scene', {}) + if mode == 'skip': + scene['gui'] = [] + return + if mode == 'screen-only': + gui = scene.get('gui', []) + scene['gui'] = [g for g in gui + if g.get('gui_container_kind', 'screen') == 'screen'] + return + # 'all' — без изменений + + def _apply_scripts_mode(project_data: dict, mode: str) -> None: """Применяет режим scripts_mode к проекту. diff --git a/rbxl-importer/src/converter.py b/rbxl-importer/src/converter.py index 3478cd8..ce15ca2 100644 --- a/rbxl-importer/src/converter.py +++ b/rbxl-importer/src/converter.py @@ -825,9 +825,13 @@ class Converter: if not hasattr(self, '_screen_gui_refs'): self._screen_gui_refs = set() self._screen_gui_enabled = {} + self._screen_gui_kind = {} # ref → 'screen' | 'billboard' | 'surface' self._screen_gui_refs.add(inst.referent) enabled = inst.properties.get('Enabled', True) self._screen_gui_enabled[inst.referent] = bool(enabled) if enabled is not None else True + # Сохраняем тип контейнера — потом отфильтруем 3D-GUI если выбрано screen-only + kind = {'ScreenGui': 'screen', 'BillboardGui': 'billboard', 'SurfaceGui': 'surface'}.get(inst.class_name, 'screen') + self._screen_gui_kind[inst.referent] = kind def _gui_parent_id(self, parent_ref) -> Optional[str]: if parent_ref is None: @@ -921,12 +925,14 @@ class Converter: # элемент тоже невидим. parent_ref = inst.parent_referent screen_enabled = True + container_kind = 'screen' # default if hasattr(self, '_screen_gui_refs'): cur = parent_ref depth = 0 while cur is not None and depth < 50: if cur in self._screen_gui_refs: screen_enabled = self._screen_gui_enabled.get(cur, True) + container_kind = self._screen_gui_kind.get(cur, 'screen') break # Поиск родителя cur в instances (если есть) cur_inst = self.model.by_referent.get(cur) if hasattr(self, 'model') else None @@ -979,6 +985,10 @@ class Converter: 'imageAsset': None, 'zIndex': int(props.get('ZIndex', 1) or 1), 'origin': 'roblox-' + cls.lower(), + # 'screen' — обычный HUD; 'billboard' — 3D-табличка над частью; + # 'surface' — на грани Part. Last 2 рендерятся в 3D-сцене и + # сильно тормозят если их сотни. + 'gui_container_kind': container_kind, } scene['gui'].append(element) diff --git a/src/api/rbxlImporterApi.js b/src/api/rbxlImporterApi.js index fa7b762..9fbe53a 100644 --- a/src/api/rbxlImporterApi.js +++ b/src/api/rbxlImporterApi.js @@ -63,6 +63,8 @@ export async function createRbxlProject(previewHash, title, opts = {}) { // 'enabled' — попытаться запустить (может вешать карту) // 'skip' — не импортировать совсем scripts_mode: opts.scriptsMode || 'disabled', + // 'all' (default) / 'screen-only' (только HUD) / 'skip' (без GUI) + gui_mode: opts.guiMode || 'all', }), }); if (!resp.ok) { diff --git a/src/components/RbxlImportModal.jsx b/src/components/RbxlImportModal.jsx index 9c3e5cd..2247a42 100644 --- a/src/components/RbxlImportModal.jsx +++ b/src/components/RbxlImportModal.jsx @@ -29,6 +29,10 @@ export default function RbxlImportModal({ open, onClose, currentUserId, onCreate // Режим скриптов: 'disabled' (импортнуть выключенными — для чтения), // 'enabled' (попытаться запустить — может вешать карту), 'skip' (удалить). const [scriptsMode, setScriptsMode] = useState('disabled'); + // Режим GUI: 'all' — все, 'screen-only' — только ScreenGui (HUD), + // 'skip' — не импортировать. Старые карты часто имеют 200+ BillboardGui + // (вывески города), что вешает рендер. + const [guiMode, setGuiMode] = useState('all'); const fileInputRef = useRef(null); if (!open) return null; @@ -49,6 +53,7 @@ export default function RbxlImportModal({ open, onClose, currentUserId, onCreate setFile(null); setReport(null); setPreviewHash(null); setTitle(''); setError(null); setAnalyzing(false); setCreating(false); setScriptsMode('disabled'); + setGuiMode('all'); }; const handleClose = () => { reset(); onClose?.(); }; @@ -92,7 +97,7 @@ export default function RbxlImportModal({ open, onClose, currentUserId, onCreate setCreating(true); setError(null); try { - const result = await createRbxlProject(previewHash, title, { scriptsMode }); + const result = await createRbxlProject(previewHash, title, { scriptsMode, guiMode }); onCreated?.(result); handleClose(); // редирект на редактор @@ -179,6 +184,29 @@ export default function RbxlImportModal({ open, onClose, currentUserId, onCreate + {report.primitives_created > 5000 && ( +