Compare commits

...
Sign in to create a new pull request.

3 commits

Author SHA1 Message Date
Vitaly Turovsky
5e4bde18a7 Merge branch 'next' into world-data-worker 2024-04-17 07:43:22 +03:00
Vitaly Turovsky
4cf578b774 test final impl 2024-03-29 14:09:10 +03:00
Vitaly Turovsky
7a88b35ae2 keep testing and half tested 2024-03-28 01:04:12 +03:00
6 changed files with 221 additions and 47 deletions

62
buildWorkers.mjs Normal file
View file

@ -0,0 +1,62 @@
// main worker file intended for computing world geometry is built using prismarine-viewer/buildWorker.mjs
import { build, context } from 'esbuild'
import fs from 'fs'
import { sharedPlugins } from './scripts/esbuildPlugins.mjs'
const watch = process.argv.includes('-w')
const result = await (watch ? context : build)({
bundle: true,
platform: 'browser',
entryPoints: [/* 'prismarine-viewer/examples/webglRendererWorker.ts', */'src/worldSaveWorker.ts'],
outdir: 'prismarine-viewer/public/',
sourcemap: watch ? 'inline' : 'external',
minify: !watch,
treeShaking: true,
logLevel: 'info',
alias: {
'three': './node_modules/three/src/Three.js',
events: 'events', // make explicit
buffer: 'buffer',
'fs': 'browserfs/dist/shims/fs.js',
http: 'http-browserify',
perf_hooks: './src/perf_hooks_replacement.js',
crypto: './src/crypto.js',
stream: 'stream-browserify',
net: 'net-browserify',
assert: 'assert',
dns: './src/dns.js'
},
inject: [
'./src/shims.js'
],
plugins: [
{
name: 'writeOutput',
setup (build) {
build.onEnd(({ outputFiles }) => {
for (const file of outputFiles) {
for (const dir of ['prismarine-viewer/public', 'dist']) {
const baseName = file.path.split('/').pop()
fs.writeFileSync(`${dir}/${baseName}`, file.contents)
}
}
})
}
},
...sharedPlugins
],
loader: {
'.vert': 'text',
'.frag': 'text'
},
mainFields: [
'browser', 'module', 'main'
],
keepNames: true,
write: false,
})
if (watch) {
await result.watch()
}

View file

@ -18,7 +18,7 @@ const watchExternal = [
] ]
/** @type {import('esbuild').Plugin[]} */ /** @type {import('esbuild').Plugin[]} */
const plugins = [ const sharedPlugins = [
{ {
name: 'strict-aliases', name: 'strict-aliases',
setup (build) { setup (build) {
@ -65,6 +65,53 @@ const plugins = [
}) })
} }
}, },
{
name: 'fix-dynamic-require',
setup (build) {
build.onResolve({
filter: /1\.14\/chunk/,
}, async ({ resolveDir, path }) => {
if (!resolveDir.includes('prismarine-provider-anvil')) return
return {
namespace: 'fix-dynamic-require',
path,
pluginData: {
resolvedPath: `${join(resolveDir, path)}.js`,
resolveDir
},
}
})
build.onLoad({
filter: /.+/,
namespace: 'fix-dynamic-require',
}, async ({ pluginData: { resolvedPath, resolveDir } }) => {
const resolvedFile = await fs.promises.readFile(resolvedPath, 'utf8')
return {
contents: resolvedFile.replace("require(`prismarine-chunk/src/pc/common/BitArray${noSpan ? 'NoSpan' : ''}`)", "noSpan ? require(`prismarine-chunk/src/pc/common/BitArray`) : require(`prismarine-chunk/src/pc/common/BitArrayNoSpan`)"),
resolveDir,
loader: 'js',
}
})
}
},
polyfillNode({
polyfills: {
fs: false,
dns: false,
crypto: false,
events: false,
http: false,
stream: false,
buffer: false,
perf_hooks: false,
net: false,
assert: false,
},
})
]
/** @type {import('esbuild').Plugin[]} */
const plugins = [
{ {
name: 'data-assets', name: 'data-assets',
setup (build) { setup (build) {
@ -256,35 +303,6 @@ const plugins = [
}) })
} }
}, },
{
name: 'fix-dynamic-require',
setup (build) {
build.onResolve({
filter: /1\.14\/chunk/,
}, async ({ resolveDir, path }) => {
if (!resolveDir.includes('prismarine-provider-anvil')) return
return {
namespace: 'fix-dynamic-require',
path,
pluginData: {
resolvedPath: `${join(resolveDir, path)}.js`,
resolveDir
},
}
})
build.onLoad({
filter: /.+/,
namespace: 'fix-dynamic-require',
}, async ({ pluginData: { resolvedPath, resolveDir } }) => {
const resolvedFile = await fs.promises.readFile(resolvedPath, 'utf8')
return {
contents: resolvedFile.replace("require(`prismarine-chunk/src/pc/common/BitArray${noSpan ? 'NoSpan' : ''}`)", "noSpan ? require(`prismarine-chunk/src/pc/common/BitArray`) : require(`prismarine-chunk/src/pc/common/BitArrayNoSpan`)"),
resolveDir,
loader: 'js',
}
})
}
},
{ {
name: 'react-displayname', name: 'react-displayname',
setup (build) { setup (build) {
@ -310,20 +328,7 @@ const plugins = [
}) })
} }
}, },
polyfillNode({ ...sharedPlugins
polyfills: {
fs: false,
dns: false,
crypto: false,
events: false,
http: false,
stream: false,
buffer: false,
perf_hooks: false,
net: false,
assert: false,
},
})
] ]
export { plugins, connectedClients as clients } export { plugins, connectedClients as clients, sharedPlugins }

View file

@ -9,5 +9,38 @@ export default () => {
chatInputValueGlobal.value = '/warp ' chatInputValueGlobal.value = '/warp '
showModal({ reactType: 'chat' }) showModal({ reactType: 'chat' })
}) })
}) });
(localServer as any).loadChunksOptimized = (chunks) => {
const workersNum = 5
const workers = [] as Worker[]
for (let i = 0; i < workersNum; i++) {
const worker = new Worker('./worldSaveWorker.js')
workers.push(worker)
}
console.time('chunks-main')
for (const [i, worker] of workers.entries()) {
worker.postMessage({
type: 'readChunks',
chunks: chunks.slice(i * chunks.length / workersNum, (i + 1) * chunks.length / workersNum),
folder: localServer!.options.worldFolder + '/region'
})
}
let finishedWorkers = 0
for (const worker of workers) {
// eslint-disable-next-line @typescript-eslint/no-loop-func
worker.onmessage = (msg) => {
if (msg.data.type === 'done') {
finishedWorkers++
if (finishedWorkers === workersNum) {
console.timeEnd('chunks-main')
}
}
}
}
}
} }

View file

@ -63,7 +63,6 @@ export default ({ indicators, effects }: {indicators: typeof defaultIndicatorsSt
}, [effects]) }, [effects])
useEffect(() => { useEffect(() => {
// todo use more precise timer for each effect
const interval = setInterval(() => { const interval = setInterval(() => {
for (const [index, effect] of effectsRef.current.entries()) { for (const [index, effect] of effectsRef.current.entries()) {
if (effect.time === 0) { if (effect.time === 0) {

3
src/workerWorkaround.ts Normal file
View file

@ -0,0 +1,3 @@
global = globalThis
globalThis.window = globalThis
window.mcData = {}

72
src/worldSaveWorker.ts Normal file
View file

@ -0,0 +1,72 @@
import './workerWorkaround'
import fs from 'fs'
import './fs2'
import { Anvil } from 'prismarine-provider-anvil'
import WorldLoader from 'prismarine-world'
import * as browserfs from 'browserfs'
import { generateSpiralMatrix } from 'flying-squid/dist/utils'
import '../dist/mc-data/1.14'
import { oneOf } from '@zardoy/utils'
console.log('install')
browserfs.install(window)
window.fs = fs
onmessage = (msg) => {
globalThis.readSkylight = false
if (msg.data.type === 'readChunks') {
browserfs.configure({
fs: 'MountableFileSystem',
options: {
'/data': { fs: 'IndexedDB' },
},
}, async () => {
const version = '1.14.4'
const AnvilLoader = Anvil(version)
const World = WorldLoader(version)
// const folder = '/data/worlds/Greenfield v0.5.3-3/region'
const { folder } = msg.data
const world = new World(() => {
throw new Error('Not implemented')
}, new AnvilLoader(folder))
// const chunks = generateSpiralMatrix(20)
const { chunks } = msg.data
// const spawn = {
// x: 113,
// y: 64,
// }
console.log('starting...')
console.time('columns')
const loadedColumns = [] as any[]
const columnToTransfarable = (chunk) => {
return {
biomes: chunk.biomes,
// blockEntities: chunk.blockEntities,
// sectionMask: chunk.sectionMask,
sections: chunk.sections,
// skyLightMask: chunk.skyLightMask,
// blockLightMask: chunk.blockLightMask,
// skyLightSections: chunk.skyLightSections,
// blockLightSections: chunk.blockLightSections
}
}
for (const chunk of chunks) {
const column = await world.getColumn(chunk[0], chunk[1])
if (!column) throw new Error(`Column ${chunk[0]} ${chunk[1]} not found`)
postMessage({
column: columnToTransfarable(column)
})
}
postMessage({
type: 'done',
})
console.timeEnd('columns')
})
}
}
// window.fs = fs