diff --git a/src/appStatus.ts b/src/appStatus.ts index 4c82973a..d3bfc461 100644 --- a/src/appStatus.ts +++ b/src/appStatus.ts @@ -33,3 +33,4 @@ export const setLoadingScreenStatus = function (status: string | undefined | nul appStatusState.status = status appStatusState.minecraftJsonMessage = minecraftJsonMessage ?? null } +globalThis.setLoadingScreenStatus = setLoadingScreenStatus diff --git a/src/index.ts b/src/index.ts index 6426f219..bac2593e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -732,12 +732,8 @@ export async function connect (connectOptions: ConnectOptions) { // don't use spawn event, player can be dead bot.once(spawnEarlier ? 'forcedMove' : 'health', async () => { if (resourcePackState.isServerInstalling) { - setLoadingScreenStatus('Downloading resource pack') await new Promise(resolve => { subscribe(resourcePackState, () => { - if (!resourcePackState.isServerDownloading) { - setLoadingScreenStatus('Installing resource pack') - } if (!resourcePackState.isServerInstalling) { resolve() } diff --git a/src/react/AppStatusProvider.tsx b/src/react/AppStatusProvider.tsx index 09fcb40a..dfb1b9bf 100644 --- a/src/react/AppStatusProvider.tsx +++ b/src/react/AppStatusProvider.tsx @@ -1,5 +1,5 @@ import { proxy, useSnapshot } from 'valtio' -import { useEffect, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import { activeModalStack, activeModalStacks, hideModal, insertActiveModalStack, miscUiState } from '../globalState' import { guessProblem } from '../errorLoadingScreenHelpers' import type { ConnectOptions } from '../connect' @@ -53,11 +53,19 @@ export const reconnectReload = () => { } export default () => { - const { isError, lastStatus, maybeRecoverable, status, hideDots, descriptionHint, loadingChunksData, loadingChunksDataPlayerChunk, minecraftJsonMessage, showReconnect } = useSnapshot(appStatusState) + const lastState = useRef(JSON.parse(JSON.stringify(appStatusState))) + const currentState = useSnapshot(appStatusState) const { active: replayActive } = useSnapshot(packetsReplaceSessionState) const isOpen = useIsModalActive('app-status') + if (isOpen) { + lastState.current = JSON.parse(JSON.stringify(currentState)) + } + + const usingState = isOpen ? currentState : lastState.current + const { isError, lastStatus, maybeRecoverable, status, hideDots, descriptionHint, loadingChunksData, loadingChunksDataPlayerChunk, minecraftJsonMessage, showReconnect } = usingState + useDidUpdateEffect(() => { // todo play effect only when world successfully loaded if (!isOpen) { @@ -108,7 +116,7 @@ export default () => { return => { try { resourcePackState.isServerInstalling = true resourcePackState.isServerDownloading = true + if (!miscUiState.gameLoaded) setLoadingScreenStatus('Downloading resource pack') console.log('Downloading server resource pack', url) console.time('downloadServerResourcePack') const response = await fetch(url).catch((err) => { @@ -390,8 +391,31 @@ const downloadAndUseResourcePack = async (url: string): Promise => { }) console.timeEnd('downloadServerResourcePack') if (!response) return + if (!miscUiState.gameLoaded) setLoadingScreenStatus('Installing resource pack') + + const contentLength = response.headers.get('Content-Length') + const total = contentLength ? parseInt(contentLength, 10) : 0 + let loaded = 0 + + const reader = response.body!.getReader() + const chunks: Uint8Array[] = [] + + // eslint-disable-next-line no-constant-condition + while (true) { + const { done, value } = await reader.read() + if (done) break + + chunks.push(value) + loaded += value.length + + if (total) { + const progress = Math.round((loaded / total) * 100) + if (!miscUiState.gameLoaded) setLoadingScreenStatus(`Downloading resource pack: ${progress}%`) + } + } + resourcePackState.isServerDownloading = false - const resourcePackData = await response.arrayBuffer() + const resourcePackData = await new Blob(chunks).arrayBuffer() showNotification('Installing resource pack...') await installResourcepackPack(resourcePackData, undefined, undefined, true).catch((err) => { console.error(err)