diff --git a/package.json b/package.json index 4ed1e3ea0..c52d9bc5e 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "version": "1.5.0", "description": "A minecraft client running in a browser", "scripts": { - "start": "node scripts/build.js copyFilesDev && node esbuild.mjs --minify --watch", + "start": "node scripts/build.js copyFilesDev && node scripts/prepareData.mjs && node esbuild.mjs --minify --watch", "start-watch-script": "nodemon -w esbuild.mjs esbuild.mjs", - "build": "node scripts/build.js copyFiles && node esbuild.mjs --minify --prod", + "build": "node scripts/build.js copyFiles && node scripts/prepareData.mjs && node esbuild.mjs --minify --prod", "watch": "node scripts/build.js copyFilesDev && webpack serve --config webpack.dev.js --progress", "test:cypress": "cypress run", "test:e2e": "start-test http-get://localhost:8080 test:cypress", @@ -32,6 +32,7 @@ "compression": "^1.7.4", "cypress-plugin-snapshots": "^1.4.4", "diamond-square": "^1.2.0", + "eruda": "^3.0.1", "esbuild": "^0.19.2", "esbuild-loader": "^4.0.0", "esbuild-plugin-polyfill-node": "^0.3.0", @@ -73,6 +74,7 @@ "https-browserify": "^1.0.0", "lodash-webpack-plugin": "^0.11.6", "memfs": "^3.5.3", + "minecraft-inventory-gui": "file:../minecraft-inventory-gui", "mineflayer": "github:zardoy/mineflayer#custom", "mineflayer-pathfinder": "^2.4.4", "npm-run-all": "^4.1.5", @@ -92,14 +94,16 @@ "webpack-dev-middleware": "^6.1.1", "webpack-dev-server": "^4.15.1", "webpack-merge": "^5.9.0", - "workbox-webpack-plugin": "^6.6.0", - "minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next" + "workbox-webpack-plugin": "^6.6.0" }, "pnpm": { "overrides": { "minecraft-data": "latest", "prismarine-provider-anvil": "github:zardoy/prismarine-provider-anvil#chunk-impl-require-fix", - "minecraft-protocol": "github:zardoy/minecraft-protocol#custom-client-extra" + "minecraft-protocol": "file:../minecraft-protocol", + "space-squid": "file:../space-squid", + "@dimaka/interface": "file:../interface", + "mineflayer": "file:../mineflayer" } } } diff --git a/scripts/esbuildPlugins.mjs b/scripts/esbuildPlugins.mjs index 42ca70b9e..ae4193666 100644 --- a/scripts/esbuildPlugins.mjs +++ b/scripts/esbuildPlugins.mjs @@ -20,24 +20,24 @@ const plugins = [ path: (await build.resolve('minecraft-protocol/src/index.js', { kind, resolveDir })).path, } }) - // build.onResolve({ - // filter: /^\.\/data.js$/, - // }, ({ resolveDir, path }) => { - // if (!resolveDir.endsWith('minecraft-data')) return - // return { - // namespace: 'load-global-minecraft-data', - // path - // } - // }) - // build.onLoad({ - // filter: /.+/, - // namespace: 'load-global-minecraft-data', - // }, () => { - // return { - // contents: 'module.exports = window.minecraftData', - // loader: 'js', - // } - // }) + build.onResolve({ + filter: /^\.\/data.js$/, + }, ({ resolveDir, path }) => { + if (!resolveDir.endsWith('minecraft-data')) return + return { + namespace: 'load-global-minecraft-data', + path + } + }) + build.onLoad({ + filter: /.+/, + namespace: 'load-global-minecraft-data', + }, () => { + return { + contents: 'window.mcData ??= {};module.exports = { pc: window.mcData }', + loader: 'js', + } + }) // build.onResolve({ // filter: /^minecraft-assets$/, // }, ({ resolveDir, path }) => { @@ -89,6 +89,7 @@ const plugins = [ filter: /.*/, namespace: customMcDataNs, }, async ({ path, ...rest }) => { + throw new Error('unreachable') const resolvedPath = await build.resolve('minecraft-data/minecraft-data/data/dataPaths.json', { kind: 'require-call', resolveDir: process.cwd() }) const dataPaths = JSON.parse(await fs.promises.readFile(resolvedPath.path, 'utf8')) diff --git a/scripts/prepareData.mjs b/scripts/prepareData.mjs new file mode 100644 index 000000000..2953736ca --- /dev/null +++ b/scripts/prepareData.mjs @@ -0,0 +1,79 @@ +//@ts-check +import { build } from 'esbuild' +import Module from "node:module" +import { dirname } from 'node:path' + +const require = Module.createRequire(import.meta.url) + +const dataPaths = require('minecraft-data/minecraft-data/data/dataPaths.json') + +function toMajor (version) { + const [a, b] = (version + '').split('.') + return `${a}.${b}` +} + +const ignoredVersionsRegex = /(^0\.30c$)|w|-pre|-rc/ + +const grouped = {} + +for (const [version, data] of Object.entries(dataPaths.pc)) { + if (ignoredVersionsRegex.test(version)) continue + const major = toMajor(version) + grouped[major] ??= {} + grouped[major][version] = data +} + +console.log('preparing data') +for (const [major, versions] of Object.entries(grouped)) { + let contents = 'Object.assign(window.mcData, {\n' + for (const [version, dataSet] of Object.entries(versions)) { + contents += ` '${version}': {\n` + for (const [dataType, dataPath] of Object.entries(dataSet)) { + const loc = `minecraft-data/data/${dataPath}/` + contents += ` get ${dataType} () { return require("./${loc}${dataType}.json") },\n` + } + contents += ' },\n' + } + contents += '})' + + build({ + bundle: true, + outfile: `dist/mc-data/${major}.js`, + // entryPoints: ['mcData.js'], + stdin: { + contents, + + resolveDir: dirname(require.resolve('minecraft-data')), + sourcefile: `mcData${major}.js`, + loader: 'js', + }, + plugins: [ + // { + // name: 'mcData', + // setup (build) { + // build.onResolve({ + // filter: /^mcData\.js$/, + // }, ({ path, pluginData }) => { + // return { + // path, + // namespace: 'mc-data', + // } + // }) + // build.onLoad({ + // filter: /.*/, + // namespace: 'mc-data', + // }, ({ namespace, path }) => { + // const version = path.split('/')[2] + // const data = versions[version] + // if (!data) throw new Error(`No data for ${version}`) + // return { + // contents: `export const data = ${JSON.stringify(data, null, 2)}`, + // loader: 'js', + // } + // }) + // } + // } + ], + }) +} +console.log('data prepared') diff --git a/src/index.js b/src/index.js index c415b4ba1..91d51bff4 100644 --- a/src/index.js +++ b/src/index.js @@ -366,6 +366,13 @@ async function connect (connectOptions) { }) let singlePlayerServer try { + Object.assign(serverOptions, _.defaultsDeep({}, connectOptions.serverOverrides, options.localServerOptions, serverOptions)) + let version = connectOptions.botVersion ?? serverOptions.version + if (version) { + setLoadingScreenStatus(`Downloading data for ${version}`) + await loadScript(`./mc-data/${toMajorVersion(version)}.js`) + } + if (singeplayer) { window.serverDataChannel ??= {} window.worldLoaded = false diff --git a/src/utils.js b/src/utils.js index aec751cee..411e92763 100644 --- a/src/utils.js +++ b/src/utils.js @@ -132,3 +132,30 @@ function javaUUID (s) { export function nameToMcOfflineUUID (name) { return (new UUID(javaUUID('OfflinePlayer:' + name))).toString() } +export const loadScript = async function (/** @type {string} */ scriptSrc) { + if (document.querySelector(`script[src="${scriptSrc}"]`)) { + return + } + + return new Promise((resolve, reject) => { + const scriptElement = document.createElement('script') + scriptElement.src = scriptSrc + scriptElement.async = true + + scriptElement.onload = () => { + resolve(scriptElement) + } + + scriptElement.onerror = (error) => { + reject(error) + } + + document.head.appendChild(scriptElement) + }) +} + +// doesn't support snapshots +export const toMajorVersion = (version) => { + const [a, b] = (version + '').split('.') + return `${a}.${b}` +}