Compare commits
5 commits
next
...
visual-cop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9236d5612b | ||
|
|
079f9404f6 | ||
|
|
488240f32a | ||
|
|
6c157245bb | ||
|
|
753821b01a |
9 changed files with 263 additions and 37 deletions
|
|
@ -282,6 +282,7 @@ function renderElement (world: World, cursor: Vec3, element: BlockElement, doAO:
|
|||
|
||||
const aos: number[] = []
|
||||
const neighborPos = position.plus(new Vec3(...dir))
|
||||
// 10%
|
||||
const baseLight = world.getLight(neighborPos, undefined, undefined, block.name) / 15
|
||||
for (const pos of corners) {
|
||||
let vertex = [
|
||||
|
|
@ -290,7 +291,7 @@ function renderElement (world: World, cursor: Vec3, element: BlockElement, doAO:
|
|||
(pos[2] ? maxz : minz)
|
||||
]
|
||||
|
||||
if (!needTiles) {
|
||||
if (!needTiles) { // 10%
|
||||
vertex = vecadd3(matmul3(localMatrix, vertex), localShift)
|
||||
vertex = vecadd3(matmul3(globalMatrix, vertex), globalShift)
|
||||
vertex = vertex.map(v => v / 16)
|
||||
|
|
@ -411,7 +412,7 @@ export function getSectionGeometry (sx, sy, sz, world: World) {
|
|||
// todo this can be removed here
|
||||
signs: {},
|
||||
// isFull: true,
|
||||
highestBlocks: {},
|
||||
highestBlocks: {}, // todo migrate to map for 2% boost perf
|
||||
hadErrors: false
|
||||
}
|
||||
|
||||
|
|
@ -449,7 +450,7 @@ export function getSectionGeometry (sx, sy, sz, world: World) {
|
|||
}
|
||||
const biome = block.biome.name
|
||||
|
||||
if (world.preflat) {
|
||||
if (world.preflat) { // 10% perf
|
||||
const patchProperties = preflatBlockCalculation(block, world, cursor)
|
||||
if (patchProperties) {
|
||||
block._originalProperties ??= block._properties
|
||||
|
|
@ -505,6 +506,7 @@ export function getSectionGeometry (sx, sy, sz, world: World) {
|
|||
const model = modelVars[useVariant] ?? modelVars[0]
|
||||
if (!model) continue
|
||||
|
||||
// #region 10%
|
||||
let globalMatrix = null as any
|
||||
let globalShift = null as any
|
||||
for (const axis of ['x', 'y', 'z'] as const) {
|
||||
|
|
@ -518,6 +520,7 @@ export function getSectionGeometry (sx, sy, sz, world: World) {
|
|||
globalShift = [8, 8, 8]
|
||||
globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift))
|
||||
}
|
||||
// #endregion
|
||||
|
||||
for (const element of model.elements ?? []) {
|
||||
const ao = model.ao ?? true
|
||||
|
|
@ -527,6 +530,7 @@ export function getSectionGeometry (sx, sy, sz, world: World) {
|
|||
renderElement(world, pos, element, ao, attr, globalMatrix, globalShift, block, biome)
|
||||
})
|
||||
} else {
|
||||
// 60%
|
||||
renderElement(world, cursor, element, ao, attr, globalMatrix, globalShift, block, biome)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,18 @@ import { useEffect, useState } from 'react'
|
|||
import styles from './appStatus.module.css'
|
||||
import Button from './Button'
|
||||
import Screen from './Screen'
|
||||
import LoadingChunks from './LoadingChunks'
|
||||
|
||||
export default ({ status, isError, hideDots = false, lastStatus = '', backAction = undefined as undefined | (() => void), description = '', actionsSlot = null as React.ReactNode | null }) => {
|
||||
export default ({
|
||||
status,
|
||||
isError,
|
||||
hideDots = false,
|
||||
lastStatus = '',
|
||||
backAction = undefined as undefined | (() => void),
|
||||
description = '',
|
||||
actionsSlot = null as React.ReactNode | null,
|
||||
children
|
||||
}) => {
|
||||
const [loadingDots, setLoadingDots] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -52,6 +62,7 @@ export default ({ status, isError, hideDots = false, lastStatus = '', backAction
|
|||
<Button onClick={() => window.location.reload()} label="Reset App (recommended)" />
|
||||
</>
|
||||
)}
|
||||
{children}
|
||||
</Screen>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { proxy, useSnapshot } from 'valtio'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { activeModalStack, activeModalStacks, hideModal, insertActiveModalStack, miscUiState } from '../globalState'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { activeModalStack, activeModalStacks, hideModal, insertActiveModalStack, miscUiState, showModal } from '../globalState'
|
||||
import { resetLocalStorageWorld } from '../browserfs'
|
||||
import { fsState } from '../loadSave'
|
||||
import { guessProblem } from '../errorLoadingScreenHelpers'
|
||||
|
|
@ -14,6 +14,7 @@ import { useIsModalActive } from './utilsApp'
|
|||
import Button from './Button'
|
||||
import { AuthenticatedAccount, updateAuthenticatedAccountData, updateLoadedServerData } from './ServersListProvider'
|
||||
import { showOptionsModal } from './SelectOption'
|
||||
import LoadingChunks from './LoadingChunks'
|
||||
|
||||
const initialState = {
|
||||
status: '',
|
||||
|
|
@ -22,9 +23,12 @@ const initialState = {
|
|||
descriptionHint: '',
|
||||
isError: false,
|
||||
hideDots: false,
|
||||
loadingChunksData: null as null | Record<string, string>,
|
||||
loadingChunksDataPlayerChunk: null as null | { x: number, z: number },
|
||||
isDisplaying: false
|
||||
}
|
||||
export const appStatusState = proxy(initialState)
|
||||
const resetState = () => {
|
||||
export const resetAppStatusState = () => {
|
||||
Object.assign(appStatusState, initialState)
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +37,7 @@ export const lastConnectOptions = {
|
|||
}
|
||||
|
||||
export default () => {
|
||||
const { isError, lastStatus, maybeRecoverable, status, hideDots, descriptionHint } = useSnapshot(appStatusState)
|
||||
const { isError, lastStatus, maybeRecoverable, status, hideDots, descriptionHint, loadingChunksData, loadingChunksDataPlayerChunk } = useSnapshot(appStatusState)
|
||||
const { active: replayActive } = useSnapshot(packetsReplaceSessionState)
|
||||
|
||||
const isOpen = useIsModalActive('app-status')
|
||||
|
|
@ -52,7 +56,7 @@ export default () => {
|
|||
}, [isOpen])
|
||||
|
||||
const reconnect = () => {
|
||||
resetState()
|
||||
resetAppStatusState()
|
||||
window.dispatchEvent(new window.CustomEvent('connect', {
|
||||
detail: lastConnectOptions.value
|
||||
}))
|
||||
|
|
@ -93,7 +97,7 @@ export default () => {
|
|||
lastStatus={lastStatus}
|
||||
description={displayAuthButton ? '' : (isError ? guessProblem(status) : '') || descriptionHint}
|
||||
backAction={maybeRecoverable ? () => {
|
||||
resetState()
|
||||
resetAppStatusState()
|
||||
miscUiState.gameLoaded = false
|
||||
miscUiState.loadedDataVersion = null
|
||||
window.loadedData = undefined
|
||||
|
|
@ -113,10 +117,25 @@ export default () => {
|
|||
{replayActive && <Button label='Download Packets Replay' onClick={downloadPacketsReplay} />}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
>
|
||||
{loadingChunksData && <LoadingChunks regionFiles={Object.keys(loadingChunksData)} stateMap={loadingChunksData} playerChunk={loadingChunksDataPlayerChunk} />}
|
||||
{isOpen && <DisplayingIndicator />}
|
||||
</AppStatus>
|
||||
</DiveTransition>
|
||||
}
|
||||
|
||||
const DisplayingIndicator = () => {
|
||||
useEffect(() => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
appStatusState.isDisplaying = true
|
||||
})
|
||||
})
|
||||
}, [])
|
||||
|
||||
return <div />
|
||||
}
|
||||
|
||||
const PossiblyVpnBypassProxyButton = ({ reconnect }: { reconnect: () => void }) => {
|
||||
const [vpnBypassProxy, setVpnBypassProxy] = useState('')
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const endExitStyle = { opacity: 0, transform: 'translateZ(150px)' }
|
|||
const endStyle = { opacity: 1, transform: 'translateZ(0)' }
|
||||
|
||||
const stateStyles = {
|
||||
entering: startStyle,
|
||||
entering: endStyle,
|
||||
entered: endStyle,
|
||||
exiting: endExitStyle,
|
||||
exited: endExitStyle,
|
||||
|
|
@ -26,6 +26,15 @@ export default ({ children, open }) => {
|
|||
if (!mounted && open) {
|
||||
setMounted(true)
|
||||
}
|
||||
let timeout
|
||||
if (mounted && !open) {
|
||||
timeout = setTimeout(() => {
|
||||
setMounted(false)
|
||||
}, duration)
|
||||
}
|
||||
return () => {
|
||||
if (timeout) clearTimeout(timeout)
|
||||
}
|
||||
}, [open])
|
||||
|
||||
if (!mounted) return null
|
||||
|
|
@ -43,5 +52,4 @@ export default ({ children, open }) => {
|
|||
</div>
|
||||
}}
|
||||
</Transition>
|
||||
|
||||
}
|
||||
|
|
|
|||
12
src/react/LoadingChunks.css
Normal file
12
src/react/LoadingChunks.css
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
@keyframes loading-chunks-loading-animation {
|
||||
/* blink */
|
||||
0% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
43
src/react/LoadingChunks.stories.tsx
Normal file
43
src/react/LoadingChunks.stories.tsx
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import LoadingChunks from './LoadingChunks'
|
||||
|
||||
const meta: Meta<typeof LoadingChunks> = {
|
||||
component: LoadingChunks,
|
||||
render (args) {
|
||||
const [stateMap, setStateMap] = useState(Object.fromEntries(args.regionFiles!.map(x => x.split('.').slice(1, 3).map(Number).map(y => y.toString()).join(',')).map(x => [x, 'loading'])))
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
// pick random and set to done
|
||||
const random = Math.floor(Math.random() * args.regionFiles!.length)
|
||||
const [x, z] = args.regionFiles![random].split('.').slice(1, 3).map(Number)
|
||||
setStateMap(prev => ({ ...prev, [`${x},${z}`]: 'done' }))
|
||||
}, 1000)
|
||||
return () => clearInterval(interval)
|
||||
}, [])
|
||||
|
||||
return <LoadingChunks stateMap={stateMap} {...args} />
|
||||
},
|
||||
}
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof LoadingChunks>
|
||||
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
regionFiles: [
|
||||
'r.-1.-1.mca',
|
||||
'r.-1.0.mca',
|
||||
'r.0.-1.mca',
|
||||
'r.0.0.mca',
|
||||
'r.0.1.mca',
|
||||
],
|
||||
playerChunk: {
|
||||
x: -1,
|
||||
z: 0
|
||||
},
|
||||
displayText: true,
|
||||
},
|
||||
}
|
||||
60
src/react/LoadingChunks.tsx
Normal file
60
src/react/LoadingChunks.tsx
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { useEffect, useRef } from 'react'
|
||||
import './LoadingChunks.css'
|
||||
|
||||
export default ({ regionFiles = [] as string[], stateMap = {} as Record<string, string>, displayText = false, playerChunk = null as null | { x: number, z: number } }) => {
|
||||
// visualize downloading chunks
|
||||
const regionNumbers = regionFiles.map(x => x.split('.').slice(1, 3).map(Number))
|
||||
const minX = Math.min(...regionNumbers.map(([x]) => x))
|
||||
const maxX = Math.max(...regionNumbers.map(([x]) => x))
|
||||
const minZ = Math.min(...regionNumbers.map(([, z]) => z))
|
||||
const maxZ = Math.max(...regionNumbers.map(([, z]) => z))
|
||||
const xChunks = maxX - minX + 1
|
||||
const zChunks = maxZ - minZ + 1
|
||||
|
||||
return <div style={{
|
||||
// maxWidth: '80%',
|
||||
// maxHeight: '80%',
|
||||
// aspectRatio: '1',
|
||||
display: 'grid',
|
||||
gridTemplateColumns: `repeat(${xChunks}, 1fr)`,
|
||||
gridTemplateRows: `repeat(${zChunks}, 1fr)`,
|
||||
gap: 1,
|
||||
width: '110px',
|
||||
height: '110px',
|
||||
}}>
|
||||
{Array.from({ length: xChunks * zChunks }).map((_, i) => {
|
||||
const x = minX + i % xChunks
|
||||
const z = minZ + Math.floor(i / xChunks)
|
||||
const file = `r.${x}.${z}.mca`
|
||||
const state = stateMap[file]
|
||||
if (!regionFiles.includes(file)) return <div key={i} style={{ background: 'gray' }} />
|
||||
return <Chunk key={i} x={x} z={z} state={state} displayText={displayText} currentPlayer={playerChunk?.x === x && playerChunk?.z === z} />
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
|
||||
const Chunk = ({ x, z, state, displayText, currentPlayer }) => {
|
||||
const text = displayText ? `${x},${z}` : undefined
|
||||
|
||||
return <div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
background: state === 'errored' ? 'red' : state === 'loading' ? 'white' : 'limegreen',
|
||||
animation: state === 'loading' ? `loading-chunks-loading-animation 4s infinite cubic-bezier(0.4, 0, 0.2, 1)` : undefined,
|
||||
transition: 'background 1s',
|
||||
color: state === 'loading' ? 'black' : 'white',
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
}}>
|
||||
{/* green dot */}
|
||||
{currentPlayer && <div style={{
|
||||
position: 'absolute',
|
||||
background: 'reed',
|
||||
borderRadius: '50%',
|
||||
width: '5px',
|
||||
height: '5px',
|
||||
zIndex: -1,
|
||||
}} />}
|
||||
{text}</div>
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
import { join } from 'path'
|
||||
import fs from 'fs'
|
||||
import { useEffect } from 'react'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { subscribe, useSnapshot } from 'valtio'
|
||||
import { usedServerPathsV1 } from 'flying-squid/dist/lib/modules/world'
|
||||
import { openURL } from 'prismarine-viewer/viewer/lib/simpleUtils'
|
||||
import { Vec3 } from 'vec3'
|
||||
import { generateSpiralMatrix } from 'flying-squid/dist/utils'
|
||||
import { subscribeKey } from 'valtio/utils'
|
||||
import {
|
||||
activeModalStack,
|
||||
showModal,
|
||||
|
|
@ -23,14 +26,29 @@ import Screen from './Screen'
|
|||
import styles from './PauseScreen.module.css'
|
||||
import { DiscordButton } from './DiscordButton'
|
||||
import { showNotification } from './NotificationProvider'
|
||||
import { appStatusState } from './AppStatusProvider'
|
||||
|
||||
const waitForPotentialRender = async () => {
|
||||
return new Promise<void>(resolve => {
|
||||
requestAnimationFrame(() => requestAnimationFrame(resolve as any))
|
||||
})
|
||||
}
|
||||
|
||||
export const saveToBrowserMemory = async () => {
|
||||
setLoadingScreenStatus('Saving world')
|
||||
try {
|
||||
await new Promise<void>(resolve => {
|
||||
subscribeKey(appStatusState, 'isDisplaying', () => {
|
||||
if (appStatusState.isDisplaying) {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
//@ts-expect-error
|
||||
const { worldFolder } = localServer.options
|
||||
const saveRootPath = await uniqueFileNameFromWorldName(worldFolder.split('/').pop(), `/data/worlds`)
|
||||
await mkdirRecursive(saveRootPath)
|
||||
console.log('made world folder', saveRootPath)
|
||||
const allRootPaths = [...usedServerPathsV1]
|
||||
const allFilesToCopy = [] as string[]
|
||||
for (const dirBase of allRootPaths) {
|
||||
|
|
@ -46,39 +64,87 @@ export const saveToBrowserMemory = async () => {
|
|||
}
|
||||
allFilesToCopy.push(...res.map(x => join(dirBase, x)))
|
||||
}
|
||||
const pathsSplit = allFilesToCopy.reduce((acc, cur, i) => {
|
||||
if (i % 15 === 0) {
|
||||
acc.push([])
|
||||
}
|
||||
acc.at(-1)!.push(cur)
|
||||
return acc
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter
|
||||
}, [] as string[][])
|
||||
console.log('paths collected')
|
||||
const pathsSplitBasic = allFilesToCopy.filter(path => {
|
||||
if (!path.startsWith('region/')) return true
|
||||
const [x, z] = path.split('/').at(-1)!.split('.').slice(1, 3).map(Number)
|
||||
return Math.abs(x) > 50 || Math.abs(z) > 50 // HACK: otherwise it's too big and we can't handle it in visual display
|
||||
})
|
||||
let copied = 0
|
||||
const upProgress = () => {
|
||||
let isRegionFiles = false
|
||||
const upProgress = (totalSize: number) => {
|
||||
copied++
|
||||
const action = fsState.remoteBackend ? 'Downloading & copying' : 'Copying'
|
||||
setLoadingScreenStatus(`${action} files (${copied}/${allFilesToCopy.length})`)
|
||||
let action = fsState.remoteBackend ? 'Downloading & copying' : 'Copying'
|
||||
action += isRegionFiles ? ' region files (world chunks)' : ' basic save files'
|
||||
setLoadingScreenStatus(`${action} files (${copied}/${totalSize})`)
|
||||
}
|
||||
for (const copyPaths of pathsSplit) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await Promise.all(copyPaths.map(async (copyPath) => {
|
||||
const srcPath = join(worldFolder, copyPath)
|
||||
const savePath = join(saveRootPath, copyPath)
|
||||
await mkdirRecursive(savePath)
|
||||
await fs.promises.writeFile(savePath, await fs.promises.readFile(srcPath))
|
||||
upProgress()
|
||||
}))
|
||||
const copyFiles = async (copyPaths: string[][]) => {
|
||||
const totalSIze = copyPaths.flat().length
|
||||
for (const copyFileGroup of copyPaths) {
|
||||
// eslint-disable-next-line no-await-in-loop, @typescript-eslint/no-loop-func
|
||||
await Promise.all(copyFileGroup.map(async (copyPath) => {
|
||||
const srcPath = join(worldFolder, copyPath)
|
||||
const savePath = join(saveRootPath, copyPath)
|
||||
await mkdirRecursive(savePath)
|
||||
await fs.promises.writeFile(savePath, await fs.promises.readFile(srcPath))
|
||||
upProgress(totalSIze)
|
||||
if (isRegionFiles) {
|
||||
const regionFile = copyPath.split('/').at(-1)!
|
||||
appStatusState.loadingChunksData![regionFile] = 'done'
|
||||
}
|
||||
}))
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await waitForPotentialRender()
|
||||
}
|
||||
}
|
||||
// basic save files
|
||||
await copyFiles(splitByCopySize(pathsSplitBasic))
|
||||
setLoadingScreenStatus('Preparing world chunks copying')
|
||||
await waitForPotentialRender()
|
||||
|
||||
// region files
|
||||
isRegionFiles = true
|
||||
copied = 0
|
||||
const regionFiles = allFilesToCopy.filter(x => !pathsSplitBasic.includes(x))
|
||||
const regionFilesNumbers = regionFiles.map(x => x.split('/').at(-1)!.split('.').slice(1, 3).map(Number))
|
||||
const xMin = Math.min(...regionFilesNumbers.flatMap(x => x[0]))
|
||||
const zMin = Math.min(...regionFilesNumbers.flatMap(x => x[1]))
|
||||
const xMax = Math.max(...regionFilesNumbers.flatMap(x => x[0]))
|
||||
const zMax = Math.max(...regionFilesNumbers.flatMap(x => x[1]))
|
||||
const playerPosRegion = bot.entity.position.divide(new Vec3(32 * 16, 32 * 16, 32 * 16)).floored()
|
||||
const maxDistantRegion = Math.max(
|
||||
Math.abs(playerPosRegion.x - xMin),
|
||||
Math.abs(playerPosRegion.z - zMin),
|
||||
Math.abs(playerPosRegion.x - xMax),
|
||||
Math.abs(playerPosRegion.z - zMax)
|
||||
)
|
||||
const spiral = generateSpiralMatrix(maxDistantRegion)
|
||||
const filesWithSpiral = spiral.filter(x => allFilesToCopy.includes(`region/r.${x[0]}.${x[1]}.mca`)).map(x => `region/r.${x[0]}.${x[1]}.mca`)
|
||||
if (filesWithSpiral.length !== regionFiles.length) throw new Error('Something went wrong with region files')
|
||||
|
||||
appStatusState.loadingChunksData = Object.fromEntries(regionFiles.map(x => [x.split('/').at(-1)!, 'loading']))
|
||||
appStatusState.loadingChunksDataPlayerChunk = { x: playerPosRegion.x, z: playerPosRegion.z }
|
||||
await copyFiles(splitByCopySize(filesWithSpiral, 10))
|
||||
|
||||
return saveRootPath
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
void showOptionsModal(`Error while saving the world: ${err.message}`, [])
|
||||
} finally {
|
||||
setLoadingScreenStatus(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
const splitByCopySize = (files: string[], copySize = 15) => {
|
||||
return files.reduce<string[][]>((acc, cur, i) => {
|
||||
if (i % copySize === 0) {
|
||||
acc.push([])
|
||||
}
|
||||
acc.at(-1)!.push(cur)
|
||||
return acc
|
||||
}, [])
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const qsParams = new URLSearchParams(window.location.search)
|
||||
const lockConnect = qsParams?.get('lockConnect') === 'true'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { hideModal, isGameActive, miscUiState, showModal } from './globalState'
|
||||
import { activeModalStack, hideModal, isGameActive, miscUiState, showModal } from './globalState'
|
||||
import { options } from './optionsStorage'
|
||||
import { appStatusState } from './react/AppStatusProvider'
|
||||
import { appStatusState, resetAppStatusState } from './react/AppStatusProvider'
|
||||
import { notificationProxy, showNotification } from './react/NotificationProvider'
|
||||
|
||||
export const goFullscreen = async (doToggle = false) => {
|
||||
|
|
@ -139,7 +139,10 @@ export const setLoadingScreenStatus = function (status: string | undefined | nul
|
|||
return
|
||||
}
|
||||
|
||||
// todo update in component instead
|
||||
if (!activeModalStack.some(x => x.reactType === 'app-status')) {
|
||||
// just showing app status
|
||||
resetAppStatusState()
|
||||
}
|
||||
showModal({ reactType: 'app-status' })
|
||||
if (appStatusState.isError) {
|
||||
miscUiState.gameLoaded = false
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue