feat: texturepack install via qs
fix: fix slow texturepack install fix: fix compatibility with most texturepack block format todo: plan to do support for huge textures soon (i hope)
This commit is contained in:
parent
88ec993d27
commit
b6d236d430
3 changed files with 56 additions and 35 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import { openWorldZip } from './browserfs'
|
||||
import { installTexturePack } from './texturePack'
|
||||
import { setLoadingScreenStatus } from './utils'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
|
||||
|
|
@ -6,21 +7,21 @@ const getConstantFilesize = (bytes: number) => {
|
|||
return prettyBytes(bytes, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
||||
}
|
||||
|
||||
export const hasMapUrl = () => {
|
||||
const qs = new URLSearchParams(window.location.search)
|
||||
const mapUrl = qs.get('map')
|
||||
return !!mapUrl
|
||||
}
|
||||
|
||||
export default async () => {
|
||||
const qs = new URLSearchParams(window.location.search)
|
||||
const mapUrl = qs.get('map')
|
||||
if (!mapUrl) return
|
||||
let mapUrl = qs.get('map')
|
||||
const texturepack = qs.get('texturepack')
|
||||
// fixme
|
||||
if (texturepack) mapUrl = texturepack
|
||||
if (!mapUrl) return false
|
||||
|
||||
const menu = document.getElementById('play-screen')
|
||||
menu.style = 'display: none;'
|
||||
if (!texturepack) {
|
||||
const menu = document.getElementById('play-screen')
|
||||
menu.style = 'display: none;'
|
||||
}
|
||||
const name = mapUrl.slice(mapUrl.lastIndexOf('/') + 1).slice(-25)
|
||||
setLoadingScreenStatus(`Downloading world ${name}...`)
|
||||
const downloadThing = texturepack ? 'texturepack' : 'world'
|
||||
setLoadingScreenStatus(`Downloading ${downloadThing} ${name}...`)
|
||||
|
||||
const response = await fetch(mapUrl)
|
||||
const contentType = response.headers.get('Content-Type')
|
||||
|
|
@ -28,7 +29,7 @@ export default async () => {
|
|||
alert('Invalid map file')
|
||||
}
|
||||
const contentLength = +response.headers.get('Content-Length')
|
||||
setLoadingScreenStatus(`Downloading world ${name}: have to download ${getConstantFilesize(contentLength)}...`)
|
||||
setLoadingScreenStatus(`Downloading ${downloadThing} ${name}: have to download ${getConstantFilesize(contentLength)}...`)
|
||||
|
||||
let downloadedBytes = 0
|
||||
const buffer = await new Response(
|
||||
|
|
@ -51,7 +52,7 @@ export default async () => {
|
|||
|
||||
// Update your progress bar or display the progress value as needed
|
||||
if (contentLength) {
|
||||
setLoadingScreenStatus(`Download Progress: ${Math.floor(progress)}% (${getConstantFilesize(downloadedBytes)} / ${getConstantFilesize(contentLength)}))`, false, true)
|
||||
setLoadingScreenStatus(`Download ${downloadThing} progress: ${Math.floor(progress)}% (${getConstantFilesize(downloadedBytes)} / ${getConstantFilesize(contentLength)}))`, false, true)
|
||||
}
|
||||
|
||||
// Pass the received data to the controller
|
||||
|
|
@ -60,5 +61,9 @@ export default async () => {
|
|||
},
|
||||
})
|
||||
).arrayBuffer()
|
||||
await openWorldZip(buffer)
|
||||
if (texturepack) {
|
||||
await installTexturePack(buffer)
|
||||
} else {
|
||||
await openWorldZip(buffer)
|
||||
}
|
||||
}
|
||||
16
src/index.ts
16
src/index.ts
|
|
@ -31,7 +31,7 @@ import './controls'
|
|||
import './dragndrop'
|
||||
import './browserfs'
|
||||
import './eruda'
|
||||
import downloadAndOpenWorld, { hasMapUrl } from './downloadAndOpenWorld'
|
||||
import downloadAndOpenFile from './downloadAndOpenFile'
|
||||
|
||||
import net from 'net'
|
||||
import Stats from 'stats.js'
|
||||
|
|
@ -63,8 +63,7 @@ import {
|
|||
isCypress,
|
||||
loadScript,
|
||||
toMajorVersion,
|
||||
setLoadingScreenStatus,
|
||||
resolveTimeout
|
||||
setLoadingScreenStatus
|
||||
} from './utils'
|
||||
|
||||
import {
|
||||
|
|
@ -756,9 +755,9 @@ window.addEventListener('keydown', (e) => {
|
|||
addPanoramaCubeMap()
|
||||
showModal(document.getElementById('title-screen'))
|
||||
main()
|
||||
if (hasMapUrl()) {
|
||||
downloadAndOpenWorld()
|
||||
} else {
|
||||
downloadAndOpenFile().then((downloadAction) => {
|
||||
if (downloadAction !== false) return
|
||||
|
||||
window.addEventListener('hud-ready', (e) => {
|
||||
// try to connect to peer
|
||||
const qs = new URLSearchParams(window.location.search)
|
||||
|
|
@ -776,4 +775,7 @@ if (hasMapUrl()) {
|
|||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}, (err) => {
|
||||
console.error(err)
|
||||
alert(`Failed to download file: ${err}`)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import type { Viewer } from 'prismarine-viewer/viewer/lib/viewer'
|
|||
import { removeFileRecursiveAsync } from './browserfs'
|
||||
import { miscUiState } from './globalState'
|
||||
import { subscribeKey } from 'valtio/utils'
|
||||
import { showNotification } from './menus/notification'
|
||||
|
||||
function nextPowerOfTwo(n) {
|
||||
if (n === 0) return 1
|
||||
|
|
@ -63,7 +64,7 @@ export const installTexturePack = async (file: File | ArrayBuffer) => {
|
|||
await uninstallTexturePack()
|
||||
} catch (err) {
|
||||
}
|
||||
const status = 'Installing resource pack: copying all files';
|
||||
const status = 'Installing resource pack: copying all files'
|
||||
setLoadingScreenStatus(status)
|
||||
// extract the zip and write to fs every file in it
|
||||
const zip = new JSZip()
|
||||
|
|
@ -71,21 +72,28 @@ export const installTexturePack = async (file: File | ArrayBuffer) => {
|
|||
if (!zipFile.file('pack.mcmeta')) throw new Error('Not a resource pack: missing pack.mcmeta')
|
||||
await mkdirRecursive(texturePackBasePath)
|
||||
|
||||
const allFilesArr = Object.entries(zipFile.files);
|
||||
let i = 0
|
||||
for (const [path, file] of allFilesArr) {
|
||||
const writePath = join(texturePackBasePath, path);
|
||||
if (path.endsWith('/')) continue
|
||||
const allFilesArr = Object.entries(zipFile.files)
|
||||
let done = 0
|
||||
const upStatus = () => {
|
||||
setLoadingScreenStatus(`${status} ${Math.round(++done / allFilesArr.length * 100)}%`)
|
||||
}
|
||||
await Promise.all(allFilesArr.map(async ([path, file]) => {
|
||||
const writePath = join(texturePackBasePath, path)
|
||||
if (path.endsWith('/')) return
|
||||
await mkdirRecursive(dirname(writePath))
|
||||
await fs.promises.writeFile(writePath, Buffer.from(await file.async('arraybuffer')))
|
||||
setLoadingScreenStatus(`${status} ${Math.round(++i / allFilesArr.length * 100)}%`)
|
||||
}
|
||||
done++
|
||||
upStatus()
|
||||
}))
|
||||
await fs.promises.writeFile(join(texturePackBasePath, 'name.txt'), file['name'] ?? '??', 'utf8')
|
||||
|
||||
if (viewer?.world.active) {
|
||||
await genTexturePackTextures(viewer.version)
|
||||
}
|
||||
setLoadingScreenStatus(undefined)
|
||||
showNotification({
|
||||
message: 'Texturepack installed!',
|
||||
})
|
||||
}
|
||||
|
||||
const existsAsync = async (path) => {
|
||||
|
|
@ -144,7 +152,7 @@ const setCustomTexturePackData = (blockTextures, blockStates) => {
|
|||
|
||||
const getSizeFromImage = async (filePath: string) => {
|
||||
const probeImg = new Image()
|
||||
const file = await fs.promises.readFile(filePath, 'base64');
|
||||
const file = await fs.promises.readFile(filePath, 'base64')
|
||||
probeImg.src = `data:image/png;base64,${file}`
|
||||
await new Promise((resolve, reject) => {
|
||||
probeImg.onload = resolve
|
||||
|
|
@ -155,11 +163,17 @@ const getSizeFromImage = async (filePath: string) => {
|
|||
|
||||
export const genTexturePackTextures = async (version: string) => {
|
||||
setCustomTexturePackData(undefined, undefined)
|
||||
const blocksBasePath = '/userData/resourcePacks/default/assets/minecraft/textures/blocks';
|
||||
let blocksBasePath = '/userData/resourcePacks/default/assets/minecraft/textures/block'
|
||||
// todo not clear why this is needed
|
||||
const blocksBasePathAlt = '/userData/resourcePacks/default/assets/minecraft/textures/blocks'
|
||||
const blocksGenereatedPath = `/userData/resourcePacks/default/${version}.png`
|
||||
const genereatedPathData = `/userData/resourcePacks/default/${version}.json`
|
||||
if (await existsAsync(blocksBasePath) === false) {
|
||||
return
|
||||
if (await existsAsync(blocksBasePathAlt) === false) {
|
||||
return
|
||||
} else {
|
||||
blocksBasePath = blocksBasePathAlt
|
||||
}
|
||||
}
|
||||
if (await existsAsync(blocksGenereatedPath) === true) {
|
||||
applyTexturePackData(version, JSON.parse(await fs.promises.readFile(genereatedPathData, 'utf8')), await fs.promises.readFile(blocksGenereatedPath, 'utf8'))
|
||||
|
|
@ -208,7 +222,7 @@ export const genTexturePackTextures = async (version: string) => {
|
|||
await new Promise<void>(resolve => {
|
||||
_imgCustom.onload = () => {
|
||||
imgCustom = _imgCustom
|
||||
resolve();
|
||||
resolve()
|
||||
}
|
||||
_imgCustom.onerror = () => {
|
||||
console.log('Skipping issued texture', fileName)
|
||||
|
|
@ -227,10 +241,10 @@ export const genTexturePackTextures = async (version: string) => {
|
|||
ctx.drawImage(img, xOrig, yOrig, originalTileSize, originalTileSize, x, y, tileSize, tileSize)
|
||||
}
|
||||
}
|
||||
const blockDataUrl = canvas.toDataURL('image/png');
|
||||
const blockDataUrl = canvas.toDataURL('image/png')
|
||||
const newData: TextureResolvedData = {
|
||||
blockSize: tileSize,
|
||||
};
|
||||
}
|
||||
await fs.promises.writeFile(genereatedPathData, JSON.stringify(newData), 'utf8')
|
||||
await fs.promises.writeFile(blocksGenereatedPath, blockDataUrl, 'utf8')
|
||||
await applyTexturePackData(version, newData, blockDataUrl)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue