import React from 'react' // Major Components import TopBar from './components/TopBar' import ServerLaunchSection from './components/ServerLaunchSection' import MainProgressBar from './components/common/MainProgressBar' import Options, { GrasscutterElevation } from './components/menu/Options' import MiniDialog from './components/MiniDialog' import DownloadList from './components/common/DownloadList' import Downloads from './components/menu/Downloads' import NewsSection from './components/news/NewsSection' import Game from './components/menu/Game' import RightBar from './components/RightBar' import { ExtrasMenu } from './components/menu/ExtrasMenu' import Notification from './components/common/Notification' import GamePathNotify from './components/menu/GamePathNotify' import { getConfig, getConfigOption, setConfigOption } from '../utils/configuration' import { invoke } from '@tauri-apps/api' import { getVersion } from '@tauri-apps/api/app' import { listen } from '@tauri-apps/api/event' import { dataDir } from '@tauri-apps/api/path' import { appWindow } from '@tauri-apps/api/window' import { unpatchGame } from '../utils/rsa' import DownloadHandler from '../utils/download' // Graphics import cogBtn from '../resources/icons/cog.svg' import downBtn from '../resources/icons/download.svg' import wrenchBtn from '../resources/icons/wrench.svg' interface IProps { downloadHandler: DownloadHandler } interface IState { isDownloading: boolean optionsOpen: boolean miniDownloadsOpen: boolean downloadsOpen: boolean gameDownloadsOpen: boolean extrasOpen: boolean migotoSet: boolean playGame: (exe?: string, proc_name?: string) => void notification: React.ReactElement | null isGamePathSet: boolean game_install_path: string } export class Main extends React.Component { constructor(props: IProps) { super(props) this.state = { isDownloading: false, optionsOpen: false, miniDownloadsOpen: false, downloadsOpen: false, gameDownloadsOpen: false, extrasOpen: false, migotoSet: false, playGame: () => { alert('Error launching game') }, notification: null, isGamePathSet: true, game_install_path: '', } listen('lang_error', (payload) => { console.log(payload) }) listen('jar_extracted', ({ payload }: { payload: string }) => { setConfigOption('grasscutter_path', payload) }) listen('migoto_extracted', ({ payload }: { payload: string }) => { setConfigOption('migoto_path', payload) }) // Emitted for rsa replacing-purposes listen('game_closed', async () => { const wasPatched = await getConfigOption('patch_rsa') if (wasPatched) { const unpatched = await unpatchGame() if (unpatched) { alert(`Could not unpatch game! (Delete version.dll in your game folder)`) } } }) listen('migoto_set', async () => { this.setState({ migotoSet: !!(await getConfigOption('migoto_path')), }) window.location.reload() }) // Emitted for automatic processes listen('grasscutter_closed', async () => { const autoService = await getConfigOption('auto_mongodb') const config = await getConfig() if (autoService) { await invoke('stop_service', { service: 'MongoDB' }) } if ((await invoke('get_platform')) === 'linux') { switch (config.grasscutter_elevation) { case GrasscutterElevation.None: break case GrasscutterElevation.Capability: await invoke('jvm_remove_cap', { javaPath: config.java_path, }) break default: console.error('Invalid grasscutter_elevation') break } } }) let min = false // periodically check if we need to min/max based on whether the game is open setInterval(async () => { const gameOpen = await invoke('is_game_running') if (gameOpen && !min) { appWindow.minimize() min = true } else if (!gameOpen && min) { appWindow.unminimize() min = false } }, 1000) this.openExtrasMenu = this.openExtrasMenu.bind(this) } async componentDidMount() { const game_path = await getConfigOption('game_install_path') const cert_generated = await getConfigOption('cert_generated') this.setState({ game_install_path: game_path, }) this.setState({ migotoSet: !!(await getConfigOption('migoto_path')), }) if (!cert_generated) { // Generate the certificate await invoke('generate_ca_files', { path: (await dataDir()) + 'cultivation', }) await setConfigOption('cert_generated', true) } // Ensure old configs are updated to use RSA const updatedConfig = await getConfigOption('patch_rsa') await setConfigOption('patch_rsa', updatedConfig) // Get latest version and compare to this version const latestVersion: { tag_name: string link: string } = await invoke('get_latest_release') const tagName = latestVersion?.tag_name.replace(/[^\d.]/g, '') // Check if tagName is different than current version if (tagName && tagName !== (await getVersion())) { // Display notification of new release this.setState({ notification: ( <> Cultivation{' '} invoke('open_in_browser', { url: latestVersion.link })}> {latestVersion?.tag_name} {' '} is now available! ), }) setTimeout(() => { this.setState({ notification: null, }) }, 6000) } // Period check to only show progress bar when downloading files setInterval(() => { this.setState({ isDownloading: this.props.downloadHandler.getDownloads().filter((d) => d.status !== 'finished')?.length > 0, }) }, 1000) } async openExtrasMenu(playGame: () => void) { this.setState({ extrasOpen: true, playGame, }) } async componentDidUpdate(prevProps: Readonly, prevState: Readonly) { const game_path = await getConfigOption('game_install_path') // Check if game exists at set location const game_exists: boolean = (await invoke('dir_exists', { path: game_path, })) as boolean // Set no game path so the user understands it doesn't exist there if (!game_exists) { setConfigOption('game_install_path', '') } //if previous state is not equal the current one - update the game_install_path to be the current game path if (prevState.game_install_path != game_path) { this.setState({ game_install_path: game_path, }) this.state.game_install_path === '' ? this.setState({ isGamePathSet: false }) : this.setState({ isGamePathSet: true }) } } render() { return ( <>
this.setState({ optionsOpen: !this.state.optionsOpen })} className="TopButton" > settings
this.setState({ downloadsOpen: !this.state.downloadsOpen })} > downloads
{this.state.migotoSet && (
{ // Create and dispatch a custom "openMods" event const event = new CustomEvent('changePage', { detail: 'modding' }) window.dispatchEvent(event) }} className="TopButton" > mods
)} {/*
this.setState({ gameDownloadsOpen: !this.state.gameDownloadsOpen })}> game
*/}
{this.state.notification} {this.state.isGamePathSet ? <> : } { // Extras section this.state.extrasOpen && ( this.setState({ extrasOpen: false })} playGame={this.state.playGame}> Yo ) } { // Mini downloads section this.state.miniDownloadsOpen ? (
{ this.setState({ miniDownloadsOpen: false }) }} >
) : null } { // Download menu this.state.downloadsOpen ? ( this.setState({ downloadsOpen: false })} /> ) : null } { // Options menu this.state.optionsOpen ? ( this.setState({ optionsOpen: !this.state.optionsOpen })} /> ) : null } { // Game downloads menu this.state.gameDownloadsOpen ? ( this.setState({ gameDownloadsOpen: false })} /> ) : null }
this.setState({ miniDownloadsOpen: !this.state.miniDownloadsOpen })} > {this.state.isDownloading ? : null}
) } }