import { proxy, useSnapshot } from 'valtio' import { useEffect, useState } from 'react' import { activeModalStack, activeModalStacks, hideModal, insertActiveModalStack, miscUiState } from '../globalState' import { guessProblem } from '../errorLoadingScreenHelpers' import type { ConnectOptions } from '../connect' import { downloadPacketsReplay, packetsReplaceSessionState, replayLogger } from '../packetsReplay' import { getProxyDetails } from '../microsoftAuthflow' import AppStatus from './AppStatus' import DiveTransition from './DiveTransition' import { useDidUpdateEffect } from './utils' import { useIsModalActive } from './utilsApp' import Button from './Button' import { updateAuthenticatedAccountData, updateLoadedServerData, AuthenticatedAccount } from './serversStorage' import { showOptionsModal } from './SelectOption' import LoadingChunks from './LoadingChunks' import MessageFormattedString from './MessageFormattedString' const initialState = { status: '', lastStatus: '', maybeRecoverable: true, descriptionHint: '', isError: false, hideDots: false, loadingChunksData: null as null | Record, loadingChunksDataPlayerChunk: null as null | { x: number, z: number }, isDisplaying: false, minecraftJsonMessage: null as null | Record, showReconnect: false } export const appStatusState = proxy(initialState) export const resetAppStatusState = () => { Object.assign(appStatusState, initialState) } export const lastConnectOptions = { value: null as ConnectOptions | null } const saveReconnectOptions = (options: ConnectOptions) => { sessionStorage.setItem('reconnectOptions', JSON.stringify({ value: options, timestamp: Date.now() })) } export const reconnectReload = () => { if (lastConnectOptions.value) { saveReconnectOptions(lastConnectOptions.value) window.location.reload() } } export default () => { const { isError, lastStatus, maybeRecoverable, status, hideDots, descriptionHint, loadingChunksData, loadingChunksDataPlayerChunk, minecraftJsonMessage, showReconnect } = useSnapshot(appStatusState) const { active: replayActive } = useSnapshot(packetsReplaceSessionState) const isOpen = useIsModalActive('app-status') useDidUpdateEffect(() => { // todo play effect only when world successfully loaded if (!isOpen) { const divingElem: HTMLElement = document.querySelector('#viewer-canvas')! divingElem.style.animationName = 'dive-animation' divingElem.parentElement!.style.perspective = '1200px' divingElem.onanimationend = () => { divingElem.parentElement!.style.perspective = '' divingElem.onanimationend = null } } }, [isOpen]) const reconnect = () => { resetAppStatusState() window.dispatchEvent(new window.CustomEvent('connect', { detail: lastConnectOptions.value })) } useEffect(() => { const controller = new AbortController() window.addEventListener('keyup', (e) => { if (activeModalStack.at(-1)?.reactType !== 'app-status') return if (e.code !== 'KeyR' || !lastConnectOptions.value) return reconnect() }, { signal: controller.signal }) return () => controller.abort() }, []) const displayAuthButton = status.includes('This server appears to be an online server and you are providing no authentication.') const displayVpnButton = status.includes('VPN') || status.includes('Proxy') const authReconnectAction = async () => { let accounts = [] as AuthenticatedAccount[] updateAuthenticatedAccountData(oldAccounts => { accounts = oldAccounts return oldAccounts }) const account = await showOptionsModal('Choose account to connect with', [...accounts.map(account => account.username), 'Use other account']) if (!account) return lastConnectOptions.value!.authenticatedAccount = accounts.find(acc => acc.username === account) || true reconnect() } return { displayAuthButton ? '' : (isError ? guessProblem(status) : '') || descriptionHint }{ minecraftJsonMessage && }} backAction={maybeRecoverable ? () => { resetAppStatusState() miscUiState.gameLoaded = false miscUiState.loadedDataVersion = null window.loadedData = undefined if (activeModalStacks['main-menu']) { insertActiveModalStack('main-menu') if (activeModalStack.at(-1)?.reactType === 'app-status') { hideModal(undefined, undefined, { force: true }) // workaround: hide loader that was shown on world loading } } else { hideModal(undefined, undefined, { force: true }) } } : undefined} actionsSlot={ <> {displayAuthButton &&