import { Box, Typography, Button, Snackbar, Alert, LinearProgress, } from '@mui/material'; import { useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import ServerStatus from '../components/ServerStatus/ServerStatus'; import PopaPopa from '../components/popa-popa'; import SettingsIcon from '@mui/icons-material/Settings'; import React from 'react'; import SettingsModal from '../components/Settings/SettingsModal'; declare global { interface Window { electron: { ipcRenderer: { invoke(channel: string, ...args: unknown[]): Promise; on(channel: string, func: (...args: unknown[]) => void): void; removeAllListeners(channel: string): void; }; }; } } // Определяем тип для props interface LaunchPageProps { onLaunchPage?: () => void; launchOptions?: { // Делаем опциональным downloadUrl: string; apiReleaseUrl: string; versionFileName: string; packName: string; memory: number; baseVersion: string; serverIp: string; fabricVersion: string; }; } const LaunchPage = ({ onLaunchPage, launchOptions = {} as any, }: LaunchPageProps) => { const navigate = useNavigate(); const { versionId } = useParams(); const [versionConfig, setVersionConfig] = useState(null); // Начальное состояние должно быть пустым или с минимальными значениями const [config, setConfig] = useState<{ memory: number; preserveFiles: string[]; }>({ memory: 0, preserveFiles: [], }); const [isDownloading, setIsDownloading] = useState(false); const [downloadProgress, setDownloadProgress] = useState(0); const [buffer, setBuffer] = useState(10); const [installStatus, setInstallStatus] = useState(''); const [notification, setNotification] = useState<{ open: boolean; message: string; severity: 'success' | 'error' | 'info'; }>({ open: false, message: '', severity: 'info' }); const [installStep, setInstallStep] = useState(''); const [installMessage, setInstallMessage] = useState(''); const [open, setOpen] = React.useState(false); const handleOpen = () => setOpen(true); const handleClose = () => setOpen(false); useEffect(() => { const savedConfig = localStorage.getItem('launcher_config'); if (!savedConfig || !JSON.parse(savedConfig).accessToken) { navigate('/login'); } const progressListener = (...args: unknown[]) => { const progress = args[0] as number; setDownloadProgress(progress); setBuffer(Math.min(progress + 10, 100)); }; const statusListener = (...args: unknown[]) => { const status = args[0] as { step: string; message: string }; setInstallStep(status.step); setInstallMessage(status.message); }; window.electron.ipcRenderer.on('download-progress', progressListener); window.electron.ipcRenderer.on('installation-status', statusListener); return () => { // Удаляем только конкретных слушателей, а не всех // Это безопаснее, чем removeAllListeners const cleanup = window.electron.ipcRenderer.on; if (typeof cleanup === 'function') { cleanup('download-progress', progressListener); cleanup('installation-status', statusListener); } // Удаляем использование removeAllListeners }; }, [navigate]); useEffect(() => { const fetchVersionConfig = async () => { if (!versionId) return; try { // Сначала проверяем, есть ли конфигурация в localStorage const savedConfig = localStorage.getItem('selected_version_config'); if (savedConfig) { const parsedConfig = JSON.parse(savedConfig); setVersionConfig(parsedConfig); // Устанавливаем значения памяти и preserveFiles из конфигурации setConfig({ memory: parsedConfig.memory || 4096, preserveFiles: parsedConfig.preserveFiles || [], }); // Очищаем localStorage localStorage.removeItem('selected_version_config'); return; } // Если нет в localStorage, запрашиваем с сервера const result = await window.electron.ipcRenderer.invoke( 'get-version-config', { versionId }, ); if (result.success) { setVersionConfig(result.config); setConfig({ memory: result.config.memory || 4096, preserveFiles: result.config.preserveFiles || [], }); } else { // Если не удалось получить конфигурацию, используем значения по умолчанию const defaultConfig = { downloadUrl: '', apiReleaseUrl: '', versionFileName: `${versionId}_version.txt`, packName: versionId || 'Comfort', memory: 4096, baseVersion: '1.21.4', serverIp: 'popa-popa.ru', fabricVersion: '0.16.14', preserveFiles: ['popa-launcher-config.json'], }; setVersionConfig(defaultConfig); setConfig({ memory: defaultConfig.memory, preserveFiles: defaultConfig.preserveFiles || [], }); } } catch (error) { console.error('Ошибка при получении настроек версии:', error); // Используем значения по умолчанию const defaultConfig = { downloadUrl: '', apiReleaseUrl: '', versionFileName: `${versionId}_version.txt`, packName: versionId || 'Comfort', memory: 4096, baseVersion: '1.21.4', serverIp: 'popa-popa.ru', fabricVersion: '0.16.14', preserveFiles: ['popa-launcher-config.json'], }; setVersionConfig(defaultConfig); setConfig({ memory: defaultConfig.memory, preserveFiles: defaultConfig.preserveFiles || [], }); } }; fetchVersionConfig(); }, [versionId]); const showNotification = ( message: string, severity: 'success' | 'error' | 'info', ) => { setNotification({ open: true, message, severity }); }; const handleCloseNotification = () => { setNotification({ ...notification, open: false }); }; // Функция для запуска игры с настройками выбранной версии const handleLaunchMinecraft = async () => { try { setIsDownloading(true); setDownloadProgress(0); setBuffer(10); // Используем настройки выбранной версии или дефолтные const currentConfig = versionConfig || { packName: versionId || 'Comfort', memory: 4096, baseVersion: '1.21.4', serverIp: 'popa-popa.ru', fabricVersion: '0.16.14', preserveFiles: [], }; // Проверяем, является ли это ванильной версией const isVanillaVersion = !currentConfig.downloadUrl || currentConfig.downloadUrl === ''; if (!isVanillaVersion) { // Если это не ванильная версия, выполняем загрузку и распаковку const packOptions = { downloadUrl: currentConfig.downloadUrl, apiReleaseUrl: currentConfig.apiReleaseUrl, versionFileName: currentConfig.versionFileName, packName: versionId || currentConfig.packName, preserveFiles: config.preserveFiles, }; // Передаем опции для скачивания const downloadResult = await window.electron.ipcRenderer.invoke( 'download-and-extract', packOptions, ); if (downloadResult?.success) { if (downloadResult.updated) { showNotification( `Сборка ${downloadResult.packName} успешно обновлена до версии ${downloadResult.version}`, 'success', ); } else { showNotification( `Установлена актуальная версия сборки ${downloadResult.packName} (${downloadResult.version})`, 'info', ); } } } else { showNotification('Запускаем ванильный Minecraft...', 'info'); } // Опции для запуска Minecraft const savedConfig = JSON.parse( localStorage.getItem('launcher_config') || '{}', ); const options = { accessToken: savedConfig.accessToken, uuid: savedConfig.uuid, username: savedConfig.username, memory: config.memory, baseVersion: currentConfig.baseVersion, packName: versionId || currentConfig.packName, serverIp: currentConfig.serverIp, fabricVersion: currentConfig.fabricVersion, // Для ванильной версии устанавливаем флаг isVanillaVersion: isVanillaVersion, versionToLaunchOverride: isVanillaVersion ? versionId : undefined, }; const launchResult = await window.electron.ipcRenderer.invoke( 'launch-minecraft', options, ); if (launchResult?.success) { showNotification('Minecraft успешно запущен!', 'success'); } } catch (error) { console.error('Error:', error); showNotification(`Ошибка: ${error.message}`, 'error'); } finally { setIsDownloading(false); } }; // Функция для сохранения настроек const savePackConfig = async () => { try { const configToSave = { memory: config.memory, preserveFiles: config.preserveFiles || [], }; await window.electron.ipcRenderer.invoke('save-pack-config', { packName: versionId || versionConfig?.packName || 'Comfort', config: configToSave, }); // Обновляем launchOptions launchOptions.memory = config.memory; showNotification('Настройки сохранены', 'success'); } catch (error) { console.error('Ошибка при сохранении настроек:', error); showNotification('Ошибка сохранения настроек', 'error'); } }; return ( Игровой сервер долбаёбов в Minecraft СЕРВЕР ГДЕ ВСЕМ НА ВАС ПОХУЙ СЕРВЕР ГДЕ РАЗРЕШЕНЫ ОДНОПОЛЫЕ БРАКИ СЕРВЕР ГДЕ ВСЕ ДОЛБАЕБЫ СЕРВЕР ГДЕ НА СПАВНЕ БУДЕТ ХУЙ (ВОЗМОЖНО) СЕРВЕР ЗА КОТОРЫЙ ВЫ ПРОДАДИТЕ МАТЬ ТЫ МОЖЕШЬ КУПИТЬ АДМИНКУ И ПОЛУЧИТЬ ПИЗДЫ {isDownloading ? ( {`${Math.round(downloadProgress)}%`} ) : ( {/* Первая кнопка — растягивается на всё доступное пространство */} {/* Вторая кнопка — квадратная, фиксированного размера (ширина = высоте) */} )} {notification.message} ); }; export default LaunchPage;