diff --git a/.eslintignore b/.eslintignore index 3c3629e64..1e851aa25 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,4 @@ node_modules +rsbuild.config.ts +*.module.css.d.ts +generated diff --git a/.vscode/launch.json b/.vscode/launch.json index 6bbd4198e..b0621b880 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -29,7 +29,7 @@ "type": "chrome", "name": "Launch Chrome", "request": "launch", - "url": "http://localhost:8080/", + "url": "http://localhost:3000/", "pathMapping": { "/": "${workspaceFolder}/dist" }, @@ -50,7 +50,7 @@ "name": "Attach Firefox", "request": "attach", // comment if using webpack - "url": "http://localhost:8080/", + "url": "http://localhost:3000/", "webRoot": "${workspaceFolder}/", "skipFiles": [ // "/**/*vendors*" diff --git a/Dockerfile b/Dockerfile index 0ae1c6e01..2e43ad8aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,14 @@ # ---- Build Stage ---- FROM node:18-alpine AS build # Without git installing the npm packages fails -RUN apk add --no-cache git python3 make g++ cairo-dev pango-dev jpeg-dev giflib-dev librsvg-dev +RUN apk add git WORKDIR /app COPY . /app # install pnpm RUN npm i -g pnpm@9.0.4 -RUN pnpm install +# TODO need flat --no-root-optional +RUN node ./scripts/dockerPrepare.mjs +RUN pnpm i # TODO for development # EXPOSE 9090 @@ -29,4 +31,4 @@ RUN npm i -g pnpm@9.0.4 RUN npm init -yp RUN pnpm i express github:zardoy/prismarinejs-net-browserify compression cors EXPOSE 8080 -ENTRYPOINT ["node", "server.js"] +ENTRYPOINT ["node", "server.js", "--prod"] diff --git a/README.MD b/README.MD index 401eec56d..b6540ea07 100644 --- a/README.MD +++ b/README.MD @@ -16,7 +16,7 @@ You can try this out at [mcraft.fun](https://mcraft.fun/), [pcm.gg](https://pcm. - Works offline - Play with friends over internet! (P2P is powered by Peer.js discovery servers) - First-class touch (mobile) & controller support -- Resource pack support +- FULL Resource pack support: Custom GUI, all textures & custom models! Server resource packs are also supported. - Builtin JEI with recipes & guides for every item (also replaces creative inventory) - even even more! diff --git a/README.NPM.MD b/README.NPM.MD index c44492c68..9c4bf17f0 100644 --- a/README.NPM.MD +++ b/README.NPM.MD @@ -1,6 +1,6 @@ # Minecraft React -Minecraft UI components for React. +Minecraft UI components for React extracted from [mcraft.fun](https://mcraft.fun) project. ```bash pnpm i minecraft-react diff --git a/assets/extra-textures/background/panorama_0.png b/assets/background/panorama_0.png similarity index 100% rename from assets/extra-textures/background/panorama_0.png rename to assets/background/panorama_0.png diff --git a/assets/extra-textures/background/panorama_1.png b/assets/background/panorama_1.png similarity index 100% rename from assets/extra-textures/background/panorama_1.png rename to assets/background/panorama_1.png diff --git a/assets/extra-textures/background/panorama_2.png b/assets/background/panorama_2.png similarity index 100% rename from assets/extra-textures/background/panorama_2.png rename to assets/background/panorama_2.png diff --git a/assets/extra-textures/background/panorama_3.png b/assets/background/panorama_3.png similarity index 100% rename from assets/extra-textures/background/panorama_3.png rename to assets/background/panorama_3.png diff --git a/assets/extra-textures/background/panorama_4.png b/assets/background/panorama_4.png similarity index 100% rename from assets/extra-textures/background/panorama_4.png rename to assets/background/panorama_4.png diff --git a/assets/extra-textures/background/panorama_5.png b/assets/background/panorama_5.png similarity index 100% rename from assets/extra-textures/background/panorama_5.png rename to assets/background/panorama_5.png diff --git a/assets/destroy_stage_0.png b/assets/destroy_stage_0.png new file mode 100644 index 000000000..f65b7ede8 Binary files /dev/null and b/assets/destroy_stage_0.png differ diff --git a/assets/destroy_stage_1.png b/assets/destroy_stage_1.png new file mode 100644 index 000000000..7c9159617 Binary files /dev/null and b/assets/destroy_stage_1.png differ diff --git a/assets/destroy_stage_2.png b/assets/destroy_stage_2.png new file mode 100644 index 000000000..dadd6b058 Binary files /dev/null and b/assets/destroy_stage_2.png differ diff --git a/assets/destroy_stage_3.png b/assets/destroy_stage_3.png new file mode 100644 index 000000000..52a40b659 Binary files /dev/null and b/assets/destroy_stage_3.png differ diff --git a/assets/destroy_stage_4.png b/assets/destroy_stage_4.png new file mode 100644 index 000000000..e37c88a2c Binary files /dev/null and b/assets/destroy_stage_4.png differ diff --git a/assets/destroy_stage_5.png b/assets/destroy_stage_5.png new file mode 100644 index 000000000..9590d2f78 Binary files /dev/null and b/assets/destroy_stage_5.png differ diff --git a/assets/destroy_stage_6.png b/assets/destroy_stage_6.png new file mode 100644 index 000000000..fb00ade54 Binary files /dev/null and b/assets/destroy_stage_6.png differ diff --git a/assets/destroy_stage_7.png b/assets/destroy_stage_7.png new file mode 100644 index 000000000..0b40c7891 Binary files /dev/null and b/assets/destroy_stage_7.png differ diff --git a/assets/destroy_stage_8.png b/assets/destroy_stage_8.png new file mode 100644 index 000000000..c0bf1dece Binary files /dev/null and b/assets/destroy_stage_8.png differ diff --git a/assets/destroy_stage_9.png b/assets/destroy_stage_9.png new file mode 100644 index 000000000..e3185f82f Binary files /dev/null and b/assets/destroy_stage_9.png differ diff --git a/assets/extra-textures/edition.png b/assets/edition.png similarity index 100% rename from assets/extra-textures/edition.png rename to assets/edition.png diff --git a/assets/extra-textures/gui.png b/assets/gui.png similarity index 100% rename from assets/extra-textures/gui.png rename to assets/gui.png diff --git a/assets/invsprite.png b/assets/invsprite.png deleted file mode 100644 index d3022e5eb..000000000 Binary files a/assets/invsprite.png and /dev/null differ diff --git a/esbuild.mjs b/esbuild.mjs deleted file mode 100644 index 3dfe9939f..000000000 --- a/esbuild.mjs +++ /dev/null @@ -1,140 +0,0 @@ -//@ts-check -import * as esbuild from 'esbuild' -import fs from 'fs' -// import htmlPlugin from '@chialab/esbuild-plugin-html' -import server from './server.js' -import { clients, plugins, startWatchingHmr } from './scripts/esbuildPlugins.mjs' -import { generateSW } from 'workbox-build' -import { getSwAdditionalEntries } from './scripts/build.js' -import { build } from 'esbuild' - -//@ts-ignore -try { await import('./localSettings.mjs') } catch { } - -const entrypoint = 'index.ts' - -fs.writeFileSync('dist/index.html', fs.readFileSync('index.html', 'utf8').replace('', ``), 'utf8') - -const watch = process.argv.includes('--watch') || process.argv.includes('-w') -const prod = process.argv.includes('--prod') -if (prod) process.env.PROD = 'true' -const dev = !prod - -const banner = [ - 'window.global = globalThis;', -] - -const buildingVersion = new Date().toISOString().split(':')[0] - -/** @type {import('esbuild').BuildOptions} */ -const buildOptions = { - bundle: true, - entryPoints: [`src/${entrypoint}`], - target: ['es2020'], - jsx: 'automatic', - jsxDev: dev, - // logLevel: 'debug', - logLevel: 'info', - platform: 'browser', - sourcemap: prod ? true : 'linked', - outdir: 'dist', - mainFields: [ - 'browser', 'module', 'main' - ], - keepNames: true, - banner: { - // using \n breaks sourcemaps! - js: banner.join(';'), - }, - external: [ - 'sharp' - ], - alias: { - 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', - 'yggdrasil': './src/yggdrasilReplacement.ts', - // todo write advancedAliases plugin - }, - inject: [ - './src/shims.js' - ], - metafile: true, - plugins, - sourcesContent: !process.argv.includes('--no-sources'), - minify: process.argv.includes('--minify'), - define: { - 'process.env.NODE_ENV': JSON.stringify(dev ? 'development' : 'production'), - 'process.env.BUILD_VERSION': JSON.stringify(!dev ? buildingVersion : 'undefined'), - 'process.env.GITHUB_URL': - JSON.stringify(`https://github.com/${process.env.GITHUB_REPOSITORY || `${process.env.VERCEL_GIT_REPO_OWNER}/${process.env.VERCEL_GIT_REPO_SLUG}`}`), - 'process.env.DEPS_VERSIONS': JSON.stringify({}) - }, - loader: { - // todo use external or resolve issues with duplicating - '.png': 'dataurl', - '.svg': 'dataurl', - '.map': 'empty', - '.vert': 'text', - '.frag': 'text', - '.obj': 'text', - '.woff': 'dataurl', - '.woff2': 'dataurl', - '.ttf': 'dataurl', - '.webp': 'dataurl', - }, - write: false, - // todo would be better to enable? - // preserveSymlinks: true, -} - -if (watch) { - const ctx = await esbuild.context(buildOptions) - await ctx.watch() - startWatchingHmr() - server.app.get('/esbuild', (req, res, next) => { - res.writeHead(200, { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache', - Connection: 'keep-alive', - }) - - // Send a comment to keep the connection alive - res.write(': ping\n\n') - - // Add the client response to the clients array - clients.push(res) - - // Handle any client disconnection logic - res.on('close', () => { - const index = clients.indexOf(res) - if (index !== -1) { - clients.splice(index, 1) - } - }) - }) -} else { - const result = await build(buildOptions) - // console.log(await esbuild.analyzeMetafile(result.metafile)) - - if (prod) { - fs.writeFileSync('dist/version.txt', buildingVersion, 'utf-8') - - const { count, size, warnings } = await generateSW({ - // dontCacheBustURLsMatching: [new RegExp('...')], - globDirectory: 'dist', - skipWaiting: true, - clientsClaim: true, - additionalManifestEntries: getSwAdditionalEntries(), - globPatterns: [], - swDest: 'dist/service-worker.js', - }) - } -} diff --git a/experiments/texture-render.html b/experiments/texture-render.html deleted file mode 100644 index be406102a..000000000 --- a/experiments/texture-render.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - Document - - - - - - - diff --git a/index.html b/index.html index 62e109cd6..26a2ef96d 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ --> Prismarine Web Client - - + diff --git a/package.json b/package.json index 922de4df2..91b42f878 100644 --- a/package.json +++ b/package.json @@ -3,22 +3,26 @@ "version": "0.0.0-dev", "description": "A minecraft client running in a browser", "scripts": { - "start": "node scripts/build.js copyFilesDev && node scripts/prepareData.mjs && node esbuild.mjs --watch", - "start-watch-script": "nodemon -w esbuild.mjs --watch", - "build": "node scripts/build.js copyFiles && node scripts/prepareData.mjs -f && node esbuild.mjs --minify --prod", - "check-build": "tsc && pnpm build", + "dev-rsbuild": "rsbuild dev", + "dev-proxy": "node server.js", + "start": "run-p dev-rsbuild dev-proxy", + "start-watch-script": "nodemon -w rsbuild.config.ts --watch", + "build": "rsbuild build", + "build-analyze": "BUNDLE_ANALYZE=true rsbuild build", + "check-build": "tsx scripts/genShims.ts && tsc && pnpm build", "test:cypress": "cypress run", "test-unit": "vitest", "test:e2e": "start-test http-get://localhost:8080 test:cypress", - "prod-start": "node server.js", - "postinstall": "node scripts/gen-texturepack-files.mjs && tsx scripts/optimizeBlockCollisions.ts", + "prod-start": "node server.js --prod", + "postinstall": "tsx scripts/optimizeBlockCollisions.ts && pnpm build-mesher", "test-mc-server": "tsx cypress/minecraft-server.mjs", "lint": "eslint \"{src,cypress}/**/*.{ts,js,jsx,tsx}\"", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build && node scripts/build.js moveStorybookFiles", "start-experiments": "vite --config experiments/vite.config.ts --host", "watch-other-workers": "echo NOT IMPLEMENTED", - "watch-mesher": "node prismarine-viewer/buildMesherWorker.mjs -w", + "build-mesher": "node prismarine-viewer/buildMesherWorker.mjs", + "watch-mesher": "pnpm build-mesher -w", "run-playground": "run-p watch-mesher watch-other-workers playground-server watch-playground", "run-all": "run-p start run-playground", "playground-server": "live-server --port=9090 prismarine-viewer/public", @@ -56,19 +60,18 @@ "classnames": "^2.5.1", "compression": "^1.7.4", "cors": "^2.8.5", - "cypress-plugin-snapshots": "^1.4.4", "debug": "^4.3.4", + "diff-match-patch": "^1.0.5", "eruda": "^3.0.1", "esbuild": "^0.19.3", "esbuild-plugin-polyfill-node": "^0.3.0", "express": "^4.18.2", "filesize": "^10.0.12", - "flying-squid": "npm:@zardoy/flying-squid@^0.0.33", + "flying-squid": "npm:@zardoy/flying-squid@^0.0.34", "fs-extra": "^11.1.1", "google-drive-browserfs": "github:zardoy/browserfs#google-drive", "jszip": "^3.10.1", "lodash-es": "^4.17.21", - "minecraft-assets": "^1.12.2", "minecraft-data": "3.65.0", "minecraft-protocol": "github:PrismarineJS/node-minecraft-protocol#master", "mineflayer-item-map-downloader": "github:zardoy/mineflayer-item-map-downloader", @@ -104,11 +107,17 @@ "workbox-build": "^7.0.0" }, "devDependencies": { + "@rsbuild/core": "1.0.1-beta.4", + "@rsbuild/plugin-node-polyfill": "^1.0.3", + "@rsbuild/plugin-type-check": "1.0.1-beta.4", + "@rsbuild/plugin-typed-css-modules": "^1.0.1", + "@rsbuild/plugin-react": "^1.0.1-beta.4", "@storybook/addon-essentials": "^7.4.6", "@storybook/addon-links": "^7.4.6", "@storybook/blocks": "^7.4.6", "@storybook/react": "^7.4.6", "@storybook/react-vite": "^7.4.6", + "@types/diff-match-patch": "^1.0.36", "@types/lodash-es": "^4.17.9", "@types/react-transition-group": "^4.4.7", "@types/stats.js": "^0.17.1", @@ -122,7 +131,6 @@ "constants-browserify": "^1.0.0", "contro-max": "^0.1.8", "crypto-browserify": "^3.12.0", - "cypress": "^10.11.0", "cypress-esbuild-preprocessor": "^1.0.2", "eslint": "^8.50.0", "eslint-config-zardoy": "^0.2.17", @@ -131,6 +139,7 @@ "http-browserify": "^1.7.0", "http-server": "^14.1.1", "https-browserify": "^1.0.0", + "mc-assets": "^0.2.5", "minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next", "mineflayer": "github:zardoy/mineflayer", "mineflayer-pathfinder": "^2.4.4", @@ -150,10 +159,13 @@ "yaml": "^2.3.2" }, "optionalDependencies": { + "cypress": "^10.11.0", + "cypress-plugin-snapshots": "^1.4.4", "systeminformation": "^5.21.22" }, "pnpm": { "overrides": { + "buffer": "^6.0.3", "@nxg-org/mineflayer-physics-util": "1.5.8", "three": "0.154.0", "diamond-square": "github:zardoy/diamond-square", @@ -171,7 +183,8 @@ "patchedDependencies": { "minecraft-protocol@1.47.0": "patches/minecraft-protocol@1.47.0.patch", "three@0.154.0": "patches/three@0.154.0.patch", - "pixelarticons@1.8.1": "patches/pixelarticons@1.8.1.patch" + "pixelarticons@1.8.1": "patches/pixelarticons@1.8.1.patch", + "mineflayer-item-map-downloader@1.2.0": "patches/mineflayer-item-map-downloader@1.2.0.patch" } }, "packageManager": "pnpm@9.0.4" diff --git a/package.npm.json b/package.npm.json index 7e13d67b5..4853780f5 100644 --- a/package.npm.json +++ b/package.npm.json @@ -3,7 +3,13 @@ "description": "A Minecraft-like React UI library", "keywords": [ "minecraft", - "minecraft style" + "minecraft style", + "minecraft ui", + "minecraft components", + "minecraft react", + "minecraft library", + "minecraft web", + "minecraft browser" ], "license": "MIT", "sideEffects": false, diff --git a/patches/mineflayer-item-map-downloader@1.2.0.patch b/patches/mineflayer-item-map-downloader@1.2.0.patch new file mode 100644 index 000000000..97813cc1d --- /dev/null +++ b/patches/mineflayer-item-map-downloader@1.2.0.patch @@ -0,0 +1,16 @@ +diff --git a/package.json b/package.json +index 2a7aff75a9f1c7fe4eebb657002e58f4581dad0e..cd3490983353336efeb13f24f0af69c6c1d16444 100644 +--- a/package.json ++++ b/package.json +@@ -9,10 +9,7 @@ + "keywords": [], + "author": "Ic3Tank", + "license": "ISC", +- "dependencies": { +- "mineflayer": "^4.3.0", +- "sharp": "^0.30.6" +- }, ++ "dependencies": {}, + "devDependencies": { + "mineflayer-item-map-downloader": "file:./" + } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ba6c10e4c..9acc23114 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: + buffer: ^6.0.3 '@nxg-org/mineflayer-physics-util': 1.5.8 three: 0.154.0 diamond-square: github:zardoy/diamond-square @@ -20,6 +21,9 @@ patchedDependencies: minecraft-protocol@1.47.0: hash: 7otpchsbv7hxsuis4rrrwdtbve path: patches/minecraft-protocol@1.47.0.patch + mineflayer-item-map-downloader@1.2.0: + hash: bck55yjvd4wrgz46x7o4vfur5q + path: patches/mineflayer-item-map-downloader@1.2.0.patch pixelarticons@1.8.1: hash: cclg2qo6d4yjs4evj64nr2mbwa path: patches/pixelarticons@1.8.1.patch @@ -88,12 +92,12 @@ importers: cors: specifier: ^2.8.5 version: 2.8.5 - cypress-plugin-snapshots: - specifier: ^1.4.4 - version: 1.4.4(cypress@10.11.0) debug: specifier: ^4.3.4 version: 4.3.4(supports-color@8.1.1) + diff-match-patch: + specifier: ^1.0.5 + version: 1.0.5 eruda: specifier: ^3.0.1 version: 3.0.1 @@ -110,8 +114,8 @@ importers: specifier: ^10.0.12 version: 10.0.12 flying-squid: - specifier: npm:@zardoy/flying-squid@^0.0.33 - version: '@zardoy/flying-squid@0.0.33(encoding@0.1.13)' + specifier: npm:@zardoy/flying-squid@^0.0.34 + version: '@zardoy/flying-squid@0.0.34(encoding@0.1.13)' fs-extra: specifier: ^11.1.1 version: 11.1.1 @@ -124,9 +128,6 @@ importers: lodash-es: specifier: ^4.17.21 version: 4.17.21 - minecraft-assets: - specifier: ^1.12.2 - version: 1.12.2 minecraft-data: specifier: 3.65.0 version: 3.65.0 @@ -135,7 +136,7 @@ importers: version: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13) mineflayer-item-map-downloader: specifier: github:zardoy/mineflayer-item-map-downloader - version: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7(encoding@0.1.13) + version: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7(patch_hash=bck55yjvd4wrgz46x7o4vfur5q)(encoding@0.1.13) mojangson: specifier: ^2.0.4 version: 2.0.4 @@ -227,10 +228,31 @@ importers: specifier: ^7.0.0 version: 7.0.0(@types/babel__core@7.20.2) optionalDependencies: + cypress: + specifier: ^10.11.0 + version: 10.11.0 + cypress-plugin-snapshots: + specifier: ^1.4.4 + version: 1.4.4(cypress@10.11.0) systeminformation: specifier: ^5.21.22 version: 5.22.7 devDependencies: + '@rsbuild/core': + specifier: 1.0.1-beta.4 + version: 1.0.1-beta.4 + '@rsbuild/plugin-node-polyfill': + specifier: ^1.0.3 + version: 1.0.3(@rsbuild/core@1.0.1-beta.4) + '@rsbuild/plugin-react': + specifier: ^1.0.1-beta.4 + version: 1.0.1-beta.4(@rsbuild/core@1.0.1-beta.4) + '@rsbuild/plugin-type-check': + specifier: 1.0.1-beta.4 + version: 1.0.1-beta.4(@rsbuild/core@1.0.1-beta.4)(esbuild@0.19.3)(typescript@5.5.4) + '@rsbuild/plugin-typed-css-modules': + specifier: ^1.0.1 + version: 1.0.1(@rsbuild/core@1.0.1-beta.4) '@storybook/addon-essentials': specifier: ^7.4.6 version: 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -245,7 +267,10 @@ importers: version: 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4) '@storybook/react-vite': specifier: ^7.4.6 - version: 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@2.79.1)(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) + version: 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@2.79.1)(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.31.3)) + '@types/diff-match-patch': + specifier: ^1.0.36 + version: 1.0.36 '@types/lodash-es': specifier: ^4.17.9 version: 4.17.9 @@ -285,9 +310,6 @@ importers: crypto-browserify: specifier: ^3.12.0 version: 3.12.0 - cypress: - specifier: ^10.11.0 - version: 10.11.0 cypress-esbuild-preprocessor: specifier: ^1.0.2 version: 1.0.2 @@ -312,6 +334,9 @@ importers: https-browserify: specifier: ^1.0.0 version: 1.0.0 + mc-assets: + specifier: ^0.2.5 + version: 0.2.5 minecraft-inventory-gui: specifier: github:zardoy/minecraft-inventory-gui#next version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/c50afc54e39817f7e4d313ce0f6fdaad71e7e4f4(@types/react@18.2.20)(react@18.2.0) @@ -359,7 +384,7 @@ importers: version: 5.5.4 vitest: specifier: ^0.34.6 - version: 0.34.6(terser@5.19.2) + version: 0.34.6(terser@5.31.3) yaml: specifier: ^2.3.2 version: 2.3.2 @@ -375,9 +400,6 @@ importers: buffer: specifier: ^6.0.3 version: 6.0.3 - canvas: - specifier: ^2.11.2 - version: 2.11.2(encoding@0.1.13) filesize: specifier: ^10.0.12 version: 10.0.12 @@ -387,9 +409,6 @@ importers: lil-gui: specifier: ^0.18.2 version: 0.18.2 - looks-same: - specifier: ^8.2.3 - version: 8.2.3 minecraft-wrap: specifier: ^1.3.0 version: 1.5.1(encoding@0.1.13) @@ -398,7 +417,7 @@ importers: version: 1.3.6 prismarine-block: specifier: github:zardoy/prismarine-block#next-era - version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 + version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/a69b66ab1e4be6b67f25a5a6db15e0ad39e11819 prismarine-chunk: specifier: github:zardoy/prismarine-chunk version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) @@ -430,6 +449,9 @@ importers: specifier: ^0.1.7 version: 0.1.8 optionalDependencies: + canvas: + specifier: ^2.11.2 + version: 2.11.2(encoding@0.1.13) node-canvas-webgl: specifier: ^0.3.0 version: 0.3.0(encoding@0.1.13) @@ -438,7 +460,7 @@ importers: dependencies: vite: specifier: ^4.4.9 - version: 4.4.10(@types/node@20.12.8)(terser@5.19.2) + version: 4.4.10(@types/node@20.12.8)(terser@5.31.3) packages: @@ -1948,6 +1970,9 @@ packages: '@jridgewell/trace-mapping@0.3.19': resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jspm/core@2.0.1': resolution: {integrity: sha512-Lg3PnLp0QXpxwLIAuuJboLeRaIhrgJjeuh797QADg3xz8wGLugQOS5DpsE8A6i6Adgzf+bacllkKZG3J0tGfDw==} @@ -1963,6 +1988,18 @@ packages: peerDependencies: react: ^18.2.0 + '@module-federation/runtime-tools@0.2.3': + resolution: {integrity: sha512-capN8CVTCEqNAjnl102girrkevczoQfnQYyiYC4WuyKsg7+LUqfirIe1Eiyv6VSE2UgvOTZDnqvervA6rBOlmg==} + + '@module-federation/runtime@0.2.3': + resolution: {integrity: sha512-N+ZxBUb1mkmfO9XT1BwgYQgShtUTlijHbukqQ4afFka5lRAT+ayC7RKfHJLz0HbuexKPCmPBDfdmCnErR5WyTQ==} + + '@module-federation/sdk@0.2.3': + resolution: {integrity: sha512-W9zrPchLocyCBc/B8CW21akcfJXLl++9xBe1L1EtgxZGfj/xwHt0GcBWE/y+QGvYTL2a1iZjwscbftbUhxgxXg==} + + '@module-federation/webpack-bundler-runtime@0.2.3': + resolution: {integrity: sha512-L/jt2uJ+8dwYiyn9GxryzDR6tr/Wk8rpgvelM2EBeLIhu7YxCHSmSjQYhw3BTux9zZIr47d1K9fGjBFsVRd/SQ==} + '@msgpack/msgpack@2.8.0': resolution: {integrity: sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==} engines: {node: '>= 10'} @@ -2393,6 +2430,106 @@ packages: rollup: optional: true + '@rsbuild/core@1.0.1-beta.4': + resolution: {integrity: sha512-mjtmZIrlNf8nHuTDIwazk/4HFkXmjg/A5CwGsl77GeCp8ciI5D2q5ZSKvFfLTOIFAWWpno3pOLT8bBR1Co9YKw==} + engines: {node: '>=16.7.0'} + hasBin: true + + '@rsbuild/plugin-node-polyfill@1.0.3': + resolution: {integrity: sha512-AoPIOV1pyInIz08K1ECwUjFemLLSa5OUq8sfJN1ShXrGR2qc14b1wzwZKwF4vgKnBromqfMLagVbk6KT/nLIvQ==} + peerDependencies: + '@rsbuild/core': 1.x + peerDependenciesMeta: + '@rsbuild/core': + optional: true + + '@rsbuild/plugin-react@1.0.1-beta.4': + resolution: {integrity: sha512-CIn56QLBZpS+4+zRFehDdW+1iHwi+M8omztCwzYbvkWwtz7XwGGjgnoRrw4FW+vCCW+n6PzIlOQiTZsOGrP3Fg==} + peerDependencies: + '@rsbuild/core': ^1.0.1-beta.0 + + '@rsbuild/plugin-type-check@1.0.1-beta.4': + resolution: {integrity: sha512-Ot5VjGBdAt5GK0wNCQcBDpj0FPDk+7Flt7TcmRs+dvt1F6bU9pLQ/WAxFBQ/NhrEXvWt8kx0AOJ2qTFId7nxjA==} + peerDependencies: + '@rsbuild/core': ^1.0.1-beta.0 + + '@rsbuild/plugin-typed-css-modules@1.0.1': + resolution: {integrity: sha512-biCSm7+vOgqrqXdAjxnjGNA7KPUfBadfndCeINJ2HApWfuQ2TLWuI5R+MzGvslis13SCKQ55K7NMAkvRhXyi8w==} + peerDependencies: + '@rsbuild/core': 1.x + peerDependenciesMeta: + '@rsbuild/core': + optional: true + + '@rspack/binding-darwin-arm64@1.0.0-alpha.5': + resolution: {integrity: sha512-ogpsxEjqwsn4aeeS0wyUnxuH8yXKTa2+BfxM7aSQILq4MNUVH0MqZ9dn0HAaGfQ3hdUhIqE3Gld6spdQCrgtHQ==} + cpu: [arm64] + os: [darwin] + + '@rspack/binding-darwin-x64@1.0.0-alpha.5': + resolution: {integrity: sha512-fcMVZJQVo9zJ+7YEqkMms+FlAkMOxTfI98sS+XxKC2M/UWDKdMdl7nyhobH+eEhH/eP0Yww6ikEWqF9r3MUsew==} + cpu: [x64] + os: [darwin] + + '@rspack/binding-linux-arm64-gnu@1.0.0-alpha.5': + resolution: {integrity: sha512-UZC2TScOVWVqICiinGWSYdYPAYcn8F/2L+8sbA6NAwSZo0mzH+LaRr6nZRdW2z7y+lELVDQG8UniMxXjoXjVjg==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-arm64-musl@1.0.0-alpha.5': + resolution: {integrity: sha512-uvrqKqNmj60eCze5ZLxod3nFyDBtDz+OeoSO3T5GU9VRv8XKtd4xJbmm4Nz3A14GOWWfGgGr1cYwQBIGBZActA==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-x64-gnu@1.0.0-alpha.5': + resolution: {integrity: sha512-7P5EnCsQmbLrYnCXJ1P8NF7/FCOpvOHaoNlReDZnut2HRppsUJXMnH3lQucq/sdS3djZ4RdG3sBMcTA3OEALwg==} + cpu: [x64] + os: [linux] + + '@rspack/binding-linux-x64-musl@1.0.0-alpha.5': + resolution: {integrity: sha512-RGj1cZLURjY8RG+t8qG2OB9ruqKQvM0M+JMhwhel57CYW9Ge9zZY+ReEhrdtYjW32KxVvuqtt2e7RhhKibK75w==} + cpu: [x64] + os: [linux] + + '@rspack/binding-win32-arm64-msvc@1.0.0-alpha.5': + resolution: {integrity: sha512-7u/LLEcDcBS5slSsAS9h23sTJNbJ+TUMy7GR91X7ySkqJ0VIR6tzml7+JqFxdPcBGXSszonGbcUupYy3nVzLCQ==} + cpu: [arm64] + os: [win32] + + '@rspack/binding-win32-ia32-msvc@1.0.0-alpha.5': + resolution: {integrity: sha512-HpP7Ptekbv/rQgV253UY+DXSIULINv49JbTBKB2PeBn9ra+Ec4vKPKlQtqIfoPStXEGSmA727nqFQ+VE581P4A==} + cpu: [ia32] + os: [win32] + + '@rspack/binding-win32-x64-msvc@1.0.0-alpha.5': + resolution: {integrity: sha512-t04ipYUTzigLtl6z7R78ytrAlK/oJWAwDUEVblyTtyJ/RwKfREUcS/8dkMx431Ia4Y0Icz6AVNf4avbYCoREyQ==} + cpu: [x64] + os: [win32] + + '@rspack/binding@1.0.0-alpha.5': + resolution: {integrity: sha512-CTrYz0Kgv+3k0sBXbY/MruciFVr2Qd+r3r/VEAVT4N0qhKporsubs1J49vLU2VXun1PBfZ3+3sBknjo5AlA0vw==} + + '@rspack/core@1.0.0-alpha.5': + resolution: {integrity: sha512-3nddnCqwnz91KprvMlqBDURYJ1GkT5IqCl+os05i2ce4Vk3zQmzvv8d/X8l/49CrDCOLrwyyuS3bKwca8aWdcg==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@swc/helpers': '>=0.5.1' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@rspack/lite-tapable@1.0.0-alpha.5': + resolution: {integrity: sha512-B1fNL3en1ohK+QybgjM45PpqcmAmr2LTRUhGvarwouNcj845vjq5clYPqUfFVC0goLmsqx+pt7r+TvpP0Yk67A==} + engines: {node: '>=16.0.0'} + + '@rspack/plugin-react-refresh@1.0.0-alpha.5': + resolution: {integrity: sha512-qyTYh1CsHQOjh6hxKIpiWgH18uwNj4+renv5U5nDIHixz7b8f96PYIP+Ptc9BnNklkc4BivF2RHpSNTsYeZ3fQ==} + peerDependencies: + react-refresh: '>=0.10.0 <1.0.0' + peerDependenciesMeta: + react-refresh: + optional: true + '@rushstack/eslint-patch@1.4.0': resolution: {integrity: sha512-cEjvTPU32OM9lUFegJagO0mRnIn+rbqrG89vV8/xLnLFX0DoR0r1oy5IlTga71Q7uT3Qus7qm7wgeiMT/+Irlg==} @@ -2657,6 +2794,9 @@ packages: '@surma/rollup-plugin-off-main-thread@2.2.3': resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} + '@swc/helpers@0.5.11': + resolution: {integrity: sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==} + '@tootallnate/once@2.0.0': resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} @@ -2706,6 +2846,9 @@ packages: '@types/detect-port@1.3.3': resolution: {integrity: sha512-bV/jQlAJ/nPY3XqSatkGpu+nGzou+uSwrH1cROhn+jBFg47yaNH+blW4C7p9KhopC7QxCv/6M86s37k8dMk0Yg==} + '@types/diff-match-patch@1.0.36': + resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==} + '@types/doctrine@0.0.3': resolution: {integrity: sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA==} @@ -2721,6 +2864,12 @@ packages: '@types/escodegen@0.0.6': resolution: {integrity: sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==} + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + + '@types/eslint@9.6.0': + resolution: {integrity: sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==} + '@types/estree@0.0.39': resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} @@ -2730,6 +2879,9 @@ packages: '@types/estree@1.0.2': resolution: {integrity: sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==} + '@types/estree@1.0.5': + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/express-serve-static-core@4.17.37': resolution: {integrity: sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==} @@ -3022,6 +3174,51 @@ packages: '@vitest/utils@0.34.6': resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==} + '@webassemblyjs/ast@1.12.1': + resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} + + '@webassemblyjs/floating-point-hex-parser@1.11.6': + resolution: {integrity: sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==} + + '@webassemblyjs/helper-api-error@1.11.6': + resolution: {integrity: sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==} + + '@webassemblyjs/helper-buffer@1.12.1': + resolution: {integrity: sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==} + + '@webassemblyjs/helper-numbers@1.11.6': + resolution: {integrity: sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==} + + '@webassemblyjs/helper-wasm-bytecode@1.11.6': + resolution: {integrity: sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==} + + '@webassemblyjs/helper-wasm-section@1.12.1': + resolution: {integrity: sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==} + + '@webassemblyjs/ieee754@1.11.6': + resolution: {integrity: sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==} + + '@webassemblyjs/leb128@1.11.6': + resolution: {integrity: sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==} + + '@webassemblyjs/utf8@1.11.6': + resolution: {integrity: sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==} + + '@webassemblyjs/wasm-edit@1.12.1': + resolution: {integrity: sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==} + + '@webassemblyjs/wasm-gen@1.12.1': + resolution: {integrity: sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==} + + '@webassemblyjs/wasm-opt@1.12.1': + resolution: {integrity: sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==} + + '@webassemblyjs/wasm-parser@1.12.1': + resolution: {integrity: sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==} + + '@webassemblyjs/wast-printer@1.12.1': + resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} + '@xboxreplay/errors@0.1.0': resolution: {integrity: sha512-Tgz1d/OIPDWPeyOvuL5+aai5VCcqObhPnlI3skQuf80GVF3k1I0lPCnGC+8Cm5PV9aLBT5m8qPcJoIUQ2U4y9g==} @@ -3064,6 +3261,12 @@ packages: '@xobotyi/scrollbar-width@1.9.5': resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==} + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + '@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15': resolution: {integrity: sha512-kYzDJO5CA9sy+on/s2aIW0411AklfCi8Ck/4QDivOqsMKpStZA2SsR+X27VTggGwpStWaLrjJcDcdDMowtG8MA==} engines: {node: '>=14.15.0'} @@ -3078,8 +3281,8 @@ packages: resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==} engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'} - '@zardoy/flying-squid@0.0.33': - resolution: {integrity: sha512-zCgHinWrNbS4HugnA1GBMuKQ0rUemBg//b+XhefxKeGBg9ngk8UVlJoR6cCAaa67zjiauEq/rhnNKnA4V7vtuQ==} + '@zardoy/flying-squid@0.0.34': + resolution: {integrity: sha512-1q9AE4GfmRQhKnSJ3QJtLZIznjJ/IcvwjjKKBS/LrxzaN+qsa3RI2H68OOULj5r/tiGU9DQNncW3CpMlezH6gA==} engines: {node: '>=8'} hasBin: true @@ -3108,6 +3311,11 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -3165,6 +3373,11 @@ packages: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} + ajv-keywords@3.5.2: + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -3314,6 +3527,9 @@ packages: assert@2.0.0: resolution: {integrity: sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==} + assert@2.1.0: + resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} + assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} @@ -3529,6 +3745,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.23.2: + resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} @@ -3552,9 +3773,6 @@ packages: buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -3562,6 +3780,9 @@ packages: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} + builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + bytes@3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} engines: {node: '>= 0.8'} @@ -3613,8 +3834,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001524: - resolution: {integrity: sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA==} + caniuse-lite@1.0.30001643: + resolution: {integrity: sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==} canvas@2.11.2: resolution: {integrity: sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==} @@ -3672,6 +3893,10 @@ packages: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + ci-info@3.8.0: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} @@ -3729,9 +3954,6 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} - color-convert@0.5.3: - resolution: {integrity: sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling==} - color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -3739,9 +3961,6 @@ packages: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - color-diff@1.4.0: - resolution: {integrity: sha512-4oDB/o78lNdppbaqrg0HjOp7pHmUc+dfCxWKWFnQg6AB/1dkjtBDop3RZht5386cq9xBUDRvDvSCA7WUlM9Jqw==} - color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} @@ -3818,6 +4037,9 @@ packages: confusing-browser-globals@1.0.11: resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} + console-browserify@1.2.0: + resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} + console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} @@ -3865,6 +4087,9 @@ packages: core-js@3.32.1: resolution: {integrity: sha512-lqufgNn9NLnESg5mQeYsxQP5w7wrViSj0jr/kv6ECQiByzQkrn1MKvV0L3acttpDqfQrHLwr2KCMgX5b8X+lyQ==} + core-js@3.37.1: + resolution: {integrity: sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==} + core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} @@ -3883,6 +4108,15 @@ packages: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + create-ecdh@4.0.4: resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} @@ -4128,6 +4362,9 @@ packages: resolution: {tarball: https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015} version: 1.3.0 + diff-match-patch@1.0.5: + resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} + diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4171,6 +4408,10 @@ packages: dom-walk@0.1.2: resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} + domain-browser@5.7.0: + resolution: {integrity: sha512-edTFu0M/7wO1pXY6GDxVNVW086uqwWYIHP98txhcPyV995X21JIH2DtYp33sQJOupYoXKe9RwTw2Ya2vWaquTQ==} + engines: {node: '>=4'} + domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} @@ -4221,6 +4462,9 @@ packages: electron-to-chromium@1.4.504: resolution: {integrity: sha512-cSMwIAd8yUh54VwitVRVvHK66QqHWE39C3DRj8SWiXitEpVSY3wNPD9y1pxQtLIi4w3UdzF9klLsmuPshz09DQ==} + electron-to-chromium@1.5.0: + resolution: {integrity: sha512-Vb3xHHYnLseK8vlMJQKJYXJ++t4u1/qJ3vykuVrVjvdiOEhYyT1AuP4x03G8EnPmYvYOhe9T+dADTmthjRQMkA==} + elliptic@6.5.4: resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} @@ -4268,6 +4512,10 @@ packages: resolution: {integrity: sha512-IML/R4eG/pUS5w7OfcDE0jKrljWS9nwnEfsxWCIJF5eO6AHo6+Hlv+lQbdlAYsiJPHzUthLm1RUjnBzWOs45cw==} engines: {node: '>=10.2.0'} + enhanced-resolve@5.17.1: + resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} + engines: {node: '>=10.13.0'} + enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} @@ -4320,6 +4568,9 @@ packages: es-module-lexer@0.9.3: resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} + es-module-lexer@1.5.4: + resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} + es-object-atoms@1.0.0: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} engines: {node: '>= 0.4'} @@ -4383,6 +4634,10 @@ packages: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -4518,6 +4773,10 @@ packages: peerDependencies: eslint: '>=8.44.0' + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + eslint-scope@7.2.2: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4556,6 +4815,10 @@ packages: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -4786,6 +5049,13 @@ packages: forever-agent@0.6.1: resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + fork-ts-checker-webpack-plugin@9.0.2: + resolution: {integrity: sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==} + engines: {node: '>=12.13.0', yarn: '>=1.0.0'} + peerDependencies: + typescript: '>3.6.0' + webpack: ^5.11.0 + form-data@2.3.3: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} engines: {node: '>= 0.12'} @@ -4805,6 +5075,10 @@ packages: fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + fs-extra@11.1.1: resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} engines: {node: '>=14.14'} @@ -4813,10 +5087,6 @@ packages: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -4825,6 +5095,9 @@ packages: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} + fs-monkey@1.0.6: + resolution: {integrity: sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -5105,6 +5378,9 @@ packages: resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} engines: {node: '>=12'} + html-entities@2.5.2: + resolution: {integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -5542,6 +5818,10 @@ packages: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + jest-worker@29.7.0: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -5564,10 +5844,6 @@ packages: js-cookie@2.2.1: resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} - js-graph-algorithms@1.0.18: - resolution: {integrity: sha512-Gu1wtWzXBzGeye/j9BuyplGHscwqKRZodp/0M1vyBc19RJpblSwKGu099KwwaTx9cRIV+Qupk8xUMfEiGfFqSA==} - hasBin: true - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -5727,6 +6003,10 @@ packages: resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} engines: {node: '>=4'} + loader-runner@4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + local-pkg@0.4.3: resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} engines: {node: '>=14'} @@ -5802,10 +6082,6 @@ packages: longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - looks-same@8.2.3: - resolution: {integrity: sha512-0LK5r4+9t2D56XPVNH3hhG4o0yBYUdeu9FEd8z0ZCs/2fR9zJQj+6ob6ued8iHk3yddrSAdUA+9YGVK2FBMGUw==} - engines: {node: '>= 12.0.0'} - loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -5885,6 +6161,10 @@ packages: peerDependencies: react: ^18.2.0 + mc-assets@0.2.5: + resolution: {integrity: sha512-HZ4Q1zqbib2ySSorCb+vMkBZAGXTTZIlcSfGq/L15fkg+l+KKslLSivWfFlCXdg9bzGc0x5WeQN3kKWfZmyuFg==} + engines: {node: '>=18.0.0'} + md5-file@4.0.0: resolution: {integrity: sha512-UC0qFwyAjn4YdPpKaDNw6gNxRf7Mcx7jC1UGCY4boCzgvU2Aoc1mOGzTtrjjLKhM5ivsnhoKpQVxKPp+1j1qwg==} engines: {node: '>=6.0'} @@ -5921,6 +6201,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + memfs@3.5.3: + resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} + engines: {node: '>= 4.0.0'} + memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} @@ -6060,9 +6344,6 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - minecraft-assets@1.12.2: - resolution: {integrity: sha512-/eMxh3LNjCXOnU6KnQMjBM8dRnoJNpWIg7mD2m2RthraYiQK2FNzPWIKxWm2j3Ufcf5nzFXupgABledE86r4fQ==} - minecraft-data@3.65.0: resolution: {integrity: sha512-9K8dOrdrcpUklTdqKBtRcKur0gLZnguTvhM/1Xv52qzh8Unkto4290RJc4ueRIYo1VqN4zzQrRxO8lnqtkERDQ==} @@ -6078,6 +6359,11 @@ packages: version: 1.47.0 engines: {node: '>=14'} + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/7057ad979b416192ada235f2f4e3b5eb26af5fa1: + resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/7057ad979b416192ada235f2f4e3b5eb26af5fa1} + version: 1.47.0 + engines: {node: '>=14'} + minecraft-wrap@1.5.1: resolution: {integrity: sha512-7DZ2WhrcRD3fUMau84l9Va0KWzV92SHNdB7mnNdNhgXID2aW6pjWuYPZi8MepEBemA4XKKdnDx7HmhTbkoiR8A==} hasBin: true @@ -6246,9 +6532,6 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - nested-error-stacks@2.1.1: - resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/d3f7f77d8ac751bc171173bba639086c931a62f7: resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/d3f7f77d8ac751bc171173bba639086c931a62f7} version: 0.2.4 @@ -6263,6 +6546,9 @@ packages: resolution: {integrity: sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A==} engines: {node: '>=10'} + node-abort-controller@3.1.1: + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + node-addon-api@5.1.0: resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} @@ -6306,6 +6592,9 @@ packages: node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + node-rsa@0.4.2: resolution: {integrity: sha512-Bvso6Zi9LY4otIZefYrscsUpo2mUpiAVIEmSZV2q41sP8tHZoert3Yu6zv4f/RXJqMNZQKCtnhDugIuCma23YA==} @@ -6502,9 +6791,6 @@ packages: parse-bmfont-xml@1.1.4: resolution: {integrity: sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==} - parse-color@1.0.0: - resolution: {integrity: sha512-fuDHYgFHJGbpGMgw9skY/bj3HL/Jrn4l/5rSspy00DoT4RyLnDcRvPxdZ+r6OFwIsgAuhDh4I09tAId4mI12bw==} - parse-headers@2.0.5: resolution: {integrity: sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==} @@ -6615,6 +6901,9 @@ packages: picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} @@ -6689,8 +6978,8 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + postcss@8.4.39: + resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} engines: {node: ^10 || ^12 || >=14} potpack@1.0.2: @@ -6740,8 +7029,8 @@ packages: minecraft-data: 3.65.0 prismarine-registry: ^1.1.0 - prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8} + prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/a69b66ab1e4be6b67f25a5a6db15e0ad39e11819: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-block/tar.gz/a69b66ab1e4be6b67f25a5a6db15e0ad39e11819} version: 1.17.1 prismarine-chat@1.10.1: @@ -6919,6 +7208,9 @@ packages: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} + punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} @@ -6948,6 +7240,10 @@ packages: resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} engines: {node: '>=0.6'} + querystring-es3@0.2.1: + resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} + engines: {node: '>=0.4.x'} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -7073,8 +7369,8 @@ packages: react: ^18.2.0 react-dom: ^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0 - react-refresh@0.14.0: - resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} react-remove-scroll-bar@2.3.4: @@ -7188,6 +7484,9 @@ packages: resolution: {integrity: sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==} engines: {node: '>=12'} + reduce-configs@1.0.0: + resolution: {integrity: sha512-/JCYSgL/QeXXsq0Lv/7kOZfqvof7vyzHWfyNQPt3c6vc73mU4WRyT8RJ6ZH5Ci08vUOqXwk7jkZy6BycHTDD9w==} + reflect.getprototypeof@1.0.6: resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} @@ -7390,6 +7689,10 @@ packages: scheduler@0.23.0: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + schema-utils@3.3.0: + resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} + engines: {node: '>= 10.13.0'} + screenfull@5.2.0: resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==} engines: {node: '>=0.10.0'} @@ -7428,6 +7731,9 @@ packages: serialize-javascript@4.0.0: resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serve-static@1.15.0: resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} engines: {node: '>= 0.8.0'} @@ -7688,6 +7994,9 @@ packages: stream-browserify@3.0.0: resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + stream-http@3.2.0: + resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==} + stream-shift@1.0.1: resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==} @@ -7817,6 +8126,10 @@ packages: tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + tar-fs@2.1.1: resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} @@ -7847,11 +8160,32 @@ packages: resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==} engines: {node: '>=10'} + terser-webpack-plugin@5.3.10: + resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + terser@5.19.2: resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==} engines: {node: '>=10'} hasBin: true + terser@5.31.3: + resolution: {integrity: sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==} + engines: {node: '>=10'} + hasBin: true + test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -7995,6 +8329,9 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tty-browserify@0.0.1: + resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} + tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -8205,6 +8542,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.1.0: + resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + upper-case-first@2.0.2: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} @@ -8220,6 +8563,9 @@ packages: url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + url@0.11.3: + resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==} + use-callback-ref@1.3.0: resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==} engines: {node: '>=10'} @@ -8421,6 +8767,9 @@ packages: webdriverio: optional: true + vm-browserify@1.1.2: + resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} + w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} @@ -8439,6 +8788,10 @@ packages: resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} engines: {node: '>=10.13.0'} + watchpack@2.4.1: + resolution: {integrity: sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==} + engines: {node: '>=10.13.0'} + wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} @@ -8455,6 +8808,16 @@ packages: webpack-virtual-modules@0.5.0: resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} + webpack@5.93.0: + resolution: {integrity: sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + webrtc-adapter@8.2.3: resolution: {integrity: sha512-gnmRz++suzmvxtp3ehQts6s2JtAGPuDPjA1F3a9ckNpG1kYdYuHWYpazoAnL9FS5/B21tKlhkorbdCXat0+4xQ==} engines: {node: '>=6.0.0', npm: '>=3.10.0'} @@ -8732,7 +9095,7 @@ snapshots: '@ampproject/remapping@2.2.1': dependencies: '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.19 + '@jridgewell/trace-mapping': 0.3.25 '@apideck/better-ajv-errors@0.3.6(ajv@8.12.0)': dependencies: @@ -8766,12 +9129,12 @@ snapshots: '@babel/code-frame': 7.22.13 '@babel/generator': 7.22.10 '@babel/helper-compilation-targets': 7.22.10 - '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.11) + '@babel/helper-module-transforms': 7.23.0(@babel/core@7.22.11) '@babel/helpers': 7.22.11 '@babel/parser': 7.22.13 '@babel/template': 7.22.5 '@babel/traverse': 7.22.11 - '@babel/types': 7.22.11 + '@babel/types': 7.23.0 convert-source-map: 1.9.0 debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 @@ -8798,8 +9161,8 @@ snapshots: '@babel/helper-compilation-targets@7.22.10': dependencies: '@babel/compat-data': 7.22.9 - '@babel/helper-validator-option': 7.22.5 - browserslist: 4.21.10 + '@babel/helper-validator-option': 7.22.15 + browserslist: 4.23.2 lru-cache: 5.1.1 semver: 6.3.1 @@ -8946,7 +9309,7 @@ snapshots: dependencies: '@babel/template': 7.22.5 '@babel/traverse': 7.22.11 - '@babel/types': 7.22.11 + '@babel/types': 7.23.0 transitivePeerDependencies: - supports-color @@ -8958,7 +9321,7 @@ snapshots: '@babel/parser@7.22.13': dependencies: - '@babel/types': 7.22.11 + '@babel/types': 7.23.0 '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.22.5(@babel/core@7.22.11)': dependencies: @@ -9556,18 +9919,18 @@ snapshots: dependencies: '@babel/code-frame': 7.22.13 '@babel/parser': 7.22.13 - '@babel/types': 7.22.11 + '@babel/types': 7.23.0 '@babel/traverse@7.22.11': dependencies: '@babel/code-frame': 7.22.13 '@babel/generator': 7.22.10 - '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.22.5 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.22.13 - '@babel/types': 7.22.11 + '@babel/types': 7.23.0 debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: @@ -9630,6 +9993,7 @@ snapshots: tough-cookie: 4.1.3 tunnel-agent: 0.6.0 uuid: 8.3.2 + optional: true '@cypress/xvfb@1.2.4(supports-color@8.1.1)': dependencies: @@ -9637,6 +10001,7 @@ snapshots: lodash.once: 4.1.1 transitivePeerDependencies: - supports-color + optional: true '@dimaka/interface@0.0.3-alpha.0(@babel/core@7.22.11)(@popperjs/core@2.11.8)(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: @@ -10054,13 +10419,14 @@ snapshots: '@jimp/utils': 0.10.3 bmp-js: 0.1.0 core-js: 3.32.1 + optional: true '@jimp/core@0.10.3': dependencies: '@babel/runtime': 7.22.11 '@jimp/utils': 0.10.3 any-base: 1.1.0 - buffer: 5.7.1 + buffer: 6.0.3 core-js: 3.32.1 exif-parser: 0.1.12 file-type: 9.0.0 @@ -10069,12 +10435,14 @@ snapshots: phin: 2.9.3 pixelmatch: 4.0.2 tinycolor2: 1.6.0 + optional: true '@jimp/custom@0.10.3': dependencies: '@babel/runtime': 7.22.11 '@jimp/core': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/gif@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10083,6 +10451,7 @@ snapshots: '@jimp/utils': 0.10.3 core-js: 3.32.1 omggif: 1.0.10 + optional: true '@jimp/jpeg@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10091,6 +10460,7 @@ snapshots: '@jimp/utils': 0.10.3 core-js: 3.32.1 jpeg-js: 0.3.7 + optional: true '@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10098,6 +10468,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-blur@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10105,6 +10476,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-circle@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10112,6 +10484,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-color@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10120,6 +10493,7 @@ snapshots: '@jimp/utils': 0.10.3 core-js: 3.32.1 tinycolor2: 1.6.0 + optional: true '@jimp/plugin-contain@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)))': dependencies: @@ -10130,6 +10504,7 @@ snapshots: '@jimp/plugin-scale': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)) '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-cover@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)))': dependencies: @@ -10140,6 +10515,7 @@ snapshots: '@jimp/plugin-scale': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)) '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10147,6 +10523,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-displace@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10154,6 +10531,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-dither@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10161,6 +10539,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-fisheye@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10168,6 +10547,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-flip@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-rotate@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)))': dependencies: @@ -10176,6 +10556,7 @@ snapshots: '@jimp/plugin-rotate': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)) '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-gaussian@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10183,6 +10564,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-invert@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10190,6 +10572,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-mask@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10197,6 +10580,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-normalize@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10204,6 +10588,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-print@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))': dependencies: @@ -10213,6 +10598,7 @@ snapshots: '@jimp/utils': 0.10.3 core-js: 3.32.1 load-bmfont: 1.4.1 + optional: true '@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10220,6 +10606,7 @@ snapshots: '@jimp/custom': 0.10.3 '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-rotate@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blit@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-crop@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))': dependencies: @@ -10230,6 +10617,7 @@ snapshots: '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3) '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-scale@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))': dependencies: @@ -10238,6 +10626,7 @@ snapshots: '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3) '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-shadow@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-blur@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))': dependencies: @@ -10247,6 +10636,7 @@ snapshots: '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3) '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugin-threshold@0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-color@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3))': dependencies: @@ -10256,6 +10646,7 @@ snapshots: '@jimp/plugin-resize': 0.10.3(@jimp/custom@0.10.3) '@jimp/utils': 0.10.3 core-js: 3.32.1 + optional: true '@jimp/plugins@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10284,6 +10675,7 @@ snapshots: '@jimp/plugin-threshold': 0.10.3(@jimp/custom@0.10.3)(@jimp/plugin-color@0.10.3(@jimp/custom@0.10.3))(@jimp/plugin-resize@0.10.3(@jimp/custom@0.10.3)) core-js: 3.32.1 timm: 1.7.1 + optional: true '@jimp/png@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10292,6 +10684,7 @@ snapshots: '@jimp/utils': 0.10.3 core-js: 3.32.1 pngjs: 3.4.0 + optional: true '@jimp/tiff@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10299,6 +10692,7 @@ snapshots: '@jimp/custom': 0.10.3 core-js: 3.32.1 utif: 2.0.1 + optional: true '@jimp/types@0.10.3(@jimp/custom@0.10.3)': dependencies: @@ -10311,20 +10705,22 @@ snapshots: '@jimp/tiff': 0.10.3(@jimp/custom@0.10.3) core-js: 3.32.1 timm: 1.7.1 + optional: true '@jimp/utils@0.10.3': dependencies: '@babel/runtime': 7.22.11 core-js: 3.32.1 regenerator-runtime: 0.13.11 + optional: true - '@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.31.3))': dependencies: glob: 7.2.3 glob-promise: 4.2.2(glob@7.2.3) magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.5.4) - vite: 4.5.3(@types/node@20.8.0)(terser@5.19.2) + vite: 4.5.3(@types/node@20.8.0)(terser@5.31.3) optionalDependencies: typescript: 5.5.4 @@ -10350,6 +10746,11 @@ snapshots: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jspm/core@2.0.1': {} '@juggle/resize-observer@3.3.1': {} @@ -10368,6 +10769,7 @@ snapshots: transitivePeerDependencies: - encoding - supports-color + optional: true '@mdx-js/react@2.3.0(react@18.2.0)': dependencies: @@ -10375,6 +10777,22 @@ snapshots: '@types/react': 18.2.20 react: 18.2.0 + '@module-federation/runtime-tools@0.2.3': + dependencies: + '@module-federation/runtime': 0.2.3 + '@module-federation/webpack-bundler-runtime': 0.2.3 + + '@module-federation/runtime@0.2.3': + dependencies: + '@module-federation/sdk': 0.2.3 + + '@module-federation/sdk@0.2.3': {} + + '@module-federation/webpack-bundler-runtime@0.2.3': + dependencies: + '@module-federation/runtime': 0.2.3 + '@module-federation/sdk': 0.2.3 + '@msgpack/msgpack@2.8.0': {} '@mui/base@5.0.0-beta.40(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': @@ -10814,6 +11232,127 @@ snapshots: optionalDependencies: rollup: 2.79.1 + '@rsbuild/core@1.0.1-beta.4': + dependencies: + '@rspack/core': 1.0.0-alpha.5(@swc/helpers@0.5.11) + '@rspack/lite-tapable': 1.0.0-alpha.5 + '@swc/helpers': 0.5.11 + caniuse-lite: 1.0.30001643 + core-js: 3.37.1 + postcss: 8.4.39 + optionalDependencies: + fsevents: 2.3.3 + + '@rsbuild/plugin-node-polyfill@1.0.3(@rsbuild/core@1.0.1-beta.4)': + dependencies: + assert: 2.1.0 + browserify-zlib: 0.2.0 + buffer: 6.0.3 + console-browserify: 1.2.0 + constants-browserify: 1.0.0 + crypto-browserify: 3.12.0 + domain-browser: 5.7.0 + events: 3.3.0 + https-browserify: 1.0.0 + os-browserify: 0.3.0 + path-browserify: 1.0.1 + process: 0.11.10 + punycode: 2.3.1 + querystring-es3: 0.2.1 + readable-stream: 4.5.2 + stream-browserify: 3.0.0 + stream-http: 3.2.0 + string_decoder: 1.3.0 + timers-browserify: 2.0.12 + tty-browserify: 0.0.1 + url: 0.11.3 + util: 0.12.5 + vm-browserify: 1.1.2 + optionalDependencies: + '@rsbuild/core': 1.0.1-beta.4 + + '@rsbuild/plugin-react@1.0.1-beta.4(@rsbuild/core@1.0.1-beta.4)': + dependencies: + '@rsbuild/core': 1.0.1-beta.4 + '@rspack/plugin-react-refresh': 1.0.0-alpha.5(react-refresh@0.14.2) + react-refresh: 0.14.2 + + '@rsbuild/plugin-type-check@1.0.1-beta.4(@rsbuild/core@1.0.1-beta.4)(esbuild@0.19.3)(typescript@5.5.4)': + dependencies: + '@rsbuild/core': 1.0.1-beta.4 + deepmerge: 4.3.1 + fork-ts-checker-webpack-plugin: 9.0.2(typescript@5.5.4)(webpack@5.93.0(esbuild@0.19.3)) + json5: 2.2.3 + reduce-configs: 1.0.0 + webpack: 5.93.0(esbuild@0.19.3) + transitivePeerDependencies: + - '@swc/core' + - esbuild + - typescript + - uglify-js + - webpack-cli + + '@rsbuild/plugin-typed-css-modules@1.0.1(@rsbuild/core@1.0.1-beta.4)': + optionalDependencies: + '@rsbuild/core': 1.0.1-beta.4 + + '@rspack/binding-darwin-arm64@1.0.0-alpha.5': + optional: true + + '@rspack/binding-darwin-x64@1.0.0-alpha.5': + optional: true + + '@rspack/binding-linux-arm64-gnu@1.0.0-alpha.5': + optional: true + + '@rspack/binding-linux-arm64-musl@1.0.0-alpha.5': + optional: true + + '@rspack/binding-linux-x64-gnu@1.0.0-alpha.5': + optional: true + + '@rspack/binding-linux-x64-musl@1.0.0-alpha.5': + optional: true + + '@rspack/binding-win32-arm64-msvc@1.0.0-alpha.5': + optional: true + + '@rspack/binding-win32-ia32-msvc@1.0.0-alpha.5': + optional: true + + '@rspack/binding-win32-x64-msvc@1.0.0-alpha.5': + optional: true + + '@rspack/binding@1.0.0-alpha.5': + optionalDependencies: + '@rspack/binding-darwin-arm64': 1.0.0-alpha.5 + '@rspack/binding-darwin-x64': 1.0.0-alpha.5 + '@rspack/binding-linux-arm64-gnu': 1.0.0-alpha.5 + '@rspack/binding-linux-arm64-musl': 1.0.0-alpha.5 + '@rspack/binding-linux-x64-gnu': 1.0.0-alpha.5 + '@rspack/binding-linux-x64-musl': 1.0.0-alpha.5 + '@rspack/binding-win32-arm64-msvc': 1.0.0-alpha.5 + '@rspack/binding-win32-ia32-msvc': 1.0.0-alpha.5 + '@rspack/binding-win32-x64-msvc': 1.0.0-alpha.5 + + '@rspack/core@1.0.0-alpha.5(@swc/helpers@0.5.11)': + dependencies: + '@module-federation/runtime-tools': 0.2.3 + '@rspack/binding': 1.0.0-alpha.5 + '@rspack/lite-tapable': 1.0.0-alpha.5 + caniuse-lite: 1.0.30001643 + optionalDependencies: + '@swc/helpers': 0.5.11 + + '@rspack/lite-tapable@1.0.0-alpha.5': {} + + '@rspack/plugin-react-refresh@1.0.0-alpha.5(react-refresh@0.14.2)': + dependencies: + error-stack-parser: 2.1.4 + html-entities: 2.5.2 + optionalDependencies: + react-refresh: 0.14.2 + '@rushstack/eslint-patch@1.4.0': {} '@sideway/address@4.1.5': @@ -11091,7 +11630,7 @@ snapshots: - encoding - supports-color - '@storybook/builder-vite@7.4.6(encoding@0.1.13)(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': + '@storybook/builder-vite@7.4.6(encoding@0.1.13)(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.31.3))': dependencies: '@storybook/channels': 7.4.6 '@storybook/client-logger': 7.4.6 @@ -11112,7 +11651,7 @@ snapshots: remark-external-links: 8.0.0 remark-slug: 6.1.0 rollup: 3.29.4 - vite: 4.5.3(@types/node@20.8.0)(terser@5.19.2) + vite: 4.5.3(@types/node@20.8.0)(terser@5.31.3) optionalDependencies: typescript: 5.5.4 transitivePeerDependencies: @@ -11398,19 +11937,19 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@storybook/react-vite@7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@2.79.1)(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': + '@storybook/react-vite@7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@2.79.1)(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.31.3))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.31.3)) '@rollup/pluginutils': 5.0.5(rollup@2.79.1) - '@storybook/builder-vite': 7.4.6(encoding@0.1.13)(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) + '@storybook/builder-vite': 7.4.6(encoding@0.1.13)(typescript@5.5.4)(vite@4.5.3(@types/node@20.8.0)(terser@5.31.3)) '@storybook/react': 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.4) - '@vitejs/plugin-react': 3.1.0(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) + '@vitejs/plugin-react': 3.1.0(vite@4.5.3(@types/node@20.8.0)(terser@5.31.3)) ast-types: 0.14.2 magic-string: 0.30.4 react: 18.2.0 react-docgen: 6.0.0-alpha.3 react-dom: 18.2.0(react@18.2.0) - vite: 4.5.3(@types/node@20.8.0)(terser@5.19.2) + vite: 4.5.3(@types/node@20.8.0)(terser@5.31.3) transitivePeerDependencies: - '@preact/preset-vite' - encoding @@ -11495,6 +12034,10 @@ snapshots: magic-string: 0.25.9 string.prototype.matchall: 4.0.10 + '@swc/helpers@0.5.11': + dependencies: + tslib: 2.6.2 + '@tootallnate/once@2.0.0': {} '@tweenjs/tween.js@18.6.4': {} @@ -11553,6 +12096,8 @@ snapshots: '@types/detect-port@1.3.3': {} + '@types/diff-match-patch@1.0.36': {} + '@types/doctrine@0.0.3': {} '@types/draco3d@1.4.7': {} @@ -11563,12 +12108,24 @@ snapshots: '@types/escodegen@0.0.6': {} + '@types/eslint-scope@3.7.7': + dependencies: + '@types/eslint': 9.6.0 + '@types/estree': 1.0.5 + + '@types/eslint@9.6.0': + dependencies: + '@types/estree': 1.0.5 + '@types/json-schema': 7.0.12 + '@types/estree@0.0.39': {} '@types/estree@0.0.51': {} '@types/estree@1.0.2': {} + '@types/estree@1.0.5': {} + '@types/express-serve-static-core@4.17.37': dependencies: '@types/node': 20.12.8 @@ -11645,7 +12202,8 @@ snapshots: '@types/node': 20.8.0 form-data: 4.0.0 - '@types/node@14.18.56': {} + '@types/node@14.18.56': + optional: true '@types/node@16.18.58': {} @@ -11713,9 +12271,11 @@ snapshots: '@types/mime': 3.0.2 '@types/node': 20.12.8 - '@types/sinonjs__fake-timers@8.1.1': {} + '@types/sinonjs__fake-timers@8.1.1': + optional: true - '@types/sizzle@2.3.3': {} + '@types/sizzle@2.3.3': + optional: true '@types/stats.js@0.17.1': {} @@ -11878,14 +12438,14 @@ snapshots: '@typescript-eslint/types': 6.7.3 eslint-visitor-keys: 3.4.3 - '@vitejs/plugin-react@3.1.0(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': + '@vitejs/plugin-react@3.1.0(vite@4.5.3(@types/node@20.8.0)(terser@5.31.3))': dependencies: '@babel/core': 7.22.11 '@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.22.11) '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.22.11) magic-string: 0.27.0 - react-refresh: 0.14.0 - vite: 4.5.3(@types/node@20.8.0)(terser@5.19.2) + react-refresh: 0.14.2 + vite: 4.5.3(@types/node@20.8.0)(terser@5.31.3) transitivePeerDependencies: - supports-color @@ -11917,6 +12477,82 @@ snapshots: loupe: 2.3.6 pretty-format: 29.7.0 + '@webassemblyjs/ast@1.12.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + + '@webassemblyjs/floating-point-hex-parser@1.11.6': {} + + '@webassemblyjs/helper-api-error@1.11.6': {} + + '@webassemblyjs/helper-buffer@1.12.1': {} + + '@webassemblyjs/helper-numbers@1.11.6': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.11.6 + '@webassemblyjs/helper-api-error': 1.11.6 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.11.6': {} + + '@webassemblyjs/helper-wasm-section@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/wasm-gen': 1.12.1 + + '@webassemblyjs/ieee754@1.11.6': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.11.6': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.11.6': {} + + '@webassemblyjs/wasm-edit@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/helper-wasm-section': 1.12.1 + '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/wasm-opt': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + '@webassemblyjs/wast-printer': 1.12.1 + + '@webassemblyjs/wasm-gen@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ieee754': 1.11.6 + '@webassemblyjs/leb128': 1.11.6 + '@webassemblyjs/utf8': 1.11.6 + + '@webassemblyjs/wasm-opt@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + + '@webassemblyjs/wasm-parser@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-api-error': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ieee754': 1.11.6 + '@webassemblyjs/leb128': 1.11.6 + '@webassemblyjs/utf8': 1.11.6 + + '@webassemblyjs/wast-printer@1.12.1': + dependencies: + '@webassemblyjs/ast': 1.12.1 + '@xtuc/long': 4.2.2 + '@xboxreplay/errors@0.1.0': {} '@xboxreplay/xboxlive-auth@3.3.3(debug@4.3.4)': @@ -11966,6 +12602,10 @@ snapshots: '@xobotyi/scrollbar-width@1.9.5': {} + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + '@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15(esbuild@0.18.20)': dependencies: esbuild: 0.18.20 @@ -11981,7 +12621,7 @@ snapshots: '@types/emscripten': 1.39.8 tslib: 1.14.1 - '@zardoy/flying-squid@0.0.33(encoding@0.1.13)': + '@zardoy/flying-squid@0.0.34(encoding@0.1.13)': dependencies: '@tootallnate/once': 2.0.0 change-case: 4.1.2 @@ -11992,7 +12632,7 @@ snapshots: flatmap: 0.0.3 long: 5.2.3 minecraft-data: 3.65.0 - minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13) + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/7057ad979b416192ada235f2f4e3b5eb26af5fa1(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13) mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 @@ -12033,7 +12673,8 @@ snapshots: Base64@0.2.1: {} - abbrev@1.1.1: {} + abbrev@1.1.1: + optional: true abort-controller@3.0.0: dependencies: @@ -12044,6 +12685,10 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + acorn-import-attributes@1.9.5(acorn@8.10.0): + dependencies: + acorn: 8.10.0 + acorn-jsx@5.3.2(acorn@7.4.1): dependencies: acorn: 7.4.1 @@ -12066,7 +12711,8 @@ snapshots: aes-js@3.1.2: {} - after@0.8.2: {} + after@0.8.2: + optional: true agent-base@5.1.1: {} @@ -12075,6 +12721,7 @@ snapshots: debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color + optional: true agent-base@7.1.0: dependencies: @@ -12092,6 +12739,10 @@ snapshots: clean-stack: 2.2.0 indent-string: 4.0.0 + ajv-keywords@3.5.2(ajv@6.12.6): + dependencies: + ajv: 6.12.6 + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -12108,11 +12759,13 @@ snapshots: animejs@3.2.1: {} - ansi-colors@4.1.3: {} + ansi-colors@4.1.3: + optional: true ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 + optional: true ansi-regex@5.0.1: {} @@ -12130,7 +12783,8 @@ snapshots: ansi-styles@6.2.1: {} - any-base@1.1.0: {} + any-base@1.1.0: + optional: true any-promise@1.3.0: {} @@ -12141,14 +12795,17 @@ snapshots: app-root-dir@1.0.2: {} - aproba@2.0.0: {} + aproba@2.0.0: + optional: true - arch@2.2.0: {} + arch@2.2.0: + optional: true are-we-there-yet@2.0.0: dependencies: delegates: 1.0.0 readable-stream: 3.6.2 + optional: true are-we-there-yet@3.0.1: dependencies: @@ -12256,7 +12913,8 @@ snapshots: is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 - arraybuffer.slice@0.0.7: {} + arraybuffer.slice@0.0.7: + optional: true arrify@1.0.1: {} @@ -12273,7 +12931,8 @@ snapshots: dependencies: safer-buffer: 2.1.2 - assert-plus@1.0.0: {} + assert-plus@1.0.0: + optional: true assert@2.0.0: dependencies: @@ -12282,6 +12941,14 @@ snapshots: object-is: 1.1.5 util: 0.12.5 + assert@2.1.0: + dependencies: + call-bind: 1.0.7 + is-nan: 1.3.2 + object-is: 1.1.5 + object.assign: 4.1.5 + util: 0.12.5 + assertion-error@1.1.0: {} ast-types@0.14.2: @@ -12296,7 +12963,8 @@ snapshots: dependencies: tslib: 2.6.2 - astral-regex@2.0.0: {} + astral-regex@2.0.0: + optional: true async-limiter@1.0.1: {} @@ -12316,9 +12984,11 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 - aws-sign2@0.7.0: {} + aws-sign2@0.7.0: + optional: true - aws4@1.12.0: {} + aws4@1.12.0: + optional: true axios@0.21.4(debug@4.3.4): dependencies: @@ -12378,13 +13048,15 @@ snapshots: transitivePeerDependencies: - supports-color - backo2@1.0.2: {} + backo2@1.0.2: + optional: true bail@2.0.2: {} balanced-match@1.0.2: {} - base64-arraybuffer@0.1.4: {} + base64-arraybuffer@0.1.4: + optional: true base64-js@1.5.1: {} @@ -12397,6 +13069,7 @@ snapshots: bcrypt-pbkdf@1.0.2: dependencies: tweetnacl: 0.14.5 + optional: true better-opn@3.0.2: dependencies: @@ -12416,17 +13089,21 @@ snapshots: bl@4.1.0: dependencies: - buffer: 5.7.1 + buffer: 6.0.3 inherits: 2.0.4 readable-stream: 3.6.2 - blob-util@2.0.2: {} + blob-util@2.0.2: + optional: true - blob@0.0.5: {} + blob@0.0.5: + optional: true - bluebird@3.7.2: {} + bluebird@3.7.2: + optional: true - bmp-js@0.1.0: {} + bmp-js@0.1.0: + optional: true bn.js@4.12.0: {} @@ -12544,11 +13221,18 @@ snapshots: browserslist@4.21.10: dependencies: - caniuse-lite: 1.0.30001524 + caniuse-lite: 1.0.30001643 electron-to-chromium: 1.4.504 node-releases: 2.0.13 update-browserslist-db: 1.0.11(browserslist@4.21.10) + browserslist@4.23.2: + dependencies: + caniuse-lite: 1.0.30001643 + electron-to-chromium: 1.5.0 + node-releases: 2.0.18 + update-browserslist-db: 1.1.0(browserslist@4.23.2) + bser@2.1.1: dependencies: node-int64: 0.4.0 @@ -12557,7 +13241,8 @@ snapshots: buffer-equal-constant-time@1.0.1: {} - buffer-equal@0.0.1: {} + buffer-equal@0.0.1: + optional: true buffer-equal@1.0.1: {} @@ -12565,11 +13250,6 @@ snapshots: buffer-xor@1.0.3: {} - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - buffer@6.0.3: dependencies: base64-js: 1.5.1 @@ -12577,6 +13257,8 @@ snapshots: builtin-modules@3.3.0: {} + builtin-status-codes@3.0.0: {} + bytes@3.0.0: {} bytes@3.1.2: {} @@ -12622,7 +13304,8 @@ snapshots: - bluebird optional: true - cachedir@2.4.0: {} + cachedir@2.4.0: + optional: true call-bind@1.0.2: dependencies: @@ -12655,7 +13338,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001524: {} + caniuse-lite@1.0.30001643: {} canvas@2.11.2(encoding@0.1.13): dependencies: @@ -12665,6 +13348,7 @@ snapshots: transitivePeerDependencies: - encoding - supports-color + optional: true capital-case@1.0.4: dependencies: @@ -12672,7 +13356,8 @@ snapshots: tslib: 2.6.2 upper-case-first: 2.0.2 - caseless@0.12.0: {} + caseless@0.12.0: + optional: true cbor-extract@2.2.0: dependencies: @@ -12734,7 +13419,8 @@ snapshots: dependencies: get-func-name: 2.0.2 - check-more-types@2.24.0: {} + check-more-types@2.24.0: + optional: true chokidar@3.5.3: dependencies: @@ -12752,6 +13438,8 @@ snapshots: chownr@2.0.0: {} + chrome-trace-event@1.0.4: {} + ci-info@3.8.0: {} cipher-base@1.0.4: @@ -12783,6 +13471,7 @@ snapshots: dependencies: slice-ansi: 3.0.0 string-width: 4.2.3 + optional: true cliui@7.0.4: dependencies: @@ -12808,8 +13497,6 @@ snapshots: clsx@2.1.1: {} - color-convert@0.5.3: {} - color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -12818,8 +13505,6 @@ snapshots: dependencies: color-name: 1.1.4 - color-diff@1.4.0: {} - color-name@1.1.3: {} color-name@1.1.4: {} @@ -12829,7 +13514,8 @@ snapshots: color-name: 1.1.4 simple-swizzle: 0.2.2 - color-support@1.1.3: {} + color-support@1.1.3: + optional: true color@4.2.3: dependencies: @@ -12846,7 +13532,8 @@ snapshots: commander@2.20.3: {} - commander@5.1.0: {} + commander@5.1.0: + optional: true commander@6.2.1: {} @@ -12854,13 +13541,17 @@ snapshots: commondir@1.0.1: {} - component-bind@1.0.0: {} + component-bind@1.0.0: + optional: true - component-emitter@1.2.1: {} + component-emitter@1.2.1: + optional: true - component-emitter@1.3.0: {} + component-emitter@1.3.0: + optional: true - component-inherit@0.0.3: {} + component-inherit@0.0.3: + optional: true compressible@2.0.18: dependencies: @@ -12889,7 +13580,10 @@ snapshots: confusing-browser-globals@1.0.11: {} - console-control-strings@1.1.0: {} + console-browserify@1.2.0: {} + + console-control-strings@1.1.0: + optional: true constant-case@3.0.4: dependencies: @@ -12934,9 +13628,13 @@ snapshots: dependencies: browserslist: 4.21.10 - core-js@3.32.1: {} + core-js@3.32.1: + optional: true + + core-js@3.37.1: {} - core-util-is@1.0.2: {} + core-util-is@1.0.2: + optional: true core-util-is@1.0.3: {} @@ -12955,6 +13653,15 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 + cosmiconfig@8.3.6(typescript@5.5.4): + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.5.4 + create-ecdh@4.0.4: dependencies: bn.js: 4.12.0 @@ -13054,6 +13761,7 @@ snapshots: - bufferutil - supports-color - utf-8-validate + optional: true cypress@10.11.0: dependencies: @@ -13065,7 +13773,7 @@ snapshots: arch: 2.2.0 blob-util: 2.0.2 bluebird: 3.7.2 - buffer: 5.7.1 + buffer: 6.0.3 cachedir: 2.4.0 chalk: 4.1.2 check-more-types: 2.24.0 @@ -13099,10 +13807,12 @@ snapshots: tmp: 0.2.1 untildify: 4.0.0 yauzl: 2.10.0 + optional: true dashdash@1.14.1: dependencies: assert-plus: 1.0.0 + optional: true data-view-buffer@1.0.1: dependencies: @@ -13122,7 +13832,8 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.1 - dayjs@1.11.9: {} + dayjs@1.11.9: + optional: true debounce@1.2.1: {} @@ -13133,6 +13844,7 @@ snapshots: debug@3.1.0: dependencies: ms: 2.0.0 + optional: true debug@3.2.7(supports-color@8.1.1): dependencies: @@ -13143,6 +13855,7 @@ snapshots: debug@4.1.1: dependencies: ms: 2.1.3 + optional: true debug@4.3.4(supports-color@8.1.1): dependencies: @@ -13166,6 +13879,7 @@ snapshots: decompress-response@4.2.1: dependencies: mimic-response: 2.1.0 + optional: true decompress-response@6.0.0: dependencies: @@ -13225,7 +13939,8 @@ snapshots: delayed-stream@1.0.0: {} - delegates@1.0.0: {} + delegates@1.0.0: + optional: true depd@2.0.0: {} @@ -13277,6 +13992,8 @@ snapshots: random-seed: 0.3.0 vec3: 0.1.8 + diff-match-patch@1.0.5: {} + diff-sequences@29.6.3: {} diff2html@2.12.2: @@ -13285,10 +14002,13 @@ snapshots: hogan.js: 3.0.2 merge: 1.2.1 whatwg-fetch: 3.6.18 + optional: true - diff@2.2.3: {} + diff@2.2.3: + optional: true - diff@4.0.2: {} + diff@4.0.2: + optional: true diffie-hellman@5.0.3: dependencies: @@ -13321,7 +14041,10 @@ snapshots: domhandler: 5.0.3 entities: 4.5.0 - dom-walk@0.1.2: {} + dom-walk@0.1.2: + optional: true + + domain-browser@5.7.0: {} domelementtype@2.3.0: {} @@ -13361,6 +14084,7 @@ snapshots: dependencies: jsbn: 0.1.1 safer-buffer: 2.1.2 + optional: true ecdsa-sig-formatter@1.0.11: dependencies: @@ -13374,6 +14098,8 @@ snapshots: electron-to-chromium@1.4.504: {} + electron-to-chromium@1.5.0: {} + elliptic@6.5.4: dependencies: bn.js: 4.12.0 @@ -13420,6 +14146,7 @@ snapshots: - bufferutil - supports-color - utf-8-validate + optional: true engine.io-client@6.5.2: dependencies: @@ -13440,6 +14167,7 @@ snapshots: base64-arraybuffer: 0.1.4 blob: 0.0.5 has-binary2: 1.0.3 + optional: true engine.io-parser@5.2.1: {} @@ -13455,6 +14183,7 @@ snapshots: - bufferutil - supports-color - utf-8-validate + optional: true engine.io@6.5.3: dependencies: @@ -13473,10 +14202,16 @@ snapshots: - supports-color - utf-8-validate + enhanced-resolve@5.17.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + optional: true entities@4.5.0: {} @@ -13614,6 +14349,8 @@ snapshots: es-module-lexer@0.9.3: {} + es-module-lexer@1.5.4: {} + es-object-atoms@1.0.0: dependencies: es-errors: 1.3.0 @@ -13745,6 +14482,8 @@ snapshots: escalade@3.1.1: {} + escalade@3.1.2: {} + escape-html@1.0.3: {} escape-string-regexp@1.0.5: {} @@ -13918,6 +14657,11 @@ snapshots: semver: 7.5.4 strip-indent: 3.0.0 + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + eslint-scope@7.2.2: dependencies: esrecurse: 4.3.0 @@ -13989,6 +14733,8 @@ snapshots: dependencies: estraverse: 5.3.0 + estraverse@4.3.0: {} + estraverse@5.3.0: {} estree-to-babel@3.2.1: @@ -14009,7 +14755,8 @@ snapshots: event-target-shim@5.0.1: {} - eventemitter2@6.4.7: {} + eventemitter2@6.4.7: + optional: true eventemitter3@4.0.7: {} @@ -14031,6 +14778,7 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 strip-final-newline: 2.0.0 + optional: true execa@5.1.1: dependencies: @@ -14047,8 +14795,10 @@ snapshots: executable@4.1.1: dependencies: pify: 2.3.0 + optional: true - exif-parser@0.1.12: {} + exif-parser@0.1.12: + optional: true exit-hook@2.2.1: {} @@ -14122,7 +14872,8 @@ snapshots: transitivePeerDependencies: - supports-color - extsprintf@1.3.0: {} + extsprintf@1.3.0: + optional: true fast-deep-equal@3.1.3: {} @@ -14163,6 +14914,7 @@ snapshots: figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 + optional: true file-entry-cache@6.0.1: dependencies: @@ -14173,7 +14925,8 @@ snapshots: fs-extra: 11.1.1 ramda: 0.29.0 - file-type@9.0.0: {} + file-type@9.0.0: + optional: true file-uri-to-path@1.0.0: optional: true @@ -14262,13 +15015,32 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 - forever-agent@0.6.1: {} + forever-agent@0.6.1: + optional: true + + fork-ts-checker-webpack-plugin@9.0.2(typescript@5.5.4)(webpack@5.93.0(esbuild@0.19.3)): + dependencies: + '@babel/code-frame': 7.22.13 + chalk: 4.1.2 + chokidar: 3.5.3 + cosmiconfig: 8.3.6(typescript@5.5.4) + deepmerge: 4.3.1 + fs-extra: 10.1.0 + memfs: 3.5.3 + minimatch: 3.1.2 + node-abort-controller: 3.1.1 + schema-utils: 3.3.0 + semver: 7.6.0 + tapable: 2.2.1 + typescript: 5.5.4 + webpack: 5.93.0(esbuild@0.19.3) form-data@2.3.3: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 + optional: true form-data@4.0.0: dependencies: @@ -14282,23 +15054,24 @@ snapshots: fs-constants@1.0.0: {} - fs-extra@11.1.1: + fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.0 - fs-extra@7.0.1: + fs-extra@11.1.1: dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.0 - fs-extra@8.1.0: + fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 jsonfile: 4.0.0 universalify: 0.1.2 + optional: true fs-extra@9.1.0: dependencies: @@ -14311,6 +15084,8 @@ snapshots: dependencies: minipass: 3.3.6 + fs-monkey@1.0.6: {} + fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -14340,6 +15115,7 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 wide-align: 1.1.5 + optional: true gauge@4.0.4: dependencies: @@ -14408,10 +15184,12 @@ snapshots: getos@3.2.1: dependencies: async: 3.2.5 + optional: true getpass@0.1.7: dependencies: assert-plus: 1.0.0 + optional: true giget@1.1.3: dependencies: @@ -14487,11 +15265,13 @@ snapshots: global-dirs@3.0.1: dependencies: ini: 2.0.0 + optional: true global@4.4.0: dependencies: min-document: 2.19.0 process: 0.11.10 + optional: true globals@11.12.0: {} @@ -14559,8 +15339,10 @@ snapshots: has-binary2@1.0.3: dependencies: isarray: 2.0.1 + optional: true - has-cors@1.1.0: {} + has-cors@1.1.0: + optional: true has-flag@3.0.0: {} @@ -14588,7 +15370,8 @@ snapshots: dependencies: has-symbols: 1.0.3 - has-unicode@2.0.1: {} + has-unicode@2.0.1: + optional: true has@1.0.3: dependencies: @@ -14630,6 +15413,7 @@ snapshots: dependencies: mkdirp: 0.3.0 nopt: 1.0.10 + optional: true hosted-git-info@2.8.9: {} @@ -14641,6 +15425,8 @@ snapshots: dependencies: whatwg-encoding: 2.0.0 + html-entities@2.5.2: {} + html-escaper@2.0.2: {} html-tags@3.3.1: {} @@ -14701,6 +15487,7 @@ snapshots: assert-plus: 1.0.0 jsprim: 2.0.2 sshpk: 1.17.0 + optional: true https-browserify@1.0.0: {} @@ -14717,6 +15504,7 @@ snapshots: debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color + optional: true https-proxy-agent@7.0.2: dependencies: @@ -14725,7 +15513,8 @@ snapshots: transitivePeerDependencies: - supports-color - human-signals@1.1.1: {} + human-signals@1.1.1: + optional: true human-signals@2.1.0: {} @@ -14750,7 +15539,8 @@ snapshots: ignore@5.2.4: {} - image-size@0.7.5: {} + image-size@0.7.5: + optional: true immediate@3.0.6: {} @@ -14767,7 +15557,8 @@ snapshots: indent-string@5.0.0: {} - indexof@0.0.1: {} + indexof@0.0.1: + optional: true infer-owner@1.0.4: optional: true @@ -14781,7 +15572,8 @@ snapshots: ini@1.3.8: {} - ini@2.0.0: {} + ini@2.0.0: + optional: true inline-style-prefixer@6.0.4: dependencies: @@ -14856,6 +15648,7 @@ snapshots: is-ci@3.0.1: dependencies: ci-info: 3.8.0 + optional: true is-core-module@2.13.0: dependencies: @@ -14885,7 +15678,8 @@ snapshots: is-fullwidth-code-point@3.0.0: {} - is-function@1.0.2: {} + is-function@1.0.2: + optional: true is-generator-function@1.0.10: dependencies: @@ -14901,6 +15695,7 @@ snapshots: dependencies: global-dirs: 3.0.1 is-path-inside: 3.0.3 + optional: true is-interactive@1.0.0: {} @@ -14977,7 +15772,8 @@ snapshots: dependencies: which-typed-array: 1.1.15 - is-typedarray@1.0.0: {} + is-typedarray@1.0.0: + optional: true is-unicode-supported@0.1.0: {} @@ -15001,7 +15797,8 @@ snapshots: isarray@1.0.0: {} - isarray@2.0.1: {} + isarray@2.0.1: + optional: true isarray@2.0.5: {} @@ -15009,7 +15806,8 @@ snapshots: isobject@3.0.1: {} - isstream@0.1.2: {} + isstream@0.1.2: + optional: true istanbul-lib-coverage@3.2.0: {} @@ -15088,6 +15886,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 7.2.0 + jest-worker@27.5.1: + dependencies: + '@types/node': 20.12.8 + merge-stream: 2.0.0 + supports-color: 8.1.1 + jest-worker@29.7.0: dependencies: '@types/node': 20.12.8 @@ -15103,6 +15907,7 @@ snapshots: '@jimp/types': 0.10.3(@jimp/custom@0.10.3) core-js: 3.32.1 regenerator-runtime: 0.13.11 + optional: true joi@17.13.1: dependencies: @@ -15114,14 +15919,14 @@ snapshots: jose@4.15.5: {} - jpeg-js@0.3.7: {} + jpeg-js@0.3.7: + optional: true - js-base64@2.6.4: {} + js-base64@2.6.4: + optional: true js-cookie@2.2.1: {} - js-graph-algorithms@1.0.18: {} - js-tokens@4.0.0: {} js-yaml@3.14.1: @@ -15133,7 +15938,8 @@ snapshots: dependencies: argparse: 2.0.1 - jsbn@0.1.1: {} + jsbn@0.1.1: + optional: true jscodeshift@0.14.0(@babel/preset-env@7.22.10(@babel/core@7.22.11)): dependencies: @@ -15193,6 +15999,7 @@ snapshots: jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 + optional: true jsonfile@6.1.0: dependencies: @@ -15221,6 +16028,7 @@ snapshots: extsprintf: 1.3.0 json-schema: 0.4.0 verror: 1.10.0 + optional: true jsx-ast-utils@3.3.5: dependencies: @@ -15255,7 +16063,8 @@ snapshots: kleur@3.0.3: {} - lazy-ass@1.6.0: {} + lazy-ass@1.6.0: + optional: true lazy-universal-dotenv@4.0.0: dependencies: @@ -15296,6 +16105,7 @@ snapshots: wrap-ansi: 7.0.0 optionalDependencies: enquirer: 2.4.1 + optional: true load-bmfont@1.4.1: dependencies: @@ -15307,6 +16117,7 @@ snapshots: phin: 2.9.3 xhr: 2.6.0 xtend: 4.0.2 + optional: true load-json-file@4.0.0: dependencies: @@ -15315,6 +16126,8 @@ snapshots: pify: 3.0.0 strip-bom: 3.0.0 + loader-runner@4.3.0: {} + local-pkg@0.4.3: {} locate-path@3.0.0: @@ -15371,21 +16184,12 @@ snapshots: cli-cursor: 3.1.0 slice-ansi: 4.0.0 wrap-ansi: 6.2.0 + optional: true long@5.2.3: {} longest-streak@3.1.0: {} - looks-same@8.2.3: - dependencies: - color-diff: 1.4.0 - fs-extra: 8.1.0 - js-graph-algorithms: 1.0.18 - lodash: 4.17.21 - nested-error-stacks: 2.1.1 - parse-color: 1.0.0 - sharp: 0.30.7 - loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -15484,6 +16288,8 @@ snapshots: dependencies: react: 18.2.0 + mc-assets@0.2.5: {} + md5-file@4.0.0: {} md5.js@1.3.5: @@ -15541,6 +16347,10 @@ snapshots: media-typer@0.3.0: {} + memfs@3.5.3: + dependencies: + fs-monkey: 1.0.6 + memoizerific@1.11.3: dependencies: map-or-similar: 1.5.0 @@ -15568,7 +16378,8 @@ snapshots: merge2@1.4.1: {} - merge@1.2.1: {} + merge@1.2.1: + optional: true meshoptimizer@0.18.1: {} @@ -15729,18 +16540,18 @@ snapshots: mimic-fn@2.1.0: {} - mimic-response@2.1.0: {} + mimic-response@2.1.0: + optional: true mimic-response@3.1.0: {} min-document@2.19.0: dependencies: dom-walk: 0.1.2 + optional: true min-indent@1.0.1: {} - minecraft-assets@1.12.2: {} - minecraft-data@3.65.0: {} minecraft-folder-path@1.2.0: {} @@ -15777,6 +16588,31 @@ snapshots: - encoding - supports-color + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/7057ad979b416192ada235f2f4e3b5eb26af5fa1(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13): + dependencies: + '@types/readable-stream': 4.0.12 + aes-js: 3.1.2 + buffer-equal: 1.0.1 + debug: 4.3.4(supports-color@8.1.1) + endian-toggle: 0.0.0 + lodash.get: 4.4.2 + lodash.merge: 4.6.2 + minecraft-data: 3.65.0 + minecraft-folder-path: 1.2.0 + node-fetch: 2.7.0(encoding@0.1.13) + node-rsa: 0.4.2 + prismarine-auth: 2.4.2(encoding@0.1.13) + prismarine-chat: 1.10.1 + prismarine-nbt: 2.5.0 + prismarine-realms: 1.3.2(encoding@0.1.13) + protodef: 1.15.0 + readable-stream: 4.5.2 + uuid-1345: 1.0.2 + yggdrasil: 1.7.0(encoding@0.1.13) + transitivePeerDependencies: + - encoding + - supports-color + minecraft-wrap@1.5.1(encoding@0.1.13): dependencies: debug: 4.3.4(supports-color@8.1.1) @@ -15800,7 +16636,7 @@ snapshots: detect-collisions: 7.0.5 vec3: 0.1.8 - mineflayer-item-map-downloader@https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7(encoding@0.1.13): + mineflayer-item-map-downloader@https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/642fd4f7023a98a96da4caf8f993f8e19361a1e7(patch_hash=bck55yjvd4wrgz46x7o4vfur5q)(encoding@0.1.13): dependencies: mineflayer: 4.20.1(encoding@0.1.13) sharp: 0.30.7 @@ -15811,7 +16647,7 @@ snapshots: mineflayer-pathfinder@2.4.4: dependencies: minecraft-data: 3.65.0 - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/a69b66ab1e4be6b67f25a5a6db15e0ad39e11819 prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.2.1 @@ -15823,7 +16659,7 @@ snapshots: minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/a69b66ab1e4be6b67f25a5a6db15e0ad39e11819 prismarine-chat: 1.10.1 prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-entity: 2.3.1 @@ -15846,7 +16682,7 @@ snapshots: minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/a69b66ab1e4be6b67f25a5a6db15e0ad39e11819 prismarine-chat: 1.10.1 prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-entity: 2.3.1 @@ -15932,7 +16768,8 @@ snapshots: mkdirp-classic@0.5.3: {} - mkdirp@0.3.0: {} + mkdirp@0.3.0: + optional: true mkdirp@0.5.6: dependencies: @@ -15969,7 +16806,8 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nan@2.18.0: {} + nan@2.18.0: + optional: true nano-css@5.3.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: @@ -16005,8 +16843,6 @@ snapshots: neo-async@2.6.2: {} - nested-error-stacks@2.1.1: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/d3f7f77d8ac751bc171173bba639086c931a62f7: dependencies: body-parser: 1.20.2 @@ -16028,6 +16864,8 @@ snapshots: dependencies: semver: 7.6.0 + node-abort-controller@3.1.1: {} + node-addon-api@5.1.0: {} node-canvas-webgl@0.3.0(encoding@0.1.13): @@ -16086,6 +16924,8 @@ snapshots: node-releases@2.0.13: {} + node-releases@2.0.18: {} + node-rsa@0.4.2: dependencies: asn1: 0.2.3 @@ -16097,10 +16937,12 @@ snapshots: nopt@1.0.10: dependencies: abbrev: 1.1.1 + optional: true nopt@5.0.0: dependencies: abbrev: 1.1.1 + optional: true nopt@6.0.0: dependencies: @@ -16145,6 +16987,7 @@ snapshots: console-control-strings: 1.1.0 gauge: 3.0.2 set-blocking: 2.0.0 + optional: true npmlog@6.0.2: dependencies: @@ -16216,7 +17059,8 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 - omggif@1.0.10: {} + omggif@1.0.10: + optional: true on-finished@2.4.1: dependencies: @@ -16265,7 +17109,8 @@ snapshots: os-browserify@0.3.0: {} - ospath@1.2.2: {} + ospath@1.2.2: + optional: true p-limit@2.3.0: dependencies: @@ -16318,20 +17163,20 @@ snapshots: pbkdf2: 3.1.2 safe-buffer: 5.2.1 - parse-bmfont-ascii@1.0.6: {} + parse-bmfont-ascii@1.0.6: + optional: true - parse-bmfont-binary@1.0.6: {} + parse-bmfont-binary@1.0.6: + optional: true parse-bmfont-xml@1.1.4: dependencies: xml-parse-from-string: 1.0.1 xml2js: 0.4.23 + optional: true - parse-color@1.0.0: - dependencies: - color-convert: 0.5.3 - - parse-headers@2.0.5: {} + parse-headers@2.0.5: + optional: true parse-json@4.0.0: dependencies: @@ -16345,9 +17190,11 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - parseqs@0.0.6: {} + parseqs@0.0.6: + optional: true - parseuri@0.0.6: {} + parseuri@0.0.6: + optional: true parseurl@1.3.3: {} @@ -16425,17 +17272,22 @@ snapshots: pend@1.2.0: {} - performance-now@2.1.0: {} + performance-now@2.1.0: + optional: true - phin@2.9.3: {} + phin@2.9.3: + optional: true picocolors@1.0.0: {} + picocolors@1.0.1: {} + picomatch@2.3.1: {} pidtree@0.3.1: {} - pify@2.3.0: {} + pify@2.3.0: + optional: true pify@3.0.0: {} @@ -16448,6 +17300,7 @@ snapshots: pixelmatch@4.0.2: dependencies: pngjs: 3.4.0 + optional: true pkg-dir@3.0.0: dependencies: @@ -16469,7 +17322,8 @@ snapshots: pluralize@8.0.0: {} - pngjs@3.4.0: {} + pngjs@3.4.0: + optional: true polished@4.2.2: dependencies: @@ -16493,10 +17347,10 @@ snapshots: picocolors: 1.0.0 source-map-js: 1.0.2 - postcss@8.4.38: + postcss@8.4.39: dependencies: nanoid: 3.3.7 - picocolors: 1.0.0 + picocolors: 1.0.1 source-map-js: 1.2.0 potpack@1.0.2: {} @@ -16518,7 +17372,8 @@ snapshots: prelude-ls@1.2.1: {} - prettier@1.19.1: {} + prettier@1.19.1: + optional: true prettier@2.8.8: {} @@ -16552,7 +17407,7 @@ snapshots: minecraft-data: 3.65.0 prismarine-registry: 1.7.0 - prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8: + prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/a69b66ab1e4be6b67f25a5a6db15e0ad39e11819: dependencies: minecraft-data: 3.65.0 prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) @@ -16570,7 +17425,7 @@ snapshots: prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/a69b66ab1e4be6b67f25a5a6db15e0ad39e11819 prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 smart-buffer: 4.2.0 @@ -16583,7 +17438,7 @@ snapshots: prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/cea0b6c792d7dcbb69dfd20fa48be5fd60ce83ef(minecraft-data@3.65.0): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/a69b66ab1e4be6b67f25a5a6db15e0ad39e11819 prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 smart-buffer: 4.2.0 @@ -16621,7 +17476,7 @@ snapshots: prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/0228b5252f48a0d6ad7f36d7189851c427fbe8c4(minecraft-data@3.65.0): dependencies: - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/a69b66ab1e4be6b67f25a5a6db15e0ad39e11819 prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-nbt: 2.5.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 @@ -16650,7 +17505,7 @@ snapshots: prismarine-schematic@1.2.3: dependencies: minecraft-data: 3.65.0 - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/a69b66ab1e4be6b67f25a5a6db15e0ad39e11819 prismarine-nbt: 2.2.1 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 vec3: 0.1.8 @@ -16803,7 +17658,8 @@ snapshots: proxy-from-env@1.1.0: {} - psl@1.9.0: {} + psl@1.9.0: + optional: true public-encrypt@4.0.3: dependencies: @@ -16832,6 +17688,8 @@ snapshots: punycode.js@2.3.1: {} + punycode@1.4.1: {} + punycode@2.3.0: {} punycode@2.3.1: {} @@ -16860,6 +17718,7 @@ snapshots: qs@6.10.4: dependencies: side-channel: 1.0.5 + optional: true qs@6.11.0: dependencies: @@ -16869,7 +17728,10 @@ snapshots: dependencies: side-channel: 1.0.4 - querystringify@2.2.0: {} + querystring-es3@0.2.1: {} + + querystringify@2.2.0: + optional: true queue-microtask@1.2.3: {} @@ -17000,7 +17862,7 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-refresh@0.14.0: {} + react-refresh@0.14.2: {} react-remove-scroll-bar@2.3.4(@types/react@18.2.20)(react@18.2.0): dependencies: @@ -17163,6 +18025,10 @@ snapshots: indent-string: 5.0.0 strip-indent: 4.0.0 + reduce-configs@1.0.0: + dependencies: + browserslist: 4.23.2 + reflect.getprototypeof@1.0.6: dependencies: call-bind: 1.0.7 @@ -17179,7 +18045,8 @@ snapshots: regenerate@1.4.2: {} - regenerator-runtime@0.13.11: {} + regenerator-runtime@0.13.11: + optional: true regenerator-runtime@0.14.0: {} @@ -17262,6 +18129,7 @@ snapshots: request-progress@3.0.0: dependencies: throttleit: 1.0.0 + optional: true require-directory@2.1.1: {} @@ -17301,7 +18169,8 @@ snapshots: reusify@1.0.4: {} - rfdc@1.3.0: {} + rfdc@1.3.0: + optional: true rimraf@2.6.3: dependencies: @@ -17392,12 +18261,19 @@ snapshots: sat@0.9.0: {} - sax@1.3.0: {} + sax@1.3.0: + optional: true scheduler@0.23.0: dependencies: loose-envify: 1.4.0 + schema-utils@3.3.0: + dependencies: + '@types/json-schema': 7.0.12 + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + screenfull@5.2.0: {} sdp@3.2.0: {} @@ -17444,6 +18320,10 @@ snapshots: dependencies: randombytes: 2.1.0 + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + serve-static@1.15.0: dependencies: encodeurl: 1.0.2 @@ -17453,7 +18333,8 @@ snapshots: transitivePeerDependencies: - supports-color - set-blocking@2.0.0: {} + set-blocking@2.0.0: + optional: true set-function-length@1.2.1: dependencies: @@ -17529,6 +18410,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.2.4 object-inspect: 1.13.1 + optional: true side-channel@1.0.6: dependencies: @@ -17550,6 +18432,7 @@ snapshots: decompress-response: 4.2.1 once: 1.4.0 simple-concat: 1.0.1 + optional: true simple-get@4.0.1: dependencies: @@ -17582,12 +18465,14 @@ snapshots: ansi-styles: 4.3.0 astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 + optional: true slice-ansi@4.0.0: dependencies: ansi-styles: 4.3.0 astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 + optional: true smart-buffer@4.2.0: {} @@ -17596,7 +18481,8 @@ snapshots: dot-case: 3.0.4 tslib: 2.6.2 - socket.io-adapter@1.1.2: {} + socket.io-adapter@1.1.2: + optional: true socket.io-adapter@2.5.2: dependencies: @@ -17622,6 +18508,7 @@ snapshots: - bufferutil - supports-color - utf-8-validate + optional: true socket.io-client@4.7.2: dependencies: @@ -17641,6 +18528,7 @@ snapshots: isarray: 2.0.1 transitivePeerDependencies: - supports-color + optional: true socket.io-parser@3.4.3: dependencies: @@ -17649,6 +18537,7 @@ snapshots: isarray: 2.0.1 transitivePeerDependencies: - supports-color + optional: true socket.io-parser@4.2.4: dependencies: @@ -17669,6 +18558,7 @@ snapshots: - bufferutil - supports-color - utf-8-validate + optional: true socket.io@4.7.2: dependencies: @@ -17749,6 +18639,7 @@ snapshots: jsbn: 0.1.1 safer-buffer: 2.1.2 tweetnacl: 0.14.5 + optional: true ssri@9.0.1: dependencies: @@ -17798,6 +18689,13 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + stream-http@3.2.0: + dependencies: + builtin-status-codes: 3.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + xtend: 4.0.2 + stream-shift@1.0.1: {} strict-event-emitter-types@2.0.0: {} @@ -17954,6 +18852,8 @@ snapshots: tabbable@6.2.0: {} + tapable@2.2.1: {} + tar-fs@2.1.1: dependencies: chownr: 1.1.4 @@ -18003,6 +18903,17 @@ snapshots: type-fest: 0.16.0 unique-string: 2.0.0 + terser-webpack-plugin@5.3.10(esbuild@0.19.3)(webpack@5.93.0(esbuild@0.19.3)): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 3.3.0 + serialize-javascript: 6.0.2 + terser: 5.31.3 + webpack: 5.93.0(esbuild@0.19.3) + optionalDependencies: + esbuild: 0.19.3 + terser@5.19.2: dependencies: '@jridgewell/source-map': 0.3.5 @@ -18010,6 +18921,13 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 + terser@5.31.3: + dependencies: + '@jridgewell/source-map': 0.3.5 + acorn: 8.10.0 + commander: 2.20.3 + source-map-support: 0.5.21 + test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 @@ -18042,7 +18960,8 @@ snapshots: throttle-debounce@3.0.1: {} - throttleit@1.0.0: {} + throttleit@1.0.0: + optional: true through2@0.6.5: dependencies: @@ -18055,19 +18974,22 @@ snapshots: readable-stream: 2.3.8 xtend: 4.0.2 - through@2.3.8: {} + through@2.3.8: + optional: true timers-browserify@2.0.12: dependencies: setimmediate: 1.0.5 - timm@1.7.1: {} + timm@1.7.1: + optional: true tiny-invariant@1.3.1: {} tinybench@2.5.1: {} - tinycolor2@1.6.0: {} + tinycolor2@1.6.0: + optional: true tinypool@0.7.0: {} @@ -18080,10 +19002,12 @@ snapshots: tmp@0.2.1: dependencies: rimraf: 3.0.2 + optional: true tmpl@1.0.5: {} - to-array@0.1.4: {} + to-array@0.1.4: + optional: true to-fast-properties@2.0.0: {} @@ -18103,6 +19027,7 @@ snapshots: punycode: 2.3.1 universalify: 0.2.0 url-parse: 1.5.10 + optional: true tr46@0.0.3: {} @@ -18144,11 +19069,14 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tty-browserify@0.0.1: {} + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 - tweetnacl@0.14.5: {} + tweetnacl@0.14.5: + optional: true type-check@0.4.0: dependencies: @@ -18160,7 +19088,8 @@ snapshots: type-fest@0.20.2: {} - type-fest@0.21.3: {} + type-fest@0.21.3: + optional: true type-fest@0.6.0: {} @@ -18282,6 +19211,7 @@ snapshots: unidiff@1.0.2: dependencies: diff: 2.2.3 + optional: true unified@11.0.4: dependencies: @@ -18343,9 +19273,11 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 - universalify@0.1.2: {} + universalify@0.1.2: + optional: true - universalify@0.2.0: {} + universalify@0.2.0: + optional: true universalify@2.0.0: {} @@ -18366,7 +19298,13 @@ snapshots: dependencies: browserslist: 4.21.10 escalade: 3.1.1 - picocolors: 1.0.0 + picocolors: 1.0.1 + + update-browserslist-db@1.1.0(browserslist@4.23.2): + dependencies: + browserslist: 4.23.2 + escalade: 3.1.2 + picocolors: 1.0.1 upper-case-first@2.0.2: dependencies: @@ -18386,6 +19324,12 @@ snapshots: dependencies: querystringify: 2.2.0 requires-port: 1.0.0 + optional: true + + url@0.11.3: + dependencies: + punycode: 1.4.1 + qs: 6.11.2 use-callback-ref@1.3.0(@types/react@18.2.20)(react@18.2.0): dependencies: @@ -18430,6 +19374,7 @@ snapshots: utif@2.0.1: dependencies: pako: 1.0.11 + optional: true util-deprecate@1.0.2: {} @@ -18479,6 +19424,7 @@ snapshots: assert-plus: 1.0.0 core-util-is: 1.0.2 extsprintf: 1.3.0 + optional: true vfile-message@4.0.2: dependencies: @@ -18491,14 +19437,14 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - vite-node@0.34.6(@types/node@20.8.0)(terser@5.19.2): + vite-node@0.34.6(@types/node@20.8.0)(terser@5.31.3): dependencies: cac: 6.7.14 debug: 4.3.4(supports-color@8.1.1) mlly: 1.4.2 pathe: 1.1.1 picocolors: 1.0.0 - vite: 4.4.10(@types/node@20.8.0)(terser@5.19.2) + vite: 4.4.10(@types/node@20.8.0)(terser@5.31.3) transitivePeerDependencies: - '@types/node' - less @@ -18509,7 +19455,7 @@ snapshots: - supports-color - terser - vite@4.4.10(@types/node@20.12.8)(terser@5.19.2): + vite@4.4.10(@types/node@20.12.8)(terser@5.31.3): dependencies: esbuild: 0.18.20 postcss: 8.4.31 @@ -18517,9 +19463,9 @@ snapshots: optionalDependencies: '@types/node': 20.12.8 fsevents: 2.3.3 - terser: 5.19.2 + terser: 5.31.3 - vite@4.4.10(@types/node@20.8.0)(terser@5.19.2): + vite@4.4.10(@types/node@20.8.0)(terser@5.31.3): dependencies: esbuild: 0.18.20 postcss: 8.4.31 @@ -18527,19 +19473,19 @@ snapshots: optionalDependencies: '@types/node': 20.8.0 fsevents: 2.3.3 - terser: 5.19.2 + terser: 5.31.3 - vite@4.5.3(@types/node@20.8.0)(terser@5.19.2): + vite@4.5.3(@types/node@20.8.0)(terser@5.31.3): dependencies: esbuild: 0.18.20 - postcss: 8.4.38 + postcss: 8.4.39 rollup: 3.29.4 optionalDependencies: '@types/node': 20.8.0 fsevents: 2.3.3 - terser: 5.19.2 + terser: 5.31.3 - vitest@0.34.6(terser@5.19.2): + vitest@0.34.6(terser@5.31.3): dependencies: '@types/chai': 4.3.6 '@types/chai-subset': 1.3.3 @@ -18562,8 +19508,8 @@ snapshots: strip-literal: 1.3.0 tinybench: 2.5.1 tinypool: 0.7.0 - vite: 4.4.10(@types/node@20.8.0)(terser@5.19.2) - vite-node: 0.34.6(@types/node@20.8.0)(terser@5.19.2) + vite: 4.4.10(@types/node@20.8.0)(terser@5.31.3) + vite-node: 0.34.6(@types/node@20.8.0)(terser@5.31.3) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -18574,6 +19520,8 @@ snapshots: - supports-color - terser + vm-browserify@1.1.2: {} + w3c-keyname@2.2.8: {} wait-on@7.2.0(debug@4.3.4): @@ -18599,6 +19547,11 @@ snapshots: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 + watchpack@2.4.1: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + wcwidth@1.0.1: dependencies: defaults: 1.0.4 @@ -18611,6 +19564,37 @@ snapshots: webpack-virtual-modules@0.5.0: {} + webpack@5.93.0(esbuild@0.19.3): + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.5 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/wasm-edit': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + acorn: 8.10.0 + acorn-import-attributes: 1.9.5(acorn@8.10.0) + browserslist: 4.21.10 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.17.1 + es-module-lexer: 1.5.4 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.3.0 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.10(esbuild@0.19.3)(webpack@5.93.0(esbuild@0.19.3)) + watchpack: 2.4.1 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + webrtc-adapter@8.2.3: dependencies: sdp: 3.2.0 @@ -18619,7 +19603,8 @@ snapshots: dependencies: iconv-lite: 0.6.3 - whatwg-fetch@3.6.18: {} + whatwg-fetch@3.6.18: + optional: true whatwg-url@5.0.0: dependencies: @@ -18694,6 +19679,7 @@ snapshots: wide-align@1.1.5: dependencies: string-width: 4.2.3 + optional: true wordwrap@1.0.0: {} @@ -18815,6 +19801,7 @@ snapshots: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 + optional: true wrap-ansi@7.0.0: dependencies: @@ -18849,7 +19836,8 @@ snapshots: dependencies: async-limiter: 1.0.1 - ws@7.4.6: {} + ws@7.4.6: + optional: true ws@8.11.0: {} @@ -18859,17 +19847,22 @@ snapshots: is-function: 1.0.2 parse-headers: 2.0.5 xtend: 4.0.2 + optional: true - xml-parse-from-string@1.0.1: {} + xml-parse-from-string@1.0.1: + optional: true xml2js@0.4.23: dependencies: sax: 1.3.0 xmlbuilder: 11.0.1 + optional: true - xmlbuilder@11.0.1: {} + xmlbuilder@11.0.1: + optional: true - xmlhttprequest-ssl@1.6.3: {} + xmlhttprequest-ssl@1.6.3: + optional: true xmlhttprequest-ssl@2.0.0: {} @@ -18906,7 +19899,7 @@ snapshots: yargs@17.7.2: dependencies: cliui: 8.0.1 - escalade: 3.1.1 + escalade: 3.1.2 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -18918,7 +19911,8 @@ snapshots: buffer-crc32: 0.2.13 fd-slicer: 1.1.0 - yeast@0.1.2: {} + yeast@0.1.2: + optional: true yggdrasil@1.7.0(encoding@0.1.13): dependencies: diff --git a/prismarine-viewer/buildMesherWorker.mjs b/prismarine-viewer/buildMesherWorker.mjs index e9f6a16f3..f70b81288 100644 --- a/prismarine-viewer/buildMesherWorker.mjs +++ b/prismarine-viewer/buildMesherWorker.mjs @@ -108,6 +108,7 @@ const buildOptions = { }) build.onEnd(({ metafile, outputFiles }) => { if (!metafile) return + fs.mkdirSync(path.join(__dirname, './public'), { recursive: true }) fs.writeFileSync(path.join(__dirname, './public/metafile.json'), JSON.stringify(metafile)) for (const outDir of ['../dist/', './public/']) { for (const outputFile of outputFiles) { @@ -115,8 +116,9 @@ const buildOptions = { // skip writing & browser loading sourcemap there, worker debugging should be done in playground // continue } - fs.mkdirSync(outDir, { recursive: true }) - fs.writeFileSync(path.join(__dirname, outDir, path.basename(outputFile.path)), outputFile.text) + const writePath = path.join(__dirname, outDir, path.basename(outputFile.path)) + fs.mkdirSync(path.dirname(writePath), { recursive: true }) + fs.writeFileSync(writePath, outputFile.text) } } }) diff --git a/prismarine-viewer/esbuild.mjs b/prismarine-viewer/esbuild.mjs index 9614a3ad6..90741ee14 100644 --- a/prismarine-viewer/esbuild.mjs +++ b/prismarine-viewer/esbuild.mjs @@ -1,7 +1,7 @@ +//@ts-check import * as fs from 'fs' import fsExtra from 'fs-extra' -//@ts-check import * as esbuild from 'esbuild' import { polyfillNode } from 'esbuild-plugin-polyfill-node' import path, { dirname, join } from 'path' @@ -17,7 +17,6 @@ if (!fs.existsSync(mcDataPath)) { await import('../scripts/prepareData.mjs') } -fs.mkdirSync(join(__dirname, 'public'), { recursive: true }) fs.copyFileSync(join(__dirname, 'playground.html'), join(__dirname, 'public/index.html')) fsExtra.copySync(mcDataPath, join(__dirname, 'public/mc-data')) const availableVersions = fs.readdirSync(mcDataPath).map(ver => ver.replace('.js', '')) @@ -47,6 +46,7 @@ const buildOptions = { http: 'http-browserify', stream: 'stream-browserify', net: 'net-browserify', + // 'mc-assets': '/Users/vitaly/Documents/mc-assets', }, inject: [], metafile: true, @@ -57,7 +57,7 @@ const buildOptions = { plugins: [ { name: 'minecraft-data', - setup (build) { + setup(build) { build.onLoad({ filter: /minecraft-data[\/\\]data.js$/, }, () => { @@ -69,7 +69,7 @@ const buildOptions = { }) build.onEnd((e) => { if (e.errors.length) return - fs.writeFileSync(join(__dirname, 'public/metafile.json'), JSON.stringify(e.metafile), 'utf8') + // fs.writeFileSync(join(__dirname, 'dist/metafile.json'), JSON.stringify(e.metafile), 'utf8') }) } }, diff --git a/prismarine-viewer/examples/examples/index.ts b/prismarine-viewer/examples/examples/index.ts new file mode 100644 index 000000000..ee2031063 --- /dev/null +++ b/prismarine-viewer/examples/examples/index.ts @@ -0,0 +1 @@ +export { default as rotation } from './rotation' diff --git a/prismarine-viewer/examples/examples/rotation.ts b/prismarine-viewer/examples/examples/rotation.ts new file mode 100644 index 000000000..8298b72a5 --- /dev/null +++ b/prismarine-viewer/examples/examples/rotation.ts @@ -0,0 +1,9 @@ +import { Vec3 } from 'vec3' +import { ExampleSetupFunction } from './type' + +const setup: ExampleSetupFunction = (world, mcData, mesherConfig, setupParam) => { + mesherConfig.debugModelVariant = [3] + world.setBlockStateId(new Vec3(0, 0, 0), mcData.blocksByName.sand.defaultState) +} + +export default setup diff --git a/prismarine-viewer/examples/examples/type.ts b/prismarine-viewer/examples/examples/type.ts new file mode 100644 index 000000000..e341e26f4 --- /dev/null +++ b/prismarine-viewer/examples/examples/type.ts @@ -0,0 +1,6 @@ +import { CustomWorld } from 'flying-squid/dist/lib/modules/world' +import { MesherConfig } from '../../viewer/lib/mesher/shared' +import { IndexedData } from 'minecraft-data' + +type SetupParams = {} +export type ExampleSetupFunction = (world: CustomWorld, mcData: IndexedData, mesherConfig: MesherConfig, setupParam: SetupParams) => void diff --git a/prismarine-viewer/examples/playground.ts b/prismarine-viewer/examples/playground.ts index bd4673e44..d881f920a 100644 --- a/prismarine-viewer/examples/playground.ts +++ b/prismarine-viewer/examples/playground.ts @@ -6,21 +6,22 @@ import ChunkLoader from 'prismarine-chunk' import WorldLoader from 'prismarine-world' import * as THREE from 'three' import { GUI } from 'lil-gui' -import { toMajor } from '../viewer/lib/version' import { loadScript } from '../viewer/lib/utils' import JSZip from 'jszip' import { TWEEN_DURATION } from '../viewer/lib/entities' import { EntityMesh } from '../viewer/lib/entity/EntityMesh' +import blockstatesModels from 'mc-assets/dist/blockStatesModels.json' globalThis.THREE = THREE //@ts-ignore import { OrbitControls } from 'three/addons/controls/OrbitControls.js' +import { toMajorVersion } from '../../src/utils' const gui = new GUI() // initial values const params = { - skip: '', + skipQs: '', version: globalThis.includedVersions.sort((a, b) => { const s = (x) => { const parts = x.split('.') @@ -38,7 +39,8 @@ const params = { entityRotate: false, camera: '', playSound () { }, - blockIsomorphicRenderBundle () { } + blockIsomorphicRenderBundle () { }, + modelVariant: 0 } const qs = new URLSearchParams(window.location.search) @@ -49,7 +51,7 @@ qs.forEach((value, key) => { const setQs = () => { const newQs = new URLSearchParams() for (const [key, value] of Object.entries(params)) { - if (!value || typeof value === 'function' || params.skip.includes(key)) continue + if (!value || typeof value === 'function' || params.skipQs.includes(key)) continue //@ts-ignore newQs.set(key, value) } @@ -65,7 +67,7 @@ async function main () { // temporary solution until web worker is here, cache data for faster reloads const globalMcData = window['mcData'] if (!globalMcData['version']) { - const major = toMajor(version) + const major = toMajorVersion(version) const sessionKey = `mcData-${major}` if (sessionStorage[sessionKey]) { Object.assign(globalMcData, JSON.parse(sessionStorage[sessionKey])) @@ -84,11 +86,12 @@ async function main () { gui.add(params, 'version', globalThis.includedVersions) gui.add(params, 'block', mcData.blocksArray.map(b => b.name).sort((a, b) => a.localeCompare(b))) const metadataGui = gui.add(params, 'metadata') + gui.add(params, 'modelVariant') gui.add(params, 'supportBlock') gui.add(params, 'entity', mcData.entitiesArray.map(b => b.name).sort((a, b) => a.localeCompare(b))).listen() gui.add(params, 'removeEntity') gui.add(params, 'entityRotate') - gui.add(params, 'skip') + gui.add(params, 'skipQs') gui.add(params, 'playSound') gui.add(params, 'blockIsomorphicRenderBundle') gui.open(false) @@ -133,7 +136,8 @@ async function main () { document.body.appendChild(renderer.domElement) // Create viewer - const viewer = new Viewer(renderer, { numWorkers: 1, showChunkBorders: false }) + const viewer = new Viewer(renderer, { numWorkers: 1, showChunkBorders: false, }) + viewer.world.blockstatesModels = blockstatesModels viewer.entities.setDebugMode('basic') viewer.setVersion(version) viewer.entities.onSkinUpdate = () => { @@ -299,36 +303,45 @@ async function main () { } const onUpdate = { + version (initialUpdate) { + if (initialUpdate) return + // viewer.world.texturesVersion = params.version + // viewer.world.updateTexturesData() + // todo warning + }, block () { + blockProps = {} metadataFolder.destroy() const block = mcData.blocksByName[params.block] if (!block) return + console.log('block', block.name) const props = new Block(block.id, 0, 0).getProperties() //@ts-ignore const { states } = mcData.blocksByStateId[getBlock()?.minStateId] ?? {} metadataFolder = gui.addFolder('metadata') if (states) { for (const state of states) { - let defaultValue - switch (state.type) { - case 'enum': - defaultValue = state.values[0] - break - case 'bool': - defaultValue = false - break - case 'int': - defaultValue = 0 - break - case 'direction': - defaultValue = 'north' - break - - default: - continue + let defaultValue: string | number | boolean + if (state.values) { // int, enum + defaultValue = state.values[0] + } else { + switch (state.type) { + case 'bool': + defaultValue = false + break + case 'int': + defaultValue = 0 + break + case 'direction': + defaultValue = 'north' + break + + default: + continue + } } blockProps[state.name] = defaultValue - if (state.type === 'enum') { + if (state.values) { metadataFolder.add(blockProps, state.name, state.values) } else { metadataFolder.add(blockProps, state.name) @@ -340,6 +353,7 @@ async function main () { metadataFolder.add(blockProps, name) } } + console.log('props', blockProps) metadataFolder.open() }, entity () { @@ -364,6 +378,9 @@ async function main () { }, supportBlock () { viewer.setBlockStateId(targetPos.offset(0, -1, 0), params.supportBlock ? 1 : 0) + }, + modelVariant () { + viewer.world.mesherConfig.debugModelVariant = params.modelVariant === 0 ? undefined : [params.modelVariant] } } @@ -407,10 +424,14 @@ async function main () { } }) viewer.waitForChunksToRender().then(async () => { + // TODO! + await new Promise(resolve => { + setTimeout(resolve, 50) + }) for (const update of Object.values(onUpdate)) { - update() + update(true) } - applyChanges(true) + applyChanges() gui.openAnimated() }) diff --git a/prismarine-viewer/index.d.ts b/prismarine-viewer/index.d.ts deleted file mode 100644 index 543fa225d..000000000 --- a/prismarine-viewer/index.d.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {Bot} from "mineflayer"; - -export function mineflayer(bot: Bot, settings: { - viewDistance?: number; - firstPerson?: boolean; - port?: number; - prefix?: string; -}); - -export function standalone(options: { - version: versions; - world: (x: number, y: number, z: number) => 0 | 1; - center?: Vec3; - viewDistance?: number; - port?: number; - prefix?: string; -}); - -export function headless(bot: Bot, settings: { - viewDistance?: number; - output?: string; - frames?: number; - width?: number; - height?: number; - logFFMPEG?: boolean; - jpegOption: any; -}); - -export const viewer: { - Viewer: any; - WorldDataEmitter: any; - MapControls: any; - Entitiy: any; - getBufferFromStream: (stream: any) => Promise; -}; - -export const supportedVersions: versions[]; -export type versions = '1.8.8' | '1.9.4' | '1.10.2' | '1.11.2' | '1.12.2' | '1.13.2' | '1.14.4' | '1.15.2' | '1.16.1' | '1.16.4' | '1.17.1' | '1.18.1'; diff --git a/prismarine-viewer/index.js b/prismarine-viewer/index.js index 67136592c..37689158e 100644 --- a/prismarine-viewer/index.js +++ b/prismarine-viewer/index.js @@ -3,5 +3,4 @@ module.exports = { standalone: require('./lib/standalone'), headless: require('./lib/headless'), viewer: require('./viewer'), - supportedVersions: require('./viewer/supportedVersions.json') } diff --git a/prismarine-viewer/jest-puppeteer.config.js b/prismarine-viewer/jest-puppeteer.config.js deleted file mode 100644 index 6007898f8..000000000 --- a/prismarine-viewer/jest-puppeteer.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - launch: { - args: ['--no-sandbox', '--disable-setuid-sandbox'] - } -} diff --git a/prismarine-viewer/jest.config.js b/prismarine-viewer/jest.config.js deleted file mode 100644 index ae87d0d01..000000000 --- a/prismarine-viewer/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - preset: 'jest-puppeteer', - testRegex: './*\\.test\\.js$' -} diff --git a/prismarine-viewer/package.json b/prismarine-viewer/package.json index 7fd2507fb..d0ea3826d 100644 --- a/prismarine-viewer/package.json +++ b/prismarine-viewer/package.json @@ -3,10 +3,7 @@ "version": "1.25.0", "description": "Web based viewer", "main": "index.js", - "scripts": { - "postinstall": "pnpm generate-textures && node buildMesherWorker.mjs", - "generate-textures": "tsx viewer/prepare/postinstall.ts" - }, + "scripts": {}, "author": "PrismarineJS", "license": "MIT", "standard": { @@ -21,11 +18,9 @@ "@tweenjs/tween.js": "^20.0.3", "assert": "^2.0.0", "buffer": "^6.0.3", - "canvas": "^2.11.2", "filesize": "^10.0.12", "fs-extra": "^11.0.0", "lil-gui": "^0.18.2", - "looks-same": "^8.2.3", "minecraft-wrap": "^1.3.0", "minecrafthawkeye": "^1.3.6", "prismarine-block": "^1.7.3", @@ -41,6 +36,7 @@ "vec3": "^0.1.7" }, "optionalDependencies": { + "canvas": "^2.11.2", "node-canvas-webgl": "^0.3.0" } } diff --git a/prismarine-viewer/tsconfig.json b/prismarine-viewer/tsconfig.json deleted file mode 100644 index b6e39df32..000000000 --- a/prismarine-viewer/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "strictNullChecks": true, - "experimentalDecorators": true - }, - "files": [ - "index.d.ts" - ] -} diff --git a/prismarine-viewer/viewer/lib/entities.js b/prismarine-viewer/viewer/lib/entities.js index d36b6936b..5bd5274cc 100644 --- a/prismarine-viewer/viewer/lib/entities.js +++ b/prismarine-viewer/viewer/lib/entities.js @@ -7,7 +7,7 @@ import EventEmitter from 'events' import { PlayerObject, PlayerAnimation } from 'skinview3d' import { loadSkinToCanvas, loadEarsToCanvasFromSkin, inferModelType, loadCapeToCanvas, loadImage } from 'skinview-utils' // todo replace with url -import stevePng from 'minecraft-assets/minecraft-assets/data/1.20.2/entity/player/wide/steve.png' +import stevePng from 'mc-assets/dist/other-textures/latest/entity/player/wide/steve.png' import { WalkingGeneralSwing } from './entity/animations' import { NameTagObject } from 'skinview3d/libs/nametag' import { flat, fromFormattedString } from '@xmcl/text-component' @@ -17,7 +17,7 @@ import { disposeObject } from './threeJsUtils' export const TWEEN_DURATION = 50 // todo should be 100 -function getUsernameTexture(username, { fontFamily = 'sans-serif' }) { +function getUsernameTexture (username, { fontFamily = 'sans-serif' }) { const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') if (!ctx) throw new Error('Could not get 2d context') @@ -61,7 +61,7 @@ const addNametag = (entity, options, mesh) => { // todo cleanup const nametags = {} -function getEntityMesh(entity, scene, options, overrides) { +function getEntityMesh (entity, scene, options, overrides) { if (entity.name) { try { // https://github.com/PrismarineJS/prismarine-viewer/pull/410 @@ -102,11 +102,12 @@ export class Entities extends EventEmitter { this.onSkinUpdate = () => { } this.clock = new THREE.Clock() this.rendering = true + /** @type {THREE.Texture | null} */ this.itemsTexture = null this.getItemUv = undefined } - clear() { + clear () { for (const mesh of Object.values(this.entities)) { this.scene.remove(mesh) disposeObject(mesh) @@ -114,7 +115,7 @@ export class Entities extends EventEmitter { this.entities = {} } - setDebugMode(mode, /** @type {THREE.Object3D?} */entity = null) { + setDebugMode (mode, /** @type {THREE.Object3D?} */entity = null) { this.debugMode = mode for (const mesh of entity ? [entity] : Object.values(this.entities)) { const boxHelper = mesh.children.find(c => c.name === 'debug') @@ -126,7 +127,7 @@ export class Entities extends EventEmitter { } } - setRendering(rendering, /** @type {THREE.Object3D?} */entity = null) { + setRendering (rendering, /** @type {THREE.Object3D?} */entity = null) { this.rendering = rendering for (const ent of entity ? [entity] : Object.values(this.entities)) { if (rendering) { @@ -137,7 +138,7 @@ export class Entities extends EventEmitter { } } - render() { + render () { const dt = this.clock.getDelta() for (const entityId of Object.keys(this.entities)) { const playerObject = this.getPlayerObject(entityId) @@ -147,7 +148,7 @@ export class Entities extends EventEmitter { } } - getPlayerObject(entityId) { + getPlayerObject (entityId) { /** @type {(PlayerObject & { animation?: PlayerAnimation }) | undefined} */ const playerObject = this.entities[entityId]?.playerObject return playerObject @@ -157,7 +158,7 @@ export class Entities extends EventEmitter { defaultSteveTexture // true means use default skin url - updatePlayerSkin(entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { + updatePlayerSkin (entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { let playerObject = this.getPlayerObject(entityId) if (!playerObject) return // const username = this.entities[entityId].username @@ -240,14 +241,14 @@ export class Entities extends EventEmitter { playerObject.cape.map = null } - function isCanvasBlank(canvas) { + function isCanvasBlank (canvas) { return !canvas.getContext('2d') .getImageData(0, 0, canvas.width, canvas.height).data .some(channel => channel !== 0) } } - playAnimation(entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { + playAnimation (entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { const playerObject = this.getPlayerObject(entityPlayerId) if (!playerObject) return @@ -267,7 +268,7 @@ export class Entities extends EventEmitter { } - parseEntityLabel(jsonLike) { + parseEntityLabel (jsonLike) { if (!jsonLike) return try { const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike) @@ -278,7 +279,7 @@ export class Entities extends EventEmitter { } } - update(/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { + update (/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { let isPlayerModel = entity.name === 'player' if (entity.name === 'zombie' || entity.name === 'zombie_villager' || entity.name === 'husk') { isPlayerModel = true @@ -407,7 +408,7 @@ export class Entities extends EventEmitter { //@ts-ignore // set visibility const isInvisible = entity.metadata?.[0] & 0x20 - for (const child of this.entities[entity.id].children.find(c => c.name === 'mesh').children) { + for (const child of this.entities[entity.id]?.children.find(c => c.name === 'mesh')?.children ?? []) { if (child.name !== 'nametag') { child.visible = !isInvisible } diff --git a/prismarine-viewer/viewer/lib/entity/EntityMesh.js b/prismarine-viewer/viewer/lib/entity/EntityMesh.js index 358b05682..ef71019a8 100644 --- a/prismarine-viewer/viewer/lib/entity/EntityMesh.js +++ b/prismarine-viewer/viewer/lib/entity/EntityMesh.js @@ -356,7 +356,7 @@ export class EntityMesh { const texture = overrides.textures?.[name] ?? e.textures[name] if (!texture) continue // console.log(JSON.stringify(jsonModel, null, 2)) - const mesh = getMesh(texture.replace('textures', 'textures/' + version) + '.png', jsonModel, overrides) + const mesh = getMesh(texture + '.png', jsonModel, overrides,) mesh.name = `geometry_${name}` this.mesh.add(mesh) diff --git a/prismarine-viewer/viewer/lib/mesher/mesher.ts b/prismarine-viewer/viewer/lib/mesher/mesher.ts index 67eb7adc8..b13b8ae09 100644 --- a/prismarine-viewer/viewer/lib/mesher/mesher.ts +++ b/prismarine-viewer/viewer/lib/mesher/mesher.ts @@ -1,6 +1,6 @@ import { World } from './world' import { Vec3 } from 'vec3' -import { getSectionGeometry, setBlockStatesData } from './models' +import { getSectionGeometry, setBlockStatesData as setMesherData } from './models' if (module.require) { // If we are in a node environement, we need to fake some env variables @@ -13,7 +13,7 @@ if (module.require) { let world: World let dirtySections: Map = new Map() -let blockStatesReady = false +let allDataReady = false function sectionKey (x, y, z) { return `${x},${y},${z}` @@ -74,14 +74,18 @@ const handleMessage = data => { } if (data.config) { + if (data.type === 'mesherData' && allDataReady) { + world = undefined as any // reset models + } + world ??= new World(data.config.version) world.config = { ...world.config, ...data.config } globalThis.world = world } if (data.type === 'mesherData') { - setBlockStatesData(data.json) - blockStatesReady = true + setMesherData(data.blockstatesModels, data.blocksAtlas) + allDataReady = true } else if (data.type === 'dirty') { const loc = new Vec3(data.x, data.y, data.z) setSectionDirty(loc, data.value) @@ -99,7 +103,7 @@ const handleMessage = data => { dirtySections = new Map() // todo also remove cached globalVar.mcData = null - blockStatesReady = false + allDataReady = false } } @@ -113,7 +117,7 @@ self.onmessage = ({ data }) => { } setInterval(() => { - if (world === null || !blockStatesReady) return + if (world === null || !allDataReady) return if (dirtySections.size === 0) return // console.log(sections.length + ' dirty sections') diff --git a/prismarine-viewer/viewer/lib/mesher/models.ts b/prismarine-viewer/viewer/lib/mesher/models.ts index c978c240a..c0faaeaeb 100644 --- a/prismarine-viewer/viewer/lib/mesher/models.ts +++ b/prismarine-viewer/viewer/lib/mesher/models.ts @@ -1,12 +1,13 @@ import { Vec3 } from 'vec3' -import type { BlockStatesOutput } from '../../prepare/modelsBuilder' -import { World } from './world' +import { World, BlockModelPartsResolved } from './world' import { WorldBlock as Block } from './world' import legacyJson from '../../../../src/preflatMap.json' -import { versionToNumber } from '../../prepare/utils' +import worldBlockProvider, { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider' +import { BlockElement, buildRotationMatrix, elemFaces, matmul3, matmulmat3, vecadd3, vecsub3 } from './modelsGeometryCommon' + +let blockProvider: WorldBlockProvider const tints: any = {} -let blockStates: BlockStatesOutput let needTiles = false let tintsData @@ -35,6 +36,10 @@ function prepareTints (tints) { }) } +function mod (x: number, n: number) { + return ((x % n) + n) % n +} + const calculatedBlocksEntries = Object.entries(legacyJson.clientCalculatedBlocks) export function preflatBlockCalculation (block: Block, world: World, position: Vec3) { const type = calculatedBlocksEntries.find(([name, blocks]) => blocks.includes(block.name))?.[0] @@ -89,75 +94,6 @@ function tintToGl (tint) { return [r / 255, g / 255, b / 255] } -const elemFaces = { - up: { - dir: [0, 1, 0], - mask1: [1, 1, 0], - mask2: [0, 1, 1], - corners: [ - [0, 1, 1, 0, 1], - [1, 1, 1, 1, 1], - [0, 1, 0, 0, 0], - [1, 1, 0, 1, 0] - ] - }, - down: { - dir: [0, -1, 0], - mask1: [1, 1, 0], - mask2: [0, 1, 1], - corners: [ - [1, 0, 1, 0, 1], - [0, 0, 1, 1, 1], - [1, 0, 0, 0, 0], - [0, 0, 0, 1, 0] - ] - }, - east: { - dir: [1, 0, 0], - mask1: [1, 1, 0], - mask2: [1, 0, 1], - corners: [ - [1, 1, 1, 0, 0], - [1, 0, 1, 0, 1], - [1, 1, 0, 1, 0], - [1, 0, 0, 1, 1] - ] - }, - west: { - dir: [-1, 0, 0], - mask1: [1, 1, 0], - mask2: [1, 0, 1], - corners: [ - [0, 1, 0, 0, 0], - [0, 0, 0, 0, 1], - [0, 1, 1, 1, 0], - [0, 0, 1, 1, 1] - ] - }, - north: { - dir: [0, 0, -1], - mask1: [1, 0, 1], - mask2: [0, 1, 1], - corners: [ - [1, 0, 0, 0, 1], - [0, 0, 0, 1, 1], - [1, 1, 0, 0, 0], - [0, 1, 0, 1, 0] - ] - }, - south: { - dir: [0, 0, 1], - mask1: [1, 0, 1], - mask2: [0, 1, 1], - corners: [ - [0, 0, 1, 0, 1], - [1, 0, 1, 1, 1], - [0, 1, 1, 0, 0], - [1, 1, 1, 1, 0] - ] - } -} - function getLiquidRenderHeight (world, block, type, pos) { if (!block || block.type !== type) return 1 / 9 if (block.metadata === 0) { // source block @@ -177,8 +113,9 @@ const everyArray = (array, callback) => { const isCube = (block) => { if (!block || block.transparent) return false if (block.isCube) return true - if (!block.variant) block.variant = getModelVariants(block) - if (!block.variant.length) return false + // TODO! + // if (!block.variant) block.variant = getModelVariants(block) + if (!block.variant?.length) return false return block.variant.every(v => everyArray(v?.model?.elements, e => { return e.from[0] === 0 && e.from[1] === 0 && e.from[2] === 0 && e.to[0] === 16 && e.to[1] === 16 && e.to[2] === 16 })) @@ -249,78 +186,9 @@ function renderLiquid (world, cursor, texture, type, biome, water, attr) { } } -function vecadd3 (a, b) { - if (!b) return a - return [a[0] + b[0], a[1] + b[1], a[2] + b[2]] -} - -function vecsub3 (a, b) { - if (!b) return a - return [a[0] - b[0], a[1] - b[1], a[2] - b[2]] -} - -function matmul3 (matrix, vector): [number, number, number] { - if (!matrix) return vector - return [ - matrix[0][0] * vector[0] + matrix[0][1] * vector[1] + matrix[0][2] * vector[2], - matrix[1][0] * vector[0] + matrix[1][1] * vector[1] + matrix[1][2] * vector[2], - matrix[2][0] * vector[0] + matrix[2][1] * vector[1] + matrix[2][2] * vector[2] - ] -} - -function matmulmat3 (a, b) { - const te = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] - - const a11 = a[0][0]; const a12 = a[1][0]; const a13 = a[2][0] - const a21 = a[0][1]; const a22 = a[1][1]; const a23 = a[2][1] - const a31 = a[0][2]; const a32 = a[1][2]; const a33 = a[2][2] - - const b11 = b[0][0]; const b12 = b[1][0]; const b13 = b[2][0] - const b21 = b[0][1]; const b22 = b[1][1]; const b23 = b[2][1] - const b31 = b[0][2]; const b32 = b[1][2]; const b33 = b[2][2] - - te[0][0] = a11 * b11 + a12 * b21 + a13 * b31 - te[1][0] = a11 * b12 + a12 * b22 + a13 * b32 - te[2][0] = a11 * b13 + a12 * b23 + a13 * b33 - - te[0][1] = a21 * b11 + a22 * b21 + a23 * b31 - te[1][1] = a21 * b12 + a22 * b22 + a23 * b32 - te[2][1] = a21 * b13 + a22 * b23 + a23 * b33 - - te[0][2] = a31 * b11 + a32 * b21 + a33 * b31 - te[1][2] = a31 * b12 + a32 * b22 + a33 * b32 - te[2][2] = a31 * b13 + a32 * b23 + a33 * b33 - - return te -} - -function buildRotationMatrix (axis, degree) { - const radians = degree / 180 * Math.PI - const cos = Math.cos(radians) - const sin = Math.sin(radians) - - const axis0 = { x: 0, y: 1, z: 2 }[axis] - const axis1 = (axis0 + 1) % 3 - const axis2 = (axis0 + 2) % 3 - - const matrix = [ - [0, 0, 0], - [0, 0, 0], - [0, 0, 0] - ] - - matrix[axis0][axis0] = 1 - matrix[axis1][axis1] = cos - matrix[axis1][axis2] = -sin - matrix[axis2][axis1] = +sin - matrix[axis2][axis2] = cos - - return matrix -} - let needRecompute = false -function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr, globalMatrix, globalShift, block: Block, biome) { +function renderElement (world: World, cursor: Vec3, element: BlockElement, doAO: boolean, attr: Record, globalMatrix: any, globalShift: any, block: Block, biome: string) { const position = cursor // const key = `${position.x},${position.y},${position.z}` // if (!globalThis.allowedBlocks.includes(key)) return @@ -349,10 +217,11 @@ function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr const maxy = element.to[1] const maxz = element.to[2] - const u = eFace.texture.u - const v = eFace.texture.v - const su = eFace.texture.su - const sv = eFace.texture.sv + const texture = eFace.texture as any + const u = texture.u + const v = texture.v + const su = texture.su + const sv = texture.sv const ndx = Math.floor(attr.positions.length / 3) @@ -382,6 +251,7 @@ function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr let localShift = null as any if (element.rotation) { + // todo do we support rescale? localMatrix = buildRotationMatrix( element.rotation.axis, element.rotation.angle @@ -485,6 +355,11 @@ function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr } } +const invisibleBlocks = ['air', 'cave_air', 'void_air', 'barrier'] + +const isBlockWaterlogged = (block: Block) => block.getProperties().waterlogged === true || block.getProperties().waterlogged === 'true' + +let unknownBlockModel: BlockModelPartsResolved export function getSectionGeometry (sx, sy, sz, world: World) { let delayedRender = [] as (() => void)[] @@ -511,6 +386,7 @@ export function getSectionGeometry (sx, sy, sz, world: World) { for (cursor.z = sz; cursor.z < sz + 16; cursor.z++) { for (cursor.x = sx; cursor.x < sx + 16; cursor.x++) { const block = world.getBlock(cursor)! + if (invisibleBlocks.includes(block.name)) continue if (block.name.includes('_sign') || block.name === 'sign') { const key = `${cursor.x},${cursor.y},${cursor.z}` const props: any = block.getProperties() @@ -546,51 +422,71 @@ export function getSectionGeometry (sx, sy, sz, world: World) { block._originalProperties = undefined } } - if (block.variant === undefined || preflatRecomputeVariant) { - block.variant = getModelVariants(block) + + const isWaterlogged = isBlockWaterlogged(block) + if (block.name === 'water' || isWaterlogged) { + const pos = cursor.clone() + delayedRender.push(() => { + renderLiquid(world, pos, blockProvider.getTextureInfo('water_still'), block.type, biome, true, attr) + }) + } else if (block.name === 'lava') { + renderLiquid(world, cursor, blockProvider.getTextureInfo('lava_still'), block.type, biome, false, attr) } + if (block.name !== "water" && block.name !== "lava" && !invisibleBlocks.includes(block.name)) { + // cache + let models = block.models + if (block.models === undefined || preflatRecomputeVariant) { + try { + models = blockProvider.getAllResolvedModels0_1({ + name: block.name, + properties: block.getProperties(), + })! + if (!models.length) models = null + } catch (err) { + console.error(`Critical assets error. Unable to get block model for ${block.name}[${JSON.stringify(block.getProperties())}]: ` + err.message, err.stack) + } + } + block.models = models ?? null - for (const variant of block.variant) { - if (!variant || !variant.model) continue + models ??= unknownBlockModel - const isWaterlogged = block.getProperties().waterlogged - if (block.name === 'water' || isWaterlogged) { - const waterBlock = block.name === 'water' ? block : { name: 'water', metadata: 0 } - const variant = getModelVariants(waterBlock as any)[0] + const firstForceVar = world.config.debugModelVariant?.[0] + let part = 0 + for (const modelVars of models ?? []) { const pos = cursor.clone() - delayedRender.push(() => { - renderLiquid(world, pos, variant.model.textures.particle, block.type, biome, true, attr) - }) - } else if (block.name === 'lava') { - renderLiquid(world, cursor, variant.model.textures.particle, block.type, biome, false, attr) - } - if (block.name !== "water") { + // const variantRuntime = mod(Math.floor(pos.x / 16) + Math.floor(pos.y / 16) + Math.floor(pos.z / 16), modelVars.length) + const variantRuntime = 0 + const useVariant = world.config.debugModelVariant?.[part] ?? firstForceVar ?? variantRuntime + part++ + const model = modelVars[useVariant] ?? modelVars[0] + if (!model) continue + let globalMatrix = null as any let globalShift = null as any - - for (const axis of ['x', 'y', 'z']) { - if (axis in variant) { - if (!globalMatrix) globalMatrix = buildRotationMatrix(axis, -variant[axis]) - else globalMatrix = matmulmat3(globalMatrix, buildRotationMatrix(axis, -variant[axis])) + for (const axis of ['x', 'y', 'z'] as const) { + if (axis in model) { + if (!globalMatrix) globalMatrix = buildRotationMatrix(axis, -(model[axis] ?? 0)) + else globalMatrix = matmulmat3(globalMatrix, buildRotationMatrix(axis, -(model[axis] ?? 0))) } } - if (globalMatrix) { globalShift = [8, 8, 8] globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift)) } - for (const element of variant.model.elements) { + for (const element of model.elements ?? []) { + const ao = model.ao ?? true if (block.transparent) { const pos = cursor.clone() delayedRender.push(() => { - renderElement(world, pos, element, variant.model.ao, attr, globalMatrix, globalShift, block, biome) + renderElement(world, pos, element, ao, attr, globalMatrix, globalShift, block, biome) }) } else { - renderElement(world, cursor, element, variant.model.ao, attr, globalMatrix, globalShift, block, biome) + renderElement(world, cursor, element, ao, attr, globalMatrix, globalShift, block, biome) } } } + } } } @@ -631,65 +527,12 @@ export function getSectionGeometry (sx, sy, sz, world: World) { return attr } -function parseProperties (properties) { - if (typeof properties === 'object') { return properties } - - const json = {} - for (const prop of properties.split(',')) { - const [key, value] = prop.split('=') - json[key] = value +export const setBlockStatesData = (blockstatesModels, blocksAtlas: any, _needTiles = false, useUnknownBlockModel = true) => { + blockProvider = worldBlockProvider(blockstatesModels, blocksAtlas, 'latest') + globalThis.blockProvider = blockProvider + if (useUnknownBlockModel) { + unknownBlockModel = blockProvider.getAllResolvedModels0_1({ name: 'unknown', properties: {} }) } - return json -} - -function matchProperties (block: Block, /* to match against */properties: Record & { OR }) { - if (!properties) { return true } - - properties = parseProperties(properties) - const blockProps = block.getProperties() - if (properties.OR) { - return properties.OR.some((or) => matchProperties(block, or)) - } - for (const prop in blockProps) { - if (properties[prop] === undefined) continue // unknown property, ignore - if (typeof properties[prop] !== 'string') properties[prop] = String(properties[prop]) - if (!(properties[prop] as string).split('|').some((value) => value === String(blockProps[prop]))) { - return false - } - } - return true -} - -function getModelVariants (block: Block) { - // air, cave_air, void_air and so on... - // full list of invisible & special blocks https://minecraft.wiki/w/Model#Blocks_and_fluids - if (block.name === '' || block.name === 'air' || block.name.endsWith('_air')) return [] - if (block.name === 'barrier') return [] - const matchedState = blockStates[block.name] - // if (!matchedState) currentWarnings.value.add(`Missing block ${block.name}`) - const state = matchedState ?? blockStates.missing_texture - if (!state) return [] - if (state.variants) { - for (const [properties, variant] of Object.entries(state.variants)) { - if (!matchProperties(block, properties as any)) continue - if (variant instanceof Array) return [variant[0]] - return [variant] - } - } - if (state.multipart) { - const parts = state.multipart.filter(multipart => matchProperties(block, multipart.when)) - let variants = [] as any[] - for (const part of parts) { - variants = [...variants, ...Array.isArray(part.apply) ? part.apply : [part.apply]] - } - - return variants - } - - return [] -} -export const setBlockStatesData = (_blockStates: BlockStatesOutput | null, _needTiles = false) => { - blockStates = _blockStates! needTiles = _needTiles } diff --git a/prismarine-viewer/viewer/lib/mesher/modelsGeometryCommon.ts b/prismarine-viewer/viewer/lib/mesher/modelsGeometryCommon.ts new file mode 100644 index 000000000..1d83c818d --- /dev/null +++ b/prismarine-viewer/viewer/lib/mesher/modelsGeometryCommon.ts @@ -0,0 +1,142 @@ +import { BlockModelPartsResolved } from './world' + +export type BlockElement = NonNullable[0] + + +export function buildRotationMatrix (axis, degree) { + const radians = degree / 180 * Math.PI + const cos = Math.cos(radians) + const sin = Math.sin(radians) + + const axis0 = { x: 0, y: 1, z: 2 }[axis] + const axis1 = (axis0 + 1) % 3 + const axis2 = (axis0 + 2) % 3 + + const matrix = [ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0] + ] + + matrix[axis0][axis0] = 1 + matrix[axis1][axis1] = cos + matrix[axis1][axis2] = -sin + matrix[axis2][axis1] = +sin + matrix[axis2][axis2] = cos + + return matrix +} + +export function vecadd3 (a, b) { + if (!b) return a + return [a[0] + b[0], a[1] + b[1], a[2] + b[2]] +} + +export function vecsub3 (a, b) { + if (!b) return a + return [a[0] - b[0], a[1] - b[1], a[2] - b[2]] +} + +export function matmul3 (matrix, vector): [number, number, number] { + if (!matrix) return vector + return [ + matrix[0][0] * vector[0] + matrix[0][1] * vector[1] + matrix[0][2] * vector[2], + matrix[1][0] * vector[0] + matrix[1][1] * vector[1] + matrix[1][2] * vector[2], + matrix[2][0] * vector[0] + matrix[2][1] * vector[1] + matrix[2][2] * vector[2] + ] +} + +export function matmulmat3 (a, b) { + const te = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] + + const a11 = a[0][0]; const a12 = a[1][0]; const a13 = a[2][0] + const a21 = a[0][1]; const a22 = a[1][1]; const a23 = a[2][1] + const a31 = a[0][2]; const a32 = a[1][2]; const a33 = a[2][2] + + const b11 = b[0][0]; const b12 = b[1][0]; const b13 = b[2][0] + const b21 = b[0][1]; const b22 = b[1][1]; const b23 = b[2][1] + const b31 = b[0][2]; const b32 = b[1][2]; const b33 = b[2][2] + + te[0][0] = a11 * b11 + a12 * b21 + a13 * b31 + te[1][0] = a11 * b12 + a12 * b22 + a13 * b32 + te[2][0] = a11 * b13 + a12 * b23 + a13 * b33 + + te[0][1] = a21 * b11 + a22 * b21 + a23 * b31 + te[1][1] = a21 * b12 + a22 * b22 + a23 * b32 + te[2][1] = a21 * b13 + a22 * b23 + a23 * b33 + + te[0][2] = a31 * b11 + a32 * b21 + a33 * b31 + te[1][2] = a31 * b12 + a32 * b22 + a33 * b32 + te[2][2] = a31 * b13 + a32 * b23 + a33 * b33 + + return te +} + +export const elemFaces = { + up: { + dir: [0, 1, 0], + mask1: [1, 1, 0], + mask2: [0, 1, 1], + corners: [ + [0, 1, 1, 0, 1], + [1, 1, 1, 1, 1], + [0, 1, 0, 0, 0], + [1, 1, 0, 1, 0] + ] + }, + down: { + dir: [0, -1, 0], + mask1: [1, 1, 0], + mask2: [0, 1, 1], + corners: [ + [1, 0, 1, 0, 1], + [0, 0, 1, 1, 1], + [1, 0, 0, 0, 0], + [0, 0, 0, 1, 0] + ] + }, + east: { + dir: [1, 0, 0], + mask1: [1, 1, 0], + mask2: [1, 0, 1], + corners: [ + [1, 1, 1, 0, 0], + [1, 0, 1, 0, 1], + [1, 1, 0, 1, 0], + [1, 0, 0, 1, 1] + ] + }, + west: { + dir: [-1, 0, 0], + mask1: [1, 1, 0], + mask2: [1, 0, 1], + corners: [ + [0, 1, 0, 0, 0], + [0, 0, 0, 0, 1], + [0, 1, 1, 1, 0], + [0, 0, 1, 1, 1] + ] + }, + north: { + dir: [0, 0, -1], + mask1: [1, 0, 1], + mask2: [0, 1, 1], + corners: [ + [1, 0, 0, 0, 1], + [0, 0, 0, 1, 1], + [1, 1, 0, 0, 0], + [0, 1, 0, 1, 0] + ] + }, + south: { + dir: [0, 0, 1], + mask1: [1, 0, 1], + mask2: [0, 1, 1], + corners: [ + [0, 0, 1, 0, 1], + [1, 0, 1, 1, 1], + [0, 1, 1, 0, 0], + [1, 1, 1, 1, 0] + ] + } +} diff --git a/prismarine-viewer/viewer/lib/mesher/shared.ts b/prismarine-viewer/viewer/lib/mesher/shared.ts index 36c319b17..782a31419 100644 --- a/prismarine-viewer/viewer/lib/mesher/shared.ts +++ b/prismarine-viewer/viewer/lib/mesher/shared.ts @@ -5,6 +5,7 @@ export const defaultMesherConfig = { smoothLighting: true, outputFormat: 'threeJs' as 'threeJs' | 'webgl', textureSize: 1024, // for testing + debugModelVariant: undefined as undefined | number[] } export type MesherConfig = typeof defaultMesherConfig diff --git a/prismarine-viewer/viewer/lib/mesher/standaloneRenderer.ts b/prismarine-viewer/viewer/lib/mesher/standaloneRenderer.ts new file mode 100644 index 000000000..71e0c56ff --- /dev/null +++ b/prismarine-viewer/viewer/lib/mesher/standaloneRenderer.ts @@ -0,0 +1,273 @@ +import { Vec3 } from 'vec3' +import { BlockElement, buildRotationMatrix, elemFaces, matmul3, matmulmat3, vecadd3, vecsub3 } from './modelsGeometryCommon' +import { Block } from 'prismarine-block' +import { BlockModelPartsResolved } from './world' +import { IndexedData } from 'minecraft-data' +import * as THREE from 'three' + +type NeighborSide = 'up' | 'down' | 'east' | 'west' | 'north' | 'south' + +function tintToGl (tint) { + const r = (tint >> 16) & 0xff + const g = (tint >> 8) & 0xff + const b = tint & 0xff + return [r / 255, g / 255, b / 255] +} + +type Neighbors = Partial> +function renderElement (element: BlockElement, doAO: boolean, attr, globalMatrix, globalShift, block: Block | undefined, biome: string, neighbors: Neighbors) { + const cursor = new Vec3(0, 0, 0) + + // const key = `${position.x},${position.y},${position.z}` + // if (!globalThis.allowedBlocks.includes(key)) return + // const cullIfIdentical = block.name.indexOf('glass') >= 0 + + for (const face in element.faces) { + const eFace = element.faces[face] + const { corners, mask1, mask2 } = elemFaces[face] + const dir = matmul3(globalMatrix, elemFaces[face].dir) + + if (eFace.cullface) { + if (neighbors[face]) continue + } + + const minx = element.from[0] + const miny = element.from[1] + const minz = element.from[2] + const maxx = element.to[0] + const maxy = element.to[1] + const maxz = element.to[2] + + const texture = eFace.texture as any + const u = texture.u + const v = texture.v + const su = texture.su + const sv = texture.sv + + const ndx = Math.floor(attr.positions.length / 3) + + let tint = [1, 1, 1] + if (eFace.tintindex !== undefined) { + if (eFace.tintindex === 0) { + // TODO + // if (block.name === 'redstone_wire') { + // tint = tints.redstone[`${block.getProperties().power}`] + // } else if (block.name === 'birch_leaves' || + // block.name === 'spruce_leaves' || + // block.name === 'lily_pad') { + // tint = tints.constant[block.name] + // } else if (block.name.includes('leaves') || block.name === 'vine') { + // tint = tints.foliage[biome] + // } else { + // tint = tints.grass[biome] + // } + } + } + + // UV rotation + const r = eFace.rotation || 0 + const uvcs = Math.cos(r * Math.PI / 180) + const uvsn = -Math.sin(r * Math.PI / 180) + + let localMatrix = null as any + let localShift = null as any + + if (element.rotation) { + // todo do we support rescale? + localMatrix = buildRotationMatrix( + element.rotation.axis, + element.rotation.angle + ) + + localShift = vecsub3( + element.rotation.origin, + matmul3( + localMatrix, + element.rotation.origin + ) + ) + } + + const aos: number[] = [] + // const neighborPos = position.plus(new Vec3(...dir)) + // const baseLight = world.getLight(neighborPos, undefined, undefined, block.name) / 15 + const baseLight = 1 + for (const pos of corners) { + let vertex = [ + (pos[0] ? maxx : minx), + (pos[1] ? maxy : miny), + (pos[2] ? maxz : minz) + ] + + vertex = vecadd3(matmul3(localMatrix, vertex), localShift) + vertex = vecadd3(matmul3(globalMatrix, vertex), globalShift) + vertex = vertex.map(v => v / 16) + + attr.positions.push( + vertex[0]/* + (cursor.x & 15) - 8 */, + vertex[1]/* + (cursor.y & 15) x */, + vertex[2]/* + (cursor.z & 15) - 8 */ + ) + + attr.normals.push(...dir) + + const baseu = (pos[3] - 0.5) * uvcs - (pos[4] - 0.5) * uvsn + 0.5 + const basev = (pos[3] - 0.5) * uvsn + (pos[4] - 0.5) * uvcs + 0.5 + attr.uvs.push(baseu * su + u, basev * sv + v) + + let light = 1 + if (doAO) { + const dx = pos[0] * 2 - 1 + const dy = pos[1] * 2 - 1 + const dz = pos[2] * 2 - 1 + const cornerDir = matmul3(globalMatrix, [dx, dy, dz]) + const side1Dir = matmul3(globalMatrix, [dx * mask1[0], dy * mask1[1], dz * mask1[2]]) + const side2Dir = matmul3(globalMatrix, [dx * mask2[0], dy * mask2[1], dz * mask2[2]]) + // const side1 = world.getBlock(cursor.offset(...side1Dir)) + // const side2 = world.getBlock(cursor.offset(...side2Dir)) + // const corner = world.getBlock(cursor.offset(...cornerDir)) + + let cornerLightResult = 15 + // if (/* world.config.smoothLighting */false) { // todo fix + // const side1Light = world.getLight(cursor.plus(new Vec3(...side1Dir)), true) + // const side2Light = world.getLight(cursor.plus(new Vec3(...side2Dir)), true) + // const cornerLight = world.getLight(cursor.plus(new Vec3(...cornerDir)), true) + // // interpolate + // cornerLightResult = (side1Light + side2Light + cornerLight) / 3 + // } + + // const side1Block = world.shouldMakeAo(side1) ? 1 : 0 + // const side2Block = world.shouldMakeAo(side2) ? 1 : 0 + // const cornerBlock = world.shouldMakeAo(corner) ? 1 : 0 + const side1Block = 0 + const side2Block = 0 + const cornerBlock = 0 + + // TODO: correctly interpolate ao light based on pos (evaluate once for each corner of the block) + + const ao = (side1Block && side2Block) ? 0 : (3 - (side1Block + side2Block + cornerBlock)) + // todo light should go upper on lower blocks + light = (ao + 1) / 4 * (cornerLightResult / 15) + aos.push(ao) + } + + attr.colors.push(baseLight * tint[0] * light, baseLight * tint[1] * light, baseLight * tint[2] * light) + } + + // if (needTiles) { + // attr.tiles[`${cursor.x},${cursor.y},${cursor.z}`] ??= { + // block: block.name, + // faces: [], + // } + // attr.tiles[`${cursor.x},${cursor.y},${cursor.z}`].faces.push({ + // face, + // neighbor: `${neighborPos.x},${neighborPos.y},${neighborPos.z}`, + // light: baseLight + // // texture: eFace.texture.name, + // }) + // } + + if (doAO && aos[0] + aos[3] >= aos[1] + aos[2]) { + attr.indices.push( + ndx, ndx + 3, ndx + 2, + ndx, ndx + 1, ndx + 3 + ) + } else { + attr.indices.push( + ndx, ndx + 1, ndx + 2, + ndx + 2, ndx + 1, ndx + 3 + ) + } + } +} + +export const renderBlockThreeAttr = (models: BlockModelPartsResolved, block: Block | undefined, biome: string, mcData: IndexedData, variants = [], neighbors: Neighbors = {}) => { + const sx = 0 + const sy = 0 + const sz = 0 + + const attr = { + sx: sx + 0.5, + sy: sy + 0.5, + sz: sz + 0.5, + positions: [], + normals: [], + colors: [], + uvs: [], + t_positions: [], + t_normals: [], + t_colors: [], + t_uvs: [], + indices: [], + tiles: {}, + } as Record + + for (const [i, modelVars] of models.entries()) { + const model = modelVars[variants[i]] ?? modelVars[0] + if (!model) continue + let globalMatrix = null as any + let globalShift = null as any + for (const axis of ['x', 'y', 'z'] as const) { + if (axis in model) { + if (!globalMatrix) globalMatrix = buildRotationMatrix(axis, -(model[axis] ?? 0)) + else globalMatrix = matmulmat3(globalMatrix, buildRotationMatrix(axis, -(model[axis] ?? 0))) + } + } + if (globalMatrix) { + globalShift = [8, 8, 8] + globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift)) + } + + const ao = model.ao ?? true + + for (const element of model.elements ?? []) { + renderElement(element, ao, attr, globalMatrix, globalShift, block, biome, neighbors) + } + } + + let ndx = attr.positions.length / 3 + for (let i = 0; i < attr.t_positions.length / 12; i++) { + attr.indices.push( + ndx, ndx + 1, ndx + 2, + ndx + 2, ndx + 1, ndx + 3, + // back face + ndx, ndx + 2, ndx + 1, + ndx + 2, ndx + 3, ndx + 1 + ) + ndx += 4 + } + + attr.positions.push(...attr.t_positions) + attr.normals.push(...attr.t_normals) + attr.colors.push(...attr.t_colors) + attr.uvs.push(...attr.t_uvs) + + delete attr.t_positions + delete attr.t_normals + delete attr.t_colors + delete attr.t_uvs + + attr.positions = new Float32Array(attr.positions) as any + attr.normals = new Float32Array(attr.normals) as any + attr.colors = new Float32Array(attr.colors) as any + attr.uvs = new Float32Array(attr.uvs) as any + + return attr +} + +export const renderBlockThree = (...args: Parameters) => { + const attr = renderBlockThreeAttr(...args) + const data = { + geometry: attr + } + + const geometry = new THREE.BufferGeometry() + geometry.setAttribute('position', new THREE.BufferAttribute(data.geometry.positions, 3)) + geometry.setAttribute('normal', new THREE.BufferAttribute(data.geometry.normals, 3)) + geometry.setAttribute('color', new THREE.BufferAttribute(data.geometry.colors, 3)) + geometry.setAttribute('uv', new THREE.BufferAttribute(data.geometry.uvs, 2)) + geometry.setIndex(data.geometry.indices) + geometry.name = 'block-geometry' + + return geometry +} diff --git a/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts b/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts index 6103a3d42..02576536e 100644 --- a/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts +++ b/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts @@ -3,10 +3,11 @@ import { World as MesherWorld } from '../world' import ChunkLoader, { PCChunk } from 'prismarine-chunk' import { Vec3 } from 'vec3' import MinecraftData from 'minecraft-data' +import blocksAtlasesJson from 'mc-assets/dist/blocksAtlases.json' export const setup = (version, initialBlocks: [number[], string][]) => { const mcData = MinecraftData(version) - const blockStates = require(`../../../../public/blocksStates/${version}.json`) + const blockStatesModels = require(`mc-assets/dist/blockStatesModels.json`) const mesherWorld = new MesherWorld(version) const Chunk = ChunkLoader(version) const chunk1 = new Chunk(undefined as any) @@ -31,7 +32,7 @@ export const setup = (version, initialBlocks: [number[], string][]) => { } } - setBlockStatesData(blockStates, true) + setBlockStatesData(blockStatesModels, blocksAtlasesJson, true, false) const reload = () => { mesherWorld.removeColumn(0, 0) mesherWorld.addColumn(0, 0, chunk1.toJson()) diff --git a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts index de5db815a..757056c79 100644 --- a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts +++ b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts @@ -1,9 +1,8 @@ import { test, expect } from 'vitest' import { setup } from './mesherTester' -import minecraftData from 'minecraft-data' -import minecraftAssets from 'minecraft-assets' +import supportedVersions from '../../../../../src/supportedVersions.mjs' -const version = minecraftAssets.versions.at(-1) +const lastVersion = supportedVersions.at(-1) const addPositions = [ // [[0, 0, 0], 'diamond_block'], @@ -16,7 +15,7 @@ const addPositions = [ ] as const test('Known blocks are not rendered', () => { - const { mesherWorld, getGeometry, pos, mcData } = setup(version, addPositions as any) + const { mesherWorld, getGeometry, pos, mcData } = setup(lastVersion, addPositions as any) const ignoreAsExpected = ['air', 'cave_air', 'void_air', 'barrier', 'water', 'lava', 'moving_piston', 'light'] let time = 0 @@ -45,96 +44,27 @@ test('Known blocks are not rendered', () => { // should be fixed, but to avoid regressions & for visibility expect(invalidBlocks).toMatchInlineSnapshot(` { - "black_banner": true, - "black_bed": true, - "black_candle": true, - "black_wall_banner": true, - "blue_banner": true, - "blue_bed": true, - "blue_candle": true, - "blue_wall_banner": true, - "brown_banner": true, - "brown_bed": true, - "brown_candle": true, - "brown_wall_banner": true, + "black_glazed_terracotta": true, + "blue_glazed_terracotta": true, + "brown_glazed_terracotta": true, "bubble_column": true, - "candle": true, - "creeper_head": true, - "creeper_wall_head": true, - "cyan_banner": true, - "cyan_bed": true, - "cyan_candle": true, - "cyan_wall_banner": true, - "dragon_head": true, - "dragon_wall_head": true, + "cyan_glazed_terracotta": true, "end_gateway": true, "end_portal": true, - "gray_banner": true, - "gray_bed": true, - "gray_candle": true, - "gray_wall_banner": true, - "green_banner": true, - "green_bed": true, - "green_candle": true, - "green_wall_banner": true, - "light_blue_banner": true, - "light_blue_bed": true, - "light_blue_candle": true, - "light_blue_wall_banner": true, - "light_gray_banner": true, - "light_gray_bed": true, - "light_gray_candle": true, - "light_gray_wall_banner": true, - "lime_banner": true, - "lime_bed": true, - "lime_candle": true, - "lime_wall_banner": true, - "magenta_banner": true, - "magenta_bed": true, - "magenta_candle": true, - "magenta_wall_banner": true, - "orange_banner": true, - "orange_bed": true, - "orange_candle": true, - "orange_wall_banner": true, - "piglin_head": true, - "piglin_wall_head": true, - "pink_banner": true, - "pink_bed": true, - "pink_candle": true, - "pink_petals": true, - "pink_wall_banner": true, - "player_head": true, - "player_wall_head": true, - "powder_snow_cauldron": true, - "purple_banner": true, - "purple_bed": true, - "purple_candle": true, - "purple_wall_banner": true, - "red_banner": true, - "red_bed": true, - "red_candle": true, - "red_wall_banner": true, - "repeater": true, - "sea_pickle": true, - "skeleton_skull": true, - "skeleton_wall_skull": true, - "snow": true, + "gray_glazed_terracotta": true, + "green_glazed_terracotta": true, + "light_blue_glazed_terracotta": true, + "light_gray_glazed_terracotta": true, + "lime_glazed_terracotta": true, + "magenta_glazed_terracotta": true, + "orange_glazed_terracotta": true, + "pink_glazed_terracotta": true, + "purple_glazed_terracotta": true, + "red_glazed_terracotta": true, "structure_void": true, - "turtle_egg": true, - "water_cauldron": true, - "white_banner": true, - "white_bed": true, - "white_candle": true, - "white_wall_banner": true, - "wither_skeleton_skull": true, - "wither_skeleton_wall_skull": true, - "yellow_banner": true, - "yellow_bed": true, - "yellow_candle": true, - "yellow_wall_banner": true, - "zombie_head": true, - "zombie_wall_head": true, + "trial_spawner": true, + "white_glazed_terracotta": true, + "yellow_glazed_terracotta": true, } `) }) diff --git a/prismarine-viewer/viewer/lib/mesher/world.ts b/prismarine-viewer/viewer/lib/mesher/world.ts index 71b859f40..cc4480376 100644 --- a/prismarine-viewer/viewer/lib/mesher/world.ts +++ b/prismarine-viewer/viewer/lib/mesher/world.ts @@ -5,6 +5,7 @@ import { Vec3 } from 'vec3' import moreBlockDataGeneratedJson from '../moreBlockDataGenerated.json' import { defaultMesherConfig } from './shared' import legacyJson from '../../../../src/preflatMap.json' +import { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider' const ignoreAoBlocks = Object.keys(moreBlockDataGeneratedJson.noOcclusions) @@ -18,10 +19,13 @@ function isCube (shapes) { return shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1 } +export type BlockModelPartsResolved = ReturnType + export type WorldBlock = Omit & { - variant?: any // todo isCube: boolean + /** cache */ + models?: BlockModelPartsResolved | null } diff --git a/prismarine-viewer/viewer/lib/version.js b/prismarine-viewer/viewer/lib/version.js deleted file mode 100644 index 804bd0c7a..000000000 --- a/prismarine-viewer/viewer/lib/version.js +++ /dev/null @@ -1,30 +0,0 @@ -const supportedVersions = require('../../public/supportedVersions.json') - -const lastOfMajor = {} -for (const version of supportedVersions) { - const major = toMajor(version) - if (lastOfMajor[major]) { - if (minor(lastOfMajor[major]) < minor(version)) { - lastOfMajor[major] = version - } - } else { - lastOfMajor[major] = version - } -} - -function toMajor (version) { - const [a, b] = (version + '').split('.') - return a + '.' + b -} - -function minor (version) { - const [, , c] = (version + '.0').split('.') - return parseInt(c, 10) -} - -function getVersion (version) { - if (supportedVersions.indexOf(version) !== -1) return version - return lastOfMajor[toMajor(version)] ?? Object.values(lastOfMajor).at(-1) -} - -module.exports = { getVersion, toMajor } diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts index 504c46372..f281c525c 100644 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ b/prismarine-viewer/viewer/lib/viewer.ts @@ -2,12 +2,13 @@ import * as THREE from 'three' import { Vec3 } from 'vec3' import { Entities } from './entities' import { Primitives } from './primitives' -import { getVersion } from './version' import EventEmitter from 'events' import { WorldRendererThree } from './worldrendererThree' import { generateSpiralMatrix } from 'flying-squid/dist/utils' import { WorldRendererCommon, WorldRendererConfig, defaultWorldRendererConfig } from './worldrendererCommon' import { versionToNumber } from '../prepare/utils' +import worldBlockProvider from 'mc-assets/dist/worldBlockProvider' +import { renderBlockThree } from './mesher/standaloneRenderer' export class Viewer { scene: THREE.Scene @@ -76,11 +77,13 @@ export class Viewer { // this.primitives.clear() } - setVersion (userVersion: string) { - let texturesVersion = getVersion(userVersion) - if (versionToNumber(userVersion) < versionToNumber('1.13')) texturesVersion = '1.13.2' // we normalize to post-flatenning in mesher + setVersion (userVersion: string, texturesVersion = userVersion) { console.log('[viewer] Using version:', userVersion, 'textures:', texturesVersion) - this.world.setVersion(userVersion, texturesVersion) + this.world.setVersion(userVersion, texturesVersion).then(() => { + return new THREE.TextureLoader().loadAsync(this.world.itemsAtlasParser!.latestImage) + }).then((texture) => { + this.entities.itemsTexture = texture + }) this.entities.clear() // this.primitives.clear() } @@ -97,6 +100,24 @@ export class Viewer { this.world.setBlockStateId(pos, stateId) } + demoModel () { + const blockProvider = worldBlockProvider(this.world.blockstatesModels, this.world.blocksAtlases, 'latest') + const models = blockProvider.getAllResolvedModels0_1({ + name: 'item_frame', + properties: { + map: false + } + }) + const geometry = renderBlockThree(models, undefined, 'plains', loadedData) + const material = this.world.material + // block material + const mesh = new THREE.Mesh(geometry, material) + mesh.position.set(this.camera.position.x, this.camera.position.y, this.camera.position.z) + const helper = new THREE.BoxHelper(mesh, 0xffff00) + mesh.add(helper) + this.scene.add(mesh) + } + updateEntity (e) { this.entities.update(e, this.processEntityOverrides(e, { rotation: { diff --git a/prismarine-viewer/viewer/lib/worldrendererCommon.ts b/prismarine-viewer/viewer/lib/worldrendererCommon.ts index 1a87fa5d6..b381a7a5a 100644 --- a/prismarine-viewer/viewer/lib/worldrendererCommon.ts +++ b/prismarine-viewer/viewer/lib/worldrendererCommon.ts @@ -5,10 +5,18 @@ import { loadTexture } from './utils.web' import { EventEmitter } from 'events' import mcDataRaw from 'minecraft-data/data.js' // handled correctly in esbuild plugin import { dynamicMcDataFiles } from '../../buildMesherConfig.mjs' -import { toMajor } from './version.js' import { chunkPos } from './simpleUtils' import { defaultMesherConfig } from './mesher/shared' import { buildCleanupDecorator } from './cleanupDecorator' +import blocksAtlases from 'mc-assets/dist/blocksAtlases.json' +import blocksAtlasLatest from 'mc-assets/dist/blocksAtlasLatest.png' +import blocksAtlasLegacy from 'mc-assets/dist/blocksAtlasLegacy.png' +import itemsAtlases from 'mc-assets/dist/itemsAtlases.json' +import itemsAtlasLatest from 'mc-assets/dist/itemsAtlasLatest.png' +import itemsAtlasLegacy from 'mc-assets/dist/itemsAtlasLegacy.png' +import { AtlasParser } from 'mc-assets' +import { getResourcepackTiles } from '../../../src/resourcePack' +import { toMajorVersion } from '../../../src/utils' function mod (x, n) { return ((x % n) + n) % n @@ -23,6 +31,11 @@ export const defaultWorldRendererConfig = { export type WorldRendererConfig = typeof defaultWorldRendererConfig +type CustomTexturesData = { + tileSize: number | undefined + textures: Record +} + export abstract class WorldRendererCommon { worldConfig = { minY: 0, worldHeight: 256 } material = new THREE.MeshLambertMaterial({ vertexColors: true, transparent: true, alphaTest: 0.1 }) @@ -36,11 +49,10 @@ export abstract class WorldRendererCommon finishedChunks = {} as Record @worldCleanup() sectionsOutstanding = new Map() + @worldCleanup() renderUpdateEmitter = new EventEmitter() - customBlockStatesData = undefined as any customTexturesDataUrl = undefined as string | undefined - downloadedBlockStatesData = undefined as any - downloadedTextureImage = undefined as any + currentTextureImage = undefined as any workers: any[] = [] viewerPosition?: Vec3 lastCamUpdate = 0 @@ -55,10 +67,22 @@ export abstract class WorldRendererCommon handleResize = () => { } mesherConfig = defaultMesherConfig camera: THREE.PerspectiveCamera + blockstatesModels: any + customBlockStates: Record | undefined + customModels: Record | undefined + itemsAtlasParser: AtlasParser | undefined + blocksAtlasParser: AtlasParser | undefined + + blocksAtlases = blocksAtlases + itemsAtlases = itemsAtlases + customTextures: { + items?: CustomTexturesData + blocks?: CustomTexturesData + } = {} abstract outputFormat: 'threeJs' | 'webgl' - constructor(public config: WorldRendererConfig) { + constructor (public config: WorldRendererConfig) { // this.initWorkers(1) // preload script on page load this.snapshotInitialValues() } @@ -161,10 +185,14 @@ export abstract class WorldRendererCommon worker.terminate() } this.workers = [] + this.currentTextureImage = undefined + this.blocksAtlasParser = undefined + this.itemsAtlasParser = undefined } // new game load happens here - setVersion (version, texturesVersion = version) { + async setVersion (version, texturesVersion = version) { + if (!this.blockstatesModels) throw new Error('Blockstates models is not loaded yet') this.version = version this.texturesVersion = texturesVersion this.resetWorld() @@ -174,11 +202,11 @@ export abstract class WorldRendererCommon this.mesherConfig.version = this.version! this.sendMesherMcData() - this.updateTexturesData() + await this.updateTexturesData() } sendMesherMcData () { - const allMcData = mcDataRaw.pc[this.version] ?? mcDataRaw.pc[toMajor(this.version)] + const allMcData = mcDataRaw.pc[this.version] ?? mcDataRaw.pc[toMajorVersion(this.version)] const mcData = Object.fromEntries(Object.entries(allMcData).filter(([key]) => dynamicMcDataFiles.includes(key))) mcData.version = JSON.parse(JSON.stringify(mcData.version)) @@ -187,38 +215,56 @@ export abstract class WorldRendererCommon } } - updateTexturesData () { - loadTexture(this.customTexturesDataUrl || `textures/${this.texturesVersion}.png`, (texture: import('three').Texture) => { - texture.magFilter = THREE.NearestFilter - texture.minFilter = THREE.NearestFilter - texture.flipY = false - this.material.map = texture - }, () => { - this.downloadedTextureImage = this.material.map!.image - const loadBlockStates = async () => { - return new Promise(resolve => { - if (this.customBlockStatesData) return resolve(this.customBlockStatesData) - return loadJSON(`/blocksStates/${this.texturesVersion}.json`, (data) => { - this.downloadedBlockStatesData = data - this.renderUpdateEmitter.emit('blockStatesDownloaded') - resolve(data) - }) - }) + async updateTexturesData () { + const blocksAssetsParser = new AtlasParser(this.blocksAtlases, blocksAtlasLatest, blocksAtlasLegacy) + const itemsAssetsParser = new AtlasParser(this.itemsAtlases, itemsAtlasLatest, itemsAtlasLegacy) + const { atlas: blocksAtlas, canvas: blocksCanvas } = await blocksAssetsParser.makeNewAtlas(this.texturesVersion ?? this.version ?? 'latest', (textureName) => { + const texture = this.customTextures?.blocks?.textures[textureName] + if (!texture) return + return texture + }, this.customTextures?.blocks?.tileSize) + const { atlas: itemsAtlas, canvas: itemsCanvas } = await itemsAssetsParser.makeNewAtlas(this.texturesVersion ?? this.version ?? 'latest', (textureName) => { + const texture = this.customTextures?.items?.textures[textureName] + if (!texture) return + return texture + }, this.customTextures?.items?.tileSize) + this.blocksAtlasParser = new AtlasParser({ latest: blocksAtlas }, blocksCanvas.toDataURL()) + this.itemsAtlasParser = new AtlasParser({ latest: itemsAtlas }, itemsCanvas.toDataURL()) + + const texture = await new THREE.TextureLoader().loadAsync(this.blocksAtlasParser.latestImage) + texture.magFilter = THREE.NearestFilter + texture.minFilter = THREE.NearestFilter + texture.flipY = false + this.material.map = texture + this.currentTextureImage = this.material.map!.image + this.mesherConfig.textureSize = this.material.map!.image.width + + for (const worker of this.workers) { + const blockstatesModels = this.blockstatesModels + if (this.customBlockStates) { + // TODO! remove from other versions as well + blockstatesModels.blockstates.latest = { + ...blockstatesModels.blockstates.latest, + ...this.customBlockStates + } } - loadBlockStates().then((blockStates) => { - this.mesherConfig.textureSize = this.material.map!.image.width - - for (const worker of this.workers) { - worker.postMessage({ - type: 'mesherData', - json: blockStates, - config: this.mesherConfig, - }) + if (this.customModels) { + blockstatesModels.models.latest = { + ...blockstatesModels.models.latest, + ...this.customModels } - this.renderUpdateEmitter.emit('textureDownloaded') + } + worker.postMessage({ + type: 'mesherData', + blocksAtlas: { + latest: blocksAtlas + }, + blockstatesModels, + config: this.mesherConfig, }) - }) - + } + this.renderUpdateEmitter.emit('textureDownloaded') + console.log('texture loaded') } addColumn (x: number, z: number, chunk: any, isLightUpdate: boolean) { diff --git a/prismarine-viewer/viewer/prepare/atlas.ts b/prismarine-viewer/viewer/prepare/atlas.ts deleted file mode 100644 index cf73fdc4e..000000000 --- a/prismarine-viewer/viewer/prepare/atlas.ts +++ /dev/null @@ -1,144 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { Canvas, Image } from 'canvas' -import { getAdditionalTextures } from './moreGeneratedBlocks' -import { McAssets } from './modelsBuilder' - -function nextPowerOfTwo (n) { - if (n === 0) return 1 - n-- - n |= n >> 1 - n |= n >> 2 - n |= n >> 4 - n |= n >> 8 - n |= n >> 16 - return n + 1 -} - -const localTextures = ['missing_texture.png'] - -function readTexture (basePath, name) { - if (localTextures.includes(name)) { - // grab ./missing_texture.png - basePath = __dirname - } - return fs.readFileSync(path.join(basePath, name), 'base64') -} - -export type JsonAtlas = { - size: number, - textures: { - [file: string]: { - u: number, - v: number, - } - } -} - -export const makeTextureAtlas = (input: string[], getInputData: (name) => { contents: string, tileWidthMult?: number, origSizeTextures?}, tilesCount = input.length, suSvOptimize: 'remove' | null = null): { - image: Buffer, - canvas: Canvas, - json: JsonAtlas -} => { - const texSize = nextPowerOfTwo(Math.ceil(Math.sqrt(tilesCount))) - const tileSize = 16 - - const imgSize = texSize * tileSize - const canvas = new Canvas(imgSize, imgSize, 'png' as any) - const g = canvas.getContext('2d') - - const texturesIndex = {} - - let nextX = 0 - let nextY = 0 - let rowMaxY = 0 - - const goToNextRow = () => { - nextX = 0 - nextY += rowMaxY - rowMaxY = 0 - } - - const suSv = tileSize / imgSize - for (const i in input) { - const img = new Image() - const keyValue = input[i] - const inputData = getInputData(keyValue) - img.src = inputData.contents - let su = suSv - let sv = suSv - let renderWidth = tileSize * (inputData.tileWidthMult ?? 1) - let renderHeight = tileSize - if (inputData.origSizeTextures?.[keyValue]) { - // todo check have enough space - renderWidth = Math.ceil(img.width / tileSize) * tileSize - renderHeight = Math.ceil(img.height / tileSize) * tileSize - su = renderWidth / imgSize - sv = renderHeight / imgSize - if (renderHeight > imgSize || renderWidth > imgSize) { - throw new Error('Texture ' + keyValue + ' is too big') - } - } - - if (nextX + renderWidth > imgSize) { - goToNextRow() - } - - const x = nextX - const y = nextY - - nextX += renderWidth - rowMaxY = Math.max(rowMaxY, renderHeight) - if (nextX >= imgSize) { - goToNextRow() - } - - g.drawImage(img, 0, 0, renderWidth, renderHeight, x, y, renderWidth, renderHeight) - - const cleanName = keyValue.split('.').slice(0, -1).join('.') || keyValue - texturesIndex[cleanName] = { - u: x / imgSize, - v: y / imgSize, - ...suSvOptimize === 'remove' ? {} : { - su: su, - sv: sv - } - } - } - - return { image: canvas.toBuffer(), canvas, json: { size: suSv, textures: texturesIndex } } -} - -export const writeCanvasStream = (canvas, path, onEnd) => { - const out = fs.createWriteStream(path) - const stream = (canvas as any).pngStream() - stream.on('data', (chunk) => out.write(chunk)) - if (onEnd) stream.on('end', onEnd) - return stream -} - -export function makeBlockTextureAtlas (mcAssets: McAssets) { - const blocksTexturePath = path.join(mcAssets.directory, '/blocks') - const textureFiles = fs.readdirSync(blocksTexturePath).filter(file => file.endsWith('.png')) - // const textureFiles = mostEncounteredBlocks.map(x => x + '.png') - textureFiles.unshift(...localTextures) - - const { generated: additionalTextures, origSizeTextures } = getAdditionalTextures() - textureFiles.push(...Object.keys(additionalTextures)) - - const atlas = makeTextureAtlas(textureFiles, name => { - let contents: string - if (additionalTextures[name]) { - contents = additionalTextures[name] - } else { - contents = 'data:image/png;base64,' + readTexture(blocksTexturePath, name) - } - - return { - contents, - // tileWidthMult: twoTileTextures.includes(name) ? 2 : undefined, - origSizeTextures - } - }) - return atlas -} diff --git a/prismarine-viewer/viewer/prepare/genItemsAtlas.ts b/prismarine-viewer/viewer/prepare/genItemsAtlas.ts deleted file mode 100644 index 788f1b60d..000000000 --- a/prismarine-viewer/viewer/prepare/genItemsAtlas.ts +++ /dev/null @@ -1,148 +0,0 @@ -import fs from 'fs' -import McAssets from 'minecraft-assets' -import { join } from 'path' -import { filesize } from 'filesize' -import minecraftDataLoader from 'minecraft-data' -import BlockLoader from 'prismarine-block' -import { JsonAtlas, makeTextureAtlas, writeCanvasStream } from './atlas' -import looksSame from 'looks-same' // ensure after canvas import -import { Version as _Version } from 'minecraft-data' -import { versionToNumber } from './utils' - -// todo move it, remove it -const legacyInvsprite = JSON.parse(fs.readFileSync(join(__dirname, '../../../src/invsprite.json'), 'utf8')) - -//@ts-ignore -const latestMcAssetsVersion = McAssets.versions.at(-1)! -// const latestVersion = minecraftDataLoader.supportedVersions.pc.at(-1) -const mcData = minecraftDataLoader(latestMcAssetsVersion) -const PBlock = BlockLoader(latestMcAssetsVersion) - -function isCube (name) { - const id = mcData.blocksByName[name]?.id - if (!id) return - const block = new PBlock(id, 0, 0) - const shape = block.shapes?.[0] - return block.shapes?.length === 1 && shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1 -} - -export type ItemsAtlasesOutputJson = { - latest: JsonAtlas - legacy: JsonAtlas - legacyMap: [string, string[]][] -} - -export const generateItemsAtlases = async () => { - const latestAssets = McAssets(latestMcAssetsVersion) - const latestItems = fs.readdirSync(join(latestAssets.directory, 'items')).map(f => f.split('.')[0]) - - // item - texture path - const toAddTextures = { - fromBlocks: {} as Record, - remapItems: {} as Record, // todo - } - - const getItemTextureOfBlock = (name: string) => { - const blockModel = latestAssets.blocksModels[name] - // const isPlainBlockDisplay = blockModel?.display?.gui?.rotation?.[0] === 0 && blockModel?.display?.gui?.rotation?.[1] === 0 && blockModel?.display?.gui?.rotation?.[2] === 0 - // it seems that information about cross blocks is hardcoded - if (blockModel?.parent?.endsWith('block/cross')) { - toAddTextures.fromBlocks[name] = `blocks/${blockModel.textures.cross.split('/')[1]}` - return true - } - - if (legacyInvsprite[name]) { - return true - } - - if (fs.existsSync(join(latestAssets.directory, 'blocks', name + '.png'))) { - // very last resort - toAddTextures.fromBlocks[name] = `blocks/${name}` - return true - } - if (name.endsWith('_spawn_egg')) { - // todo also color - toAddTextures.fromBlocks[name] = `items/spawn_egg` - } - } - - for (const item of mcData.itemsArray) { - if (latestItems.includes(item.name)) { - continue - } - // USE IN RUNTIME - if (isCube(item.name)) { - // console.log('cube', block.name) - } else if (!getItemTextureOfBlock(item.name)) { - console.warn('skipping item (not cube, no item texture)', item.name) - } - } - - let fullItemsMap = {} as Record - - const itemsSizes = {} - let saving = 0 - let overallsize = 0 - let prevItemsDir - let prevVersion - for (const version of [...McAssets.versions].reverse()) { - const itemsDir = join(McAssets(version).directory, 'items') - for (const item of fs.readdirSync(itemsDir)) { - const prevItemPath = !prevItemsDir ? undefined : join(prevItemsDir, item) - const itemSize = fs.statSync(join(itemsDir, item)).size - if (prevItemPath && fs.existsSync(prevItemPath) && (await looksSame(join(itemsDir, item), prevItemPath, { strict: true })).equal) { - saving += itemSize - } else { - fullItemsMap[version] ??= [] - fullItemsMap[version].push(item) - } - overallsize += itemSize - } - prevItemsDir = itemsDir - prevVersion = version - } - - fullItemsMap = Object.fromEntries(Object.entries(fullItemsMap).map(([ver, items]) => [ver, items.filter(item => item.endsWith('.png'))])) - const latestVersionItems = fullItemsMap[latestMcAssetsVersion] - delete fullItemsMap[latestMcAssetsVersion] - const legacyItemsSortedEntries = Object.entries(fullItemsMap).sort(([a], [b]) => versionToNumber(a) - versionToNumber(b)).map(([key, value]) => [key, value.map(x => x.replace('.png', ''))] as [typeof key, typeof value]) - // const allItemsLength = Object.values(fullItemsMap).reduce((acc, x) => acc + x.length, 0) - // console.log(`Items to generate: ${allItemsLength} (latest version: ${latestVersionItems.length})`) - const fullLatestItemsObject = { - ...Object.fromEntries(latestVersionItems.map(item => [item, `items/${item.replace('.png', '')}`])), - ...toAddTextures.fromBlocks, - ...toAddTextures.remapItems - } - - const latestAtlas = makeTextureAtlas(Object.keys(fullLatestItemsObject), (name) => { - const contents = `data:image/png;base64,${fs.readFileSync(join(latestAssets.directory, `${fullLatestItemsObject[name]}.png`), 'base64')}` - return { - contents, - } - }, undefined, 'remove') - const texturesPath = join(__dirname, '../../public/textures') - writeCanvasStream(latestAtlas.canvas, join(texturesPath, 'items.png'), () => { - console.log('Generated latest items atlas') - }) - - const legacyItemsMap = legacyItemsSortedEntries.flatMap(([ver, items]) => items.map(item => `${ver}-${item}.png`)) - const legacyItemsAtlas = makeTextureAtlas(legacyItemsMap, (name) => { - const [ver, item] = name.split('-') - const contents = `data:image/png;base64,${fs.readFileSync(join(McAssets(ver).directory, `items/${item}`), 'base64')}` - return { - contents, - } - }, undefined, 'remove') - writeCanvasStream(legacyItemsAtlas.canvas, join(texturesPath, 'items-legacy.png'), () => { - console.log('Generated legacy items atlas') - }) - - const allItemsMaps: ItemsAtlasesOutputJson = { - latest: latestAtlas.json, - legacy: legacyItemsAtlas.json, - legacyMap: legacyItemsSortedEntries - } - fs.writeFileSync(join(texturesPath, 'items.json'), JSON.stringify(allItemsMaps), 'utf8') - - console.log(`Generated items! Input size: ${filesize(overallsize)}, saving: ~${filesize(saving)}`) -} diff --git a/prismarine-viewer/viewer/prepare/generateTextures.ts b/prismarine-viewer/viewer/prepare/generateTextures.ts deleted file mode 100644 index f66fb5d75..000000000 --- a/prismarine-viewer/viewer/prepare/generateTextures.ts +++ /dev/null @@ -1,52 +0,0 @@ -import path from 'path' -import { makeBlockTextureAtlas } from './atlas' -import { prepareBlocksStates } from './modelsBuilder' -import mcAssets from 'minecraft-assets' -import fs from 'fs-extra' -import { prepareMoreGeneratedBlocks } from './moreGeneratedBlocks' -import { generateItemsAtlases } from './genItemsAtlas' -import { versionToNumber } from './utils' - -const publicPath = path.resolve(__dirname, '../../public') - -const texturesPath = path.join(publicPath, 'textures') -fs.mkdirSync(texturesPath, { recursive: true }) - -const blockStatesPath = path.join(publicPath, 'blocksStates') -fs.mkdirSync(blockStatesPath, { recursive: true }) - -const warnings = new Set() -Promise.resolve().then(async () => { - generateItemsAtlases() - console.time('generateTextures') - const versions = process.argv.includes('-l') ? [mcAssets.versions.at(-1)!] : mcAssets.versions - for (const version of versions as typeof mcAssets['versions']) { - // for debugging (e.g. when above is overridden) - if (!versions.includes(version)) { - throw new Error(`Version ${version} is not supported by minecraft-assets`) - } - if (versionToNumber(version) < versionToNumber('1.13')) { - // we normalize data to 1.13 for pre 1.13 versions - continue - } - const assets = mcAssets(version) - const { warnings: _warnings } = await prepareMoreGeneratedBlocks(assets) - _warnings.forEach(x => warnings.add(x)) - // #region texture atlas - const atlas = makeBlockTextureAtlas(assets) - const out = fs.createWriteStream(path.resolve(texturesPath, version + '.png')) - const stream = (atlas.canvas as any).pngStream() - stream.on('data', (chunk) => out.write(chunk)) - stream.on('end', () => console.log('Generated textures/' + version + '.png')) - // #endregion - - const blocksStates = JSON.stringify(prepareBlocksStates(assets, atlas)) - fs.writeFileSync(path.resolve(blockStatesPath, version + '.json'), blocksStates) - - fs.copySync(assets.directory, path.resolve(texturesPath, version), { overwrite: true }) - } - - fs.writeFileSync(path.join(publicPath, 'supportedVersions.json'), '[' + versions.map(v => `"${v}"`).toString() + ']') - warnings.forEach(x => console.warn(x)) - console.timeEnd('generateTextures') -}) diff --git a/prismarine-viewer/viewer/prepare/missing_texture.png b/prismarine-viewer/viewer/prepare/missing_texture.png deleted file mode 100644 index affd9d681..000000000 Binary files a/prismarine-viewer/viewer/prepare/missing_texture.png and /dev/null differ diff --git a/prismarine-viewer/viewer/prepare/modelsBuilder.ts b/prismarine-viewer/viewer/prepare/modelsBuilder.ts deleted file mode 100644 index b6e5268f1..000000000 --- a/prismarine-viewer/viewer/prepare/modelsBuilder.ts +++ /dev/null @@ -1,259 +0,0 @@ -type ModelBasic = { - model: string - x?: number - y?: number - uvlock?: boolean -} - -type BlockApplyModel = ModelBasic | (ModelBasic & { weight })[] - -type BlockStateCondition = { - [name: string]: string | number -} - -type BlockState = { - variants?: { - [name: string | ""]: BlockApplyModel - } - multipart?: { - when: { - [name: string]: string | number - } & { - OR?: BlockStateCondition[] - } - apply: BlockApplyModel - }[] -} - -type BlockModel = { - parent?: string - textures?: { - [name: string]: string - } - elements?: { - from: number[] - to: number[] - faces: { - [name: string]: { - texture: string - uv?: number[] - cullface?: string - } - } - }[] - ambientocclusion?: boolean - x?: number - y?: number - z?: number - ao?: boolean -} - -export type McAssets = { - blocksStates: { - [x: string]: BlockState - } - blocksModels: { - [x: string]: BlockModel - } - directory: string - version: string -} - -export type BlockStatesOutput = { - // states: { - [blockName: string]: any/* ResolvedModel */ - // } - // defaults: { - // su: number - // sv: number - // } -} - -export type ResolvedModel = { - textures: { - [name: string]: { - u: number - v: number - su: number - sv: number - bu: number - bv: number - } - } - elements: { - from: number[] - to: number[] - faces: { - [name: string]: { - texture: { - u: number - v: number - su: number - sv: number - bu: number - bv: number - } - } - } - }[] - ao: boolean - x?: number - y?: number - z?: number -} - -export const addBlockAllModel = (mcAssets: McAssets, name: string, texture = name) => { - mcAssets.blocksStates[name] = { - "variants": { - "": { - "model": name - } - } - } - mcAssets.blocksModels[name] = { - "parent": "block/cube_all", - "textures": { - "all": `blocks/${texture}` - } - } -} - -function cleanupBlockName (name: string) { - if (name.startsWith('block') || name.startsWith('minecraft:block')) return name.split('/')[1] - return name -} - -const objectAssignStrict = > (target: T, source: Partial) => Object.assign(target, source) - -function getFinalModel (name: string, blocksModels: { [x: string]: BlockModel }) { - name = cleanupBlockName(name) - const input = blocksModels[name] - if (!input) { - return null - } - - let out: BlockModel | null = { - textures: {}, - elements: [], - ao: true, - x: input.x, - y: input.y, - z: input.z, - } - - if (input.parent) { - out = getFinalModel(input.parent, blocksModels) - if (!out) return null - } - if (input.textures) { - Object.assign(out.textures!, deepCopy(input.textures)) - } - if (input.elements) out.elements = deepCopy(input.elements) - if (input.ao !== undefined) out.ao = input.ao - return out -} - -const deepCopy = (obj) => JSON.parse(JSON.stringify(obj)) - -const workerUsedTextures = ['particle'] -function prepareModel (model: BlockModel, texturesJson) { - const newModel = {} - - const getFinalTexture = (originalBlockName) => { - // texture name e.g. blocks/anvil_base - const cleanBlockName = cleanupBlockName(originalBlockName) - return { ...texturesJson[cleanBlockName], /* __debugName: cleanBlockName */ } - } - - const finalTextures = [] - - // resolve texture names eg west: #all -> blocks/stone - for (const side in model.textures) { - let texture = model.textures[side] - - while (texture.charAt(0) === '#') { - const textureName = texture.slice(1) - texture = model.textures[textureName] - if (texture === undefined) throw new Error(`Texture ${textureName} in ${JSON.stringify(model.textures)} not found`) - } - - finalTextures[side] = getFinalTexture(texture) - if (workerUsedTextures.includes(side)) { - model.textures[side] = finalTextures[side] - } - } - - for (const elem of model.elements!) { - for (const sideName of Object.keys(elem.faces)) { - const face = elem.faces[sideName] - - const textureRaw = face.texture.charAt(0) === '#' - ? finalTextures![face.texture.slice(1)] - : getFinalTexture(face.texture) - if (!textureRaw) throw new Error(`Texture ${face.texture} in ${JSON.stringify(model.textures)} not found`) - const finalTexture = deepCopy( - textureRaw - ) - - const _from = elem.from - const _to = elem.to - // taken from https://github.com/DragonDev1906/Minecraft-Overviewer/ - const uv = face.uv || { - // default UVs - // format: [u1, v1, u2, v2] (u = x, v = y) - north: [_to[0], 16 - _to[1], _from[0], 16 - _from[1]], - east: [_from[2], 16 - _to[1], _to[2], 16 - _from[1]], - south: [_from[0], 16 - _to[1], _to[0], 16 - _from[1]], - west: [_from[2], 16 - _to[1], _to[2], 16 - _from[1]], - up: [_from[0], _from[2], _to[0], _to[2]], - down: [_to[0], _from[2], _from[0], _to[2]] - }[sideName]! - - const su = (uv[2] - uv[0]) / 16 * finalTexture.su - const sv = (uv[3] - uv[1]) / 16 * finalTexture.sv - finalTexture.u += uv[0] / 16 * finalTexture.su - finalTexture.v += uv[1] / 16 * finalTexture.sv - finalTexture.su = su - finalTexture.sv = sv - face.texture = finalTexture - } - } - return model -} - -function resolveModel (name, blocksModels, texturesJson) { - const model = getFinalModel(name, blocksModels) - return prepareModel(model, texturesJson.textures) -} - -export function prepareBlocksStates (mcAssets: McAssets, atlas: { json: any }) { - addBlockAllModel(mcAssets, 'missing_texture') - - const blocksStates = mcAssets.blocksStates - for (const block of Object.values(blocksStates)) { - if (!block) continue - if (block.variants) { - for (const variant of Object.values(block.variants)) { - if (variant instanceof Array) { - for (const v of variant) { - v.model = resolveModel(v.model, mcAssets.blocksModels, atlas.json) as any - } - } else { - variant.model = resolveModel(variant.model, mcAssets.blocksModels, atlas.json) as any - } - } - } - if (block.multipart) { - for (const variant of block.multipart) { - if (variant.apply instanceof Array) { - for (const v of variant.apply) { - v.model = resolveModel(v.model, mcAssets.blocksModels, atlas.json) as any - } - } else { - variant.apply.model = resolveModel(variant.apply.model, mcAssets.blocksModels, atlas.json) as any - } - } - } - } - return blocksStates -} diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts deleted file mode 100644 index e64b7cffb..000000000 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ /dev/null @@ -1,421 +0,0 @@ -import Jimp from 'jimp' -import minecraftData from 'minecraft-data' -import { McAssets } from './modelsBuilder' -import path from 'path' -import fs from 'fs' -import { fileURLToPath } from 'url' -import { versionToNumber } from './utils' - -// todo refactor -const handledBlocks = ['water', 'lava', 'barrier'] -const origSizeTextures: string[] = [] -let currentImage: Jimp -let currentBlockName: string -let currentMcAssets: McAssets -const __dirname = path.dirname(fileURLToPath(new URL(import.meta.url))) - -type SidesType = { - "up": string - "north": string - "east": string - "south": string - "west": string - "down": string -} - -const getBlockStates = (name: string) => { - const mcData = minecraftData(currentMcAssets.version) - return mcData.blocksByName[name]?.states -} - -export const addBlockCustomSidesModel = (name: string, sides: SidesType) => { - currentMcAssets.blocksStates[name] = { - "variants": { - "": { - "model": name - } - } - } - currentMcAssets.blocksModels[name] = { - "parent": "block/cube", - "textures": sides - } -} - -type TextureMap = [ - x: number, - y: number, - width?: number, - height?: number, -] - -const justCropUV = (x: number, y: number, x1, y1) => { - // input: 0-16, output: 0-currentImage.getWidth() - const width = Math.abs(x1 - x) - const height = Math.abs(y1 - y) - return currentImage.clone().crop( - x / 16 * currentImage.getWidth(), - y / 16 * currentImage.getHeight(), - width / 16 * currentImage.getWidth(), - height / 16 * currentImage.getHeight(), - ) -} -const justCrop = (x: number, y: number, width = 16, height = 16) => { - return currentImage.clone().crop(x, y, width, height) -} - -const combineTextures = (locations: TextureMap[]) => { - const resized: Jimp[] = [] - for (const [x, y, height = 16, width = 16] of locations) { - resized.push(justCrop(x, y, width, height)) - } - - const combinedImage = new Jimp(locations[0]![2] ?? 16, locations[0]![3] ?? 16) - for (const image of resized) { - combinedImage.blit(image, 0, 0) - } - return combinedImage -} - -const generatedImageTextures: { [blockName: string]: /* base64 */string } = {} - -const getBlockTexturesFromJimp = async > (sides: T, withUv = false, textureNameBase = currentBlockName): Promise> => { - const sidesTextures = {} as any - for (const [side, jimp] of Object.entries(sides)) { - const textureName = `${textureNameBase}_${side}` - const sideTexture = withUv ? { uv: [0, 0, jimp.getWidth(), jimp.getHeight()], texture: textureName } : textureName - const base64Url = await jimp.getBase64Async(jimp.getMIME()) - if (side === 'side') { - sidesTextures['north'] = sideTexture - sidesTextures['east'] = sideTexture - sidesTextures['south'] = sideTexture - sidesTextures['west'] = sideTexture - } else { - sidesTextures[side] = sideTexture - } - generatedImageTextures[textureName] = base64Url - } - - return sidesTextures -} - -const addSimpleCubeWithSides = async (sides: Record) => { - const sidesTextures = await getBlockTexturesFromJimp(sides) - - addBlockCustomSidesModel(currentBlockName, sidesTextures as any) -} - -const handleShulkerBox = async (dataBase: string, match: RegExpExecArray) => { - const [, shulkerColor = ''] = match - currentImage = await Jimp.read(dataBase + `entity/shulker/shulker${shulkerColor && `_${shulkerColor}`}.png`) - - const shulkerBoxTextures = { - // todo do all sides - side: combineTextures([ - [0, 16], // top - [0, 36], // bottom - ]), - up: justCrop(16, 0), - down: justCrop(32, 28) - } - - await addSimpleCubeWithSides(shulkerBoxTextures) -} - -// TODO! should not be there! move to data with signs! -const chestModels = { - chest: { - "parent": "block/block", - "textures": { - "particle": "#particles" - }, - "elements": [ - { - "from": [1, 0, 1], - "to": [15, 10, 15], - "faces": { - "down": { "texture": "#chest", "uv": [3.5, 4.75, 7, 8.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [10.5, 8.25, 14, 10.75], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0, 8.25, 3.5, 10.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 8.25, 7, 10.75], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [7, 8.25, 10.5, 10.75], "rotation": 180 } - }, - }, - { - "from": [1, 10, 1], - "to": [15, 14, 15], - "faces": { - "up": { "texture": "#chest", "uv": [3.5, 4.75, 7, 8.25] }, - "north": { "texture": "#chest", "uv": [10.5, 3.75, 14, 4.75], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0, 3.75, 3.5, 4.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 3.75, 7, 4.75], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [7, 3.75, 10.5, 4.75], "rotation": 180 } - } - }, - { - "from": [7, 7, 0], - "to": [9, 11, 1], - "faces": { - "down": { "texture": "#chest", "uv": [0.25, 0, 0.75, 0.25], "rotation": 180 }, - "up": { "texture": "#chest", "uv": [0.75, 0, 1.25, 0.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [1, 0.25, 1.5, 1.25], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [0.75, 0.25, 1, 1.25], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0, 0.25, 0.25, 1.25], "rotation": 180 } - } - } - ] - }, - chest_left: { - "parent": "block/block", - "textures": { - "particle": "#particles" - }, - "elements": [ - { - "from": [1, 0, 1], - "to": [16, 10, 15], - "faces": { - "down": { "texture": "#chest", "uv": [3.5, 4.75, 7.25, 8.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [10.75, 8.25, 14.5, 10.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 8.25, 7.25, 10.75], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [7.25, 8.25, 10.75, 10.75], "rotation": 180 } - } - }, - { - "from": [1, 10, 1], - "to": [16, 14, 15], - "faces": { - "up": { "texture": "#chest", "uv": [3.5, 4.75, 7.25, 8.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [10.75, 3.75, 14.5, 4.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 3.75, 7.25, 4.75], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [7.25, 3.75, 10.75, 4.75], "rotation": 180 } - } - }, - { - "from": [15, 7, 0], - "to": [16, 11, 1], - "faces": { - "down": { "texture": "#chest", "uv": [0.25, 0, 0.5, 0.25], "rotation": 180 }, - "up": { "texture": "#chest", "uv": [0.5, 0, 0.75, 0.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [0.75, 0.25, 1, 1.25], "rotation": 180 }, - "west": { "texture": "#chest", "uv": [0.5, 0.25, 0.75, 1.25], "rotation": 180 } - } - } - ] - }, - chest_right: { - "parent": "block/block", - "textures": { - "particle": "#particles" - }, - "elements": [ - { - "from": [0, 0, 1], - "to": [15, 10, 15], - "faces": { - "down": { "texture": "#chest", "uv": [3.5, 4.75, 7.25, 8.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [10.75, 8.25, 14.5, 10.75], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0, 8.25, 3.5, 10.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 8.25, 7.25, 10.75], "rotation": 180 } - } - }, - { - "from": [0, 10, 1], - "to": [15, 14, 15], - "faces": { - "up": { "texture": "#chest", "uv": [3.5, 4.75, 7.25, 8.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [10.75, 3.75, 14.5, 4.75], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0, 3.75, 3.5, 4.75], "rotation": 180 }, - "south": { "texture": "#chest", "uv": [3.5, 3.75, 7.25, 4.75], "rotation": 180 } - } - }, - { - "from": [0, 7, 0], - "to": [1, 11, 1], - "faces": { - "down": { "texture": "#chest", "uv": [0.25, 0, 0.5, 0.25], "rotation": 180 }, - "up": { "texture": "#chest", "uv": [0.5, 0, 0.75, 0.25], "rotation": 180 }, - "north": { "texture": "#chest", "uv": [0.75, 0.25, 1, 1.25], "rotation": 180 }, - "east": { "texture": "#chest", "uv": [0.0, 0.25, 0.25, 1.25], "rotation": 180 } - } - } - ] - } -} - -// these blockStates / models copied from https://github.com/FakeDomi/FastChest/blob/master/src/main/resources/assets/minecraft/blockstates/ -const chestBlockStatesMap = { - chest: JSON.parse(fs.readFileSync(path.join(__dirname, 'blockStates/chest.json'), 'utf-8')), - trapped_chest: JSON.parse(fs.readFileSync(path.join(__dirname, 'blockStates/trapped_chest.json'), 'utf-8')), - ender_chest: JSON.parse(fs.readFileSync(path.join(__dirname, 'blockStates/ender_chest.json'), 'utf-8')), -} -const handleChest = async (dataBase: string, match: RegExpExecArray) => { - const blockStates = structuredClone(chestBlockStatesMap[currentBlockName]) - - const particle = match[1] === 'ender' ? 'obsidian' : 'oak_planks' - - const blockStatesVariants = Object.values(blockStates.variants) as { model }[] - const neededModels = [...new Set(blockStatesVariants.map((x) => x.model))] - - for (const modelName of neededModels) { - let chestTextureName = { - chest: 'normal', - trapped_chest: 'trapped', - ender_chest: 'ender', - }[currentBlockName] - if (modelName.endsWith('_left')) chestTextureName = `${chestTextureName}_left` - if (modelName.endsWith('_right')) chestTextureName = `${chestTextureName}_right` - - const texture = path.join(currentMcAssets.directory, `../1.19.1/entity/chest/${chestTextureName}.png`) - - currentImage = await Jimp.read(texture) - - const model = structuredClone(chestModels[modelName]) - model.textures.particle = particle - const newModelName = `${currentBlockName}_${modelName}` - for (const variant of blockStatesVariants) { - if (variant.model !== modelName) continue - variant.model = newModelName - } - for (const [i, { faces }] of model.elements.entries()) { - for (const [faceName, face] of Object.entries(faces) as any) { - const { uv } = face - //@ts-ignore - const jimp = justCropUV(...uv) - const key = `${chestTextureName}_${modelName}_${i}_${faceName}` - const texture = await getBlockTexturesFromJimp({ - [key]: jimp - }, true, key).then(a => a[key]) - face.texture = texture.texture - face.uv = texture.uv - } - } - currentMcAssets.blocksModels[newModelName] = model - } - currentMcAssets.blocksStates[currentBlockName] = blockStates -} - -async function loadBlockModelTextures (dataBase: string, blockModel: any) { - for (const key in blockModel.textures) { - let texture: string = blockModel.textures[key] - const useAssetsPath = !!texture.match(/^[0-9.]+\//) - blockModel.textures.particle = texture - generatedImageTextures[texture] = `data:image/png;base64,${fs.readFileSync(path.join(dataBase, useAssetsPath ? '..' : '', texture + '.png'), 'base64')}` - origSizeTextures[texture] = true - } -} - -const handlers = [ - [/(.+)_shulker_box$/, handleShulkerBox], - [/^shulker_box$/, handleShulkerBox], - [/^(?:(ender|trapped)_)?chest$/, handleChest], - // [/(^|(.+)_)bed$/, handleBed], - // no-op just suppress warning - [/(^light|^moving_piston$)/, true], -] as const - -export const tryHandleBlockEntity = async (dataBase, blockName) => { - currentBlockName = blockName - for (const [regex, handler] of handlers) { - const match = regex.exec(blockName) - if (!match) continue - if (handler !== true) { - await handler(dataBase, match) - } - return true - } -} - -async function readAllBlockStates (blockStatesDir: string) { - const files = fs.readdirSync(blockStatesDir) - for (const file of files) { - if (file.endsWith('.json')) { - const state = JSON.parse(fs.readFileSync(path.join(blockStatesDir, file), 'utf-8')) - const name = file.replace('.json', '') - currentMcAssets.blocksStates[name] = state - handledBlocks.push(name) - } else { - await readAllBlockStates(path.join(blockStatesDir, file)) - } - } -} - -async function readAllBlockModels (dataBase: string, blockModelsDir: string, completePath: string) { - const actualPath = completePath.length ? completePath + "/" : "" - const files = fs.readdirSync(blockModelsDir) - for (const file of files) { - if (file.endsWith('.json')) { - const model = JSON.parse(fs.readFileSync(path.join(blockModelsDir, file), 'utf-8')) - const name = actualPath + file.replace('.json', '') - currentMcAssets.blocksModels[name] = model - await loadBlockModelTextures(dataBase, model) - } else { - await readAllBlockModels(dataBase, path.join(blockModelsDir, file), actualPath + file) - } - } -} - -const handleExternalData = async (assetsPathRoot: string, version: string) => { - const currentVersionNumber = versionToNumber(version) - const versions = fs.readdirSync(path.join(__dirname, 'data'), { withFileTypes: true }) - .filter(x => x.isDirectory()) - .map(x => x.name) - .sort((a, b) => versionToNumber(b) - versionToNumber(a)) - - const allAssetsVersions = fs.readdirSync(assetsPathRoot, { withFileTypes: true }) - .filter(x => x.isDirectory()) - .map(x => x.name) - .sort((a, b) => versionToNumber(b) - versionToNumber(a)) - - const getAssetsVersion = (version: string) => { - return allAssetsVersions[version] ?? allAssetsVersions.find(x => x.startsWith(version)) - } - - for (const curVer of versions) { - const baseDir = path.join(__dirname, 'data', curVer) - if (versionToNumber(curVer) > currentVersionNumber) continue - - const assetsVersion = getAssetsVersion(curVer) - await readAllBlockStates(path.join(baseDir, 'blockStates')) - await readAllBlockModels(path.join(assetsPathRoot, assetsVersion), path.join(baseDir, 'blockModels'), "") - } -} - -export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { - const mcData = minecraftData(mcAssets.version) - const allTheBlocks = mcData.blocksArray.map(x => x.name) - - currentMcAssets = mcAssets - // todo - const ignoredBlocks = ['skull', 'structure_void', 'banner', 'bed', 'end_portal'] - - for (const theBlock of allTheBlocks) { - try { - if (await tryHandleBlockEntity(mcAssets.directory, theBlock)) { - handledBlocks.push(theBlock) - } - } catch (err) { - // todo remove when all warnings are resolved - console.warn(`[${mcAssets.version}] failed to generate block ${theBlock}`) - } - } - - await handleExternalData(path.join(mcAssets.directory, '..'), mcAssets.version) - - const warnings: string[] = [] - for (const [name, model] of Object.entries(mcAssets.blocksModels)) { - if (Object.keys(model).length === 1 && model.textures) { - const keys = Object.keys(model.textures) - if (keys.length === 1 && keys[0] === 'particle') { - if (handledBlocks.includes(name) || ignoredBlocks.includes(name)) continue - warnings.push(`unhandled block ${name}`) - } - } - } - - return { warnings } -} - -export const getAdditionalTextures = () => { - return { generated: generatedImageTextures, origSizeTextures } -} diff --git a/prismarine-viewer/viewer/prepare/postinstall.ts b/prismarine-viewer/viewer/prepare/postinstall.ts deleted file mode 100644 index bf70d26c0..000000000 --- a/prismarine-viewer/viewer/prepare/postinstall.ts +++ /dev/null @@ -1,12 +0,0 @@ -import path from 'path' -import fs from 'fs' - -const publicPath = path.resolve(__dirname, '../../public') -const texturesPath = path.join(publicPath, 'textures') - -if (fs.existsSync(texturesPath) && !process.argv.includes('-f')) { - console.log('textures folder already exists, skipping...') - process.exit(0) -} else { - import('./generateTextures') -} diff --git a/prismarine-viewer/viewer/supportedVersions.json b/prismarine-viewer/viewer/supportedVersions.json deleted file mode 100644 index d4fcd3d8e..000000000 --- a/prismarine-viewer/viewer/supportedVersions.json +++ /dev/null @@ -1 +0,0 @@ -["1.8.8", "1.9.4", "1.10.2", "1.11.2", "1.12.2", "1.13.2", "1.14.4", "1.15.2", "1.16.1", "1.16.4", "1.17.1", "1.18.1", "1.18.2"] \ No newline at end of file diff --git a/prismarine-viewer/webpack.config.js b/prismarine-viewer/webpack.config.js deleted file mode 100644 index d1577c9df..000000000 --- a/prismarine-viewer/webpack.config.js +++ /dev/null @@ -1,88 +0,0 @@ -// eslint-disable-next-line no-unused-vars -const webpack = require('webpack') -const path = require('path') -// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin - -// Minify the index.js by removing unused minecraft data. Since the worker only needs to do meshing, -// we can remove all the other data unrelated to meshing. -const blockedIndexFiles = ['blocksB2J', 'blocksJ2B', 'blockMappings', 'steve', 'recipes'] -const allowedWorkerFiles = ['blocks', 'blockCollisionShapes', 'tints', 'blockStates', - 'biomes', 'features', 'version', 'legacy', 'versions', 'version', 'protocolVersions'] - -const indexConfig = { - entry: './lib/index.js', - mode: 'production', - output: { - path: path.resolve(__dirname, './public'), - filename: './index.js' - }, - resolve: { - fallback: { - zlib: false - } - }, - plugins: [ - // fix "process is not defined" error: - new webpack.ProvidePlugin({ - process: 'process/browser' - }), - new webpack.ProvidePlugin({ - Buffer: ['buffer', 'Buffer'] - }), - new webpack.NormalModuleReplacementPlugin( - // eslint-disable-next-line - /viewer[\/|\\]lib[\/|\\]utils/, - './utils.web.js' - ) - // new BundleAnalyzerPlugin() - ], - externals: [ - function (req, cb) { - if (req.context.includes('minecraft-data') && req.request.endsWith('.json')) { - const fileName = req.request.split('/').pop().replace('.json', '') - if (blockedIndexFiles.includes(fileName)) { - cb(null, []) - return - } - } - cb() - } - ] -} - -const workerConfig = { - entry: './viewer/lib/worker.js', - mode: 'production', - output: { - path: path.join(__dirname, '/public'), - filename: './worker.js' - }, - resolve: { - fallback: { - zlib: false - } - }, - plugins: [ - // fix "process is not defined" error: - new webpack.ProvidePlugin({ - process: 'process/browser' - }), - new webpack.ProvidePlugin({ - Buffer: ['buffer', 'Buffer'] - }) - ], - externals: [ - function (req, cb) { - if (req.context.includes('minecraft-data') && req.request.endsWith('.json')) { - const fileName = req.request.split('/').pop().replace('.json', '') - if (!allowedWorkerFiles.includes(fileName)) { - cb(null, []) - return - } - } - cb() - } - ] -} - -module.exports = [indexConfig, workerConfig] diff --git a/rsbuild.config.ts b/rsbuild.config.ts new file mode 100644 index 000000000..28a16ec38 --- /dev/null +++ b/rsbuild.config.ts @@ -0,0 +1,185 @@ +import { defineConfig, RsbuildPluginAPI } from '@rsbuild/core' +import { pluginReact } from '@rsbuild/plugin-react' +import { pluginTypedCSSModules } from '@rsbuild/plugin-typed-css-modules' +import { pluginNodePolyfill } from '@rsbuild/plugin-node-polyfill' +import { pluginTypeCheck } from '@rsbuild/plugin-type-check' +import path from 'path' +import childProcess from 'child_process' +import fs from 'fs' +import fsExtra from 'fs-extra' +import { promisify } from 'util' +import { generateSW } from 'workbox-build' +import { getSwAdditionalEntries } from './scripts/build' + +//@ts-ignore +try { require('./localSettings.js') } catch { } + +const execAsync = promisify(childProcess.exec) + +const buildingVersion = new Date().toISOString().split(':')[0] + +const dev = process.env.NODE_ENV === 'development' + +export default defineConfig({ + dev: { + progressBar: true, + writeToDisk: true + }, + html: { + template: './index.html', + }, + output: { + polyfill: 'usage', + externals: [ + 'sharp' + ], + sourceMap: { + js: 'source-map', + css: true, + }, + // 50kb limit for data uri + dataUriLimit: 50 * 1024 + }, + source: { + alias: { + fs: './src/shims/fs.js', + http: 'http-browserify', + stream: 'stream-browserify', + net: 'net-browserify', + 'minecraft-protocol$': 'minecraft-protocol/src/index.js', + 'buffer$': 'buffer', + // avoid bundling, not used on client side + 'prismarine-auth': './src/shims/empty.ts', + perf_hooks: './src/shims/perf_hooks_replacement.js', + crypto: './src/shims/crypto.js', + dns: './src/shims/dns.js', + yggdrasil: './src/shims/yggdrasilReplacement.ts', + }, + entry: { + index: './src/index.ts', + }, + // exclude: [ + // /.woff$/ + // ], + define: { + 'process.env.BUILD_VERSION': JSON.stringify(!dev ? buildingVersion : 'undefined'), + 'process.platform': '"browser"', + 'process.env.GITHUB_URL': + JSON.stringify(`https://github.com/${process.env.GITHUB_REPOSITORY || `${process.env.VERCEL_GIT_REPO_OWNER}/${process.env.VERCEL_GIT_REPO_SLUG}`}`), + 'process.env.DEPS_VERSIONS': JSON.stringify({}) + }, + decorators: { + version: 'legacy', // default is a lie + }, + }, + server: { + // strictPort: true, + htmlFallback: false, + publicDir: false, + // publicDir: { + // name: 'assets', + // }, + headers: { + // enable shared array buffer + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp', + }, + open: process.env.OPEN_BROWSER === 'true', + proxy: { + '/api': 'http://localhost:8080', + }, + }, + plugins: [ + pluginReact(), + pluginTypedCSSModules(), + pluginNodePolyfill(), + { + name: 'test', + setup (build: RsbuildPluginAPI) { + const prep = async () => { + console.time('total-prep') + if (!fs.existsSync('./generated/minecraft-data-data.js')) { + childProcess.execSync('tsx ./scripts/genShims.ts', { stdio: 'inherit' }) + } + fsExtra.copySync('./node_modules/mc-assets/dist/other-textures/latest/entity', './dist/textures/entity') + fsExtra.copySync('./assets/background', './dist/background') + fs.copyFileSync('./assets/favicon.png', './dist/favicon.png') + fs.copyFileSync('./assets/manifest.json', './dist/manifest.json') + fs.copyFileSync('./assets/loading-bg.jpg', './dist/loading-bg.jpg') + const configJson = JSON.parse(fs.readFileSync('./config.json', 'utf8')) + if (dev) { + configJson.defaultProxy = ':8080' + } + fs.writeFileSync('./dist/config.json', JSON.stringify(configJson), 'utf8') + childProcess.execSync('node ./scripts/prepareData.mjs', { stdio: 'inherit' }) + // childProcess.execSync('./scripts/prepareSounds.mjs', { stdio: 'inherit' }) + // childProcess.execSync('tsx ./scripts/genMcDataTypes.ts', { stdio: 'inherit' }) + // childProcess.execSync('tsx ./scripts/genPixelartTypes.ts', { stdio: 'inherit' }) + if (fs.existsSync('./prismarine-viewer/public/mesher.js')) { + // copy mesher + fs.copyFileSync('./prismarine-viewer/public/mesher.js', './dist/mesher.js') + } else { + await execAsync('pnpm run build-mesher') + } + fs.writeFileSync('./dist/version.txt', buildingVersion, 'utf-8') + console.timeEnd('total-prep') + } + if (!dev) { + build.onBeforeBuild(async () => { + await prep() + }) + build.onAfterBuild(async () => { + const { count, size, warnings } = await generateSW({ + // dontCacheBustURLsMatching: [new RegExp('...')], + globDirectory: 'dist', + skipWaiting: true, + clientsClaim: true, + additionalManifestEntries: getSwAdditionalEntries(), + globPatterns: [], + swDest: './dist/service-worker.js', + }) + }) + } + build.onBeforeStartDevServer(prep) + }, + }, + ], + tools: { + bundlerChain (chain, { CHAIN_ID }) { + }, + rspack (config, { addRules, appendPlugins, rspack }) { + appendPlugins(new rspack.NormalModuleReplacementPlugin(/data/, (resource) => { + let absolute: string + const request = resource.request.replaceAll('\\', '/') + absolute = path.join(resource.context, request).replaceAll('\\', '/') + if (request.includes('minecraft-data/data/pc/1.')) { + console.log('Error: incompatible resource', request, resource.contextInfo.issuer) + process.exit(1) + // throw new Error(`${resource.request} was requested by ${resource.contextInfo.issuer}`) + } + if (absolute.endsWith('/minecraft-data/data.js')) { + resource.request = path.join(__dirname, './generated/minecraft-data-data.js') + } + })) + addRules([ + { + test: /\.obj$/, + type: 'asset/source', + }, + { + test: /\.mp3$/, + type: 'asset/source', + } + ]) + config.ignoreWarnings = [ + /the request of a dependency is an expression/, + /Unsupported pseudo class or element: xr-overlay/ + ] + } + }, + performance: { + // bundleAnalyze: { + // analyzerMode: 'json', + // }, + }, +}) diff --git a/scripts/build.js b/scripts/build.js index 9fcc6d2cc..7d3dc3fc6 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -5,18 +5,15 @@ const glob = require('glob') const fs = require('fs') const crypto = require('crypto') const path = require('path') -const McAssets = require('minecraft-assets') const prismarineViewerBase = "./node_modules/prismarine-viewer" -const entityMcAssets = McAssets('1.16.4') // these files could be copied at build time eg with copy plugin, but copy plugin slows down the config so we copy them there, alternative we could inline it in esbuild config const filesToCopy = [ - { from: `${prismarineViewerBase}/public/blocksStates/`, to: 'dist/blocksStates/' }, { from: `${prismarineViewerBase}/public/mesher.js`, to: 'dist/mesher.js' }, { from: './assets/', to: './dist/' }, { from: './config.json', to: 'dist/config.json' }, - { from: path.join(entityMcAssets.directory, 'entity'), to: 'dist/textures/1.16.4/entity' }, + // { from: path.join(entityMcAssets.directory, 'entity'), to: 'dist/textures/1.16.4/entity' }, ] exports.filesToCopy = filesToCopy exports.copyFiles = (dev = false) => { @@ -46,15 +43,10 @@ exports.copyFilesDev = () => { exports.getSwAdditionalEntries = () => { // need to be careful with this - const singlePlayerVersion = defaultLocalServerOptions.version const filesToCachePatterns = [ 'index.html', - 'index.js', - 'index.css', - 'favicon.ico', `mc-data/${defaultLocalServerOptions.versionMajor}.js`, - `blocksStates/${singlePlayerVersion}.json`, - 'extra-textures/**', + 'background/**', // todo-low copy from assets '*.mp3', '*.ttf', @@ -62,13 +54,12 @@ exports.getSwAdditionalEntries = () => { '*.woff', 'mesher.js', 'worldSaveWorker.js', - // todo-low preload entity atlas? - `textures/${singlePlayerVersion}.png`, - `textures/1.16.4/entity/squid.png`, + `textures/entity/squid/squid.png`, + // everything but not .map + 'static/**/!(*.map)', ] const filesNeedsCacheKey = [ - 'index.js', - 'index.css', + 'index.html', 'mesher.js', 'worldSaveWorker.js', ] @@ -89,6 +80,9 @@ exports.getSwAdditionalEntries = () => { output.push({ url, revision }) } } + if (output.length > 40) { + throw new Error(`SW: Ios has a limit of 40 urls to cache (now ${output.length})`) + } console.log(`Got ${output.length} additional sw entries to cache`) return output } @@ -98,6 +92,16 @@ exports.moveStorybookFiles = () => { fsExtra.copySync('dist/storybook', '.vercel/output/static/storybook') } +exports.getSwFilesSize = () => { + const files = exports.getSwAdditionalEntries() + let size = 0 + for (const { url } of files) { + const file = path.join(__dirname, '../dist', url) + size += fs.statSync(file).size + } + console.log('mb', size / 1024 / 1024) +} + const fn = require.main === module && exports[process.argv[2]] if (fn) { diff --git a/scripts/buildNpmReact.ts b/scripts/buildNpmReact.ts index bc0fc192b..f23a37cc2 100644 --- a/scripts/buildNpmReact.ts +++ b/scripts/buildNpmReact.ts @@ -11,7 +11,7 @@ fs.promises.readdir(path.resolve(__dirname, '../src/react')).then(async (files) const components = files .filter((file) => { if (file.startsWith('Concept')) return false - return file.endsWith('.stories.tsx'); + return file.endsWith('.stories.tsx') }) .map((file) => { return file.replace('.stories.tsx', '') @@ -39,7 +39,7 @@ fs.promises.readdir(path.resolve(__dirname, '../src/react')).then(async (files) version = version.replace(/^v/, '') packageJson.version = version - const externalize = ['minecraft-assets', 'prismarine-viewer'] + const externalize = ['prismarine-viewer', 'mc-assets'] const { metafile } = await build({ entryPoints: [path.resolve(__dirname, '../src/react/npmReactComponents.ts')], bundle: true, diff --git a/scripts/dockerPrepare.mjs b/scripts/dockerPrepare.mjs new file mode 100644 index 000000000..fd3680b4d --- /dev/null +++ b/scripts/dockerPrepare.mjs @@ -0,0 +1,12 @@ +//@ts-check +import fs from 'fs' +import path from 'path' +import { fileURLToPath } from 'url' + +const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8')) +delete packageJson.optionalDependencies +fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, 2), 'utf8') + +const packageJsonViewer = JSON.parse(fs.readFileSync('./prismarine-viewer/package.json', 'utf8')) +delete packageJsonViewer.optionalDependencies +fs.writeFileSync('./prismarine-viewer/package.json', JSON.stringify(packageJsonViewer, null, 2), 'utf8') diff --git a/scripts/esbuildPlugins.mjs b/scripts/esbuildPlugins.mjs index 60ac7a942..431c16a4b 100644 --- a/scripts/esbuildPlugins.mjs +++ b/scripts/esbuildPlugins.mjs @@ -1,47 +1,16 @@ //@ts-check -import { polyfillNode } from 'esbuild-plugin-polyfill-node' -import { join, dirname, basename } from 'path' +import { join, dirname } from 'path' import * as fs from 'fs' -import { filesize } from 'filesize' -import MCProtocol from 'minecraft-protocol' -import MCData from 'minecraft-data' -import { throttle } from 'lodash-es' import { fileURLToPath } from 'url' -import { gzipSizeFromFileSync } from 'gzip-size' const __dirname = dirname(fileURLToPath(new URL(import.meta.url))) -const { supportedVersions } = MCProtocol - -const prod = process.argv.includes('--prod') -let connectedClients = [] - -const writeToClients = (data) => { - connectedClients.forEach((res) => { - res.write(`data: ${JSON.stringify(data)}\n\n`) - res.flush() - }) -} - -export const startWatchingHmr = () => { - const eventsPerFile = { - 'mesher.js': 'mesher', - // 'dist/webglRendererWorker.js': 'webglRendererWorker', - } - for (const name of Object.keys(eventsPerFile)) { - const file = join('dist', name) - if (!fs.existsSync(file)) console.warn(`[missing worker] File ${name} does not exist`) - fs.watchFile(file, () => { - writeToClients({ replace: { type: eventsPerFile[name] } }) - }) - } -} /** @type {import('esbuild').Plugin[]} */ const mesherSharedPlugins = [ { name: 'minecraft-data', - setup(build) { + setup (build) { build.onLoad({ filter: /data[\/\\]pc[\/\\]common[\/\\]legacy.json$/, }, async (args) => { @@ -55,311 +24,4 @@ const mesherSharedPlugins = [ } ] -/** @type {import('esbuild').Plugin[]} */ -const plugins = [ - ...mesherSharedPlugins, - { - name: 'strict-aliases', - setup(build) { - build.onResolve({ - filter: /^minecraft-protocol$/, - }, async ({ kind, resolveDir }) => { - return { - path: (await build.resolve('minecraft-protocol/src/index.js', { kind, resolveDir })).path, - } - }) - build.onLoad({ - filter: /minecraft-data[\/\\]data.js$/, - }, (args) => { - const version = supportedVersions.at(-1) - if (!version) throw new Error('unreachable') - const data = MCData(version) - const defaultVersionsObj = { - // default protocol data, needed for auto-version - [version]: { - version: data.version, - // protocol: JSON.parse(fs.readFileSync(join(args.path, '..', 'minecraft-data/data/pc/1.20/protocol.json'), 'utf8')), - protocol: data.protocol, - } - } - return { - contents: `window.mcData ??= ${JSON.stringify(defaultVersionsObj)};module.exports = { pc: window.mcData }`, - loader: 'js', - } - }) - build.onResolve({ - filter: /^minecraft-assets$/, - }, () => { - throw new Error('hit banned package') - }) - build.onLoad({ - filter: /^prismarine-auth/, - }, () => { - return { - contents: 'module.exports = {}', - } - }) - - build.onResolve({ - filter: /^three$/, - }, async ({ kind, resolveDir }) => { - return { - path: (await build.resolve('three/src/Three.js', { kind, resolveDir })).path, - } - }) - } - }, - { - name: 'data-assets', - setup(build) { - build.onResolve({ - filter: /.*/, - }, async ({ path, ...rest }) => { - if (['.woff', '.woff2', '.ttf'].some(ext => path.endsWith(ext)) || path.startsWith('extra-textures/')) { - return { - path, - namespace: 'assets', - external: true, - } - } - }) - - const removeNodeModulesSourcemaps = (map) => { - const doNotRemove = ['prismarine', 'mineflayer', 'flying-squid', '@jspm/core', 'minecraft', 'three'] - map.sourcesContent.forEach((_, i) => { - if (map.sources[i].includes('node_modules') && !doNotRemove.some(x => map.sources[i].includes(x))) { - map.sourcesContent[i] = null - } - }) - } - - build.onEnd(async ({ metafile, outputFiles }) => { - // write outputFiles - //@ts-ignore - for (const file of outputFiles) { - let contents = file.text - if (file.path.endsWith('.map') && file.text && !process.env.PROD) { - const map = JSON.parse(file.text) - removeNodeModulesSourcemaps(map) - contents = JSON.stringify(map) - } - await fs.promises.writeFile(file.path, contents) - } - if (!prod) return - // const deps = Object.entries(metafile.inputs).sort(([, a], [, b]) => b.bytes - a.bytes).map(([x, { bytes }]) => [x, filesize(bytes)]).slice(0, 5) - //@ts-ignore - const sizeByExt = {} - //@ts-ignore - Object.entries(metafile.inputs).sort(([, a], [, b]) => b.bytes - a.bytes).forEach(([x, { bytes }]) => { - const ext = x.slice(x.lastIndexOf('.')) - sizeByExt[ext] ??= 0 - sizeByExt[ext] += bytes - }) - console.log('Input size by ext for dist/index.js:') - console.log(Object.fromEntries(Object.entries(sizeByExt).map(x => [x[0], filesize(x[1])]))) - console.log('Gzip size for dist/index.js:', filesize(gzipSizeFromFileSync('dist/index.js'))) - }) - }, - }, - { - name: 'prevent-incorrect-linking', - setup(build) { - build.onResolve({ - filter: /.+/, - }, async ({ resolveDir, path, importer, kind, pluginData }) => { - if (pluginData?.__internal) return - // not ideal as packages can have different version, on the other hand we should not have multiple versions of the same package of developing deps - const packageName = path.startsWith('@') ? path.split('/', 2).join('/') : path.split('/', 1)[0] - const localPackageToReuse = join('node_modules', packageName) - if (!resolveDir.startsWith(process.cwd()) && ['./', '../'].every(x => !path.startsWith(x)) && fs.existsSync(localPackageToReuse)) { - const redirected = await build.resolve(path, { kind: 'import-statement', resolveDir: process.cwd(), pluginData: { __internal: true }, }) - return redirected - } - // disallow imports from outside the root directory to ensure modules are resolved from node_modules of this workspace - // if ([resolveDir, path].some(x => x.includes('node_modules')) && !resolveDir.startsWith(process.cwd())) { - // // why? ensure workspace dependency versions are used (we have overrides and need to dedupe so it doesn't grow in size) - // throw new Error(`Restricted package import from outside the root directory: ${resolveDir}`) - // } - return undefined - }) - } - }, - { - name: 'watch-notify', - setup(build) { - let count = 0 - let time - let prevHash - - build.onStart(() => { - time = Date.now() - }) - build.onEnd(({ errors, outputFiles: _outputFiles, metafile, warnings }) => { - /** @type {import('esbuild').OutputFile[]} */ - // @ts-ignore - const outputFiles = _outputFiles - const elapsed = Date.now() - time - outputFiles.find(outputFile => outputFile.path) - - if (errors.length) { - writeToClients({ errors: errors.map(error => error.text) }) - return - } - - // write metafile to disk if needed to analyze - fs.writeFileSync('dist/meta.json', JSON.stringify(metafile, null, 2)) - - /** @type {import('esbuild').OutputFile} */ - //@ts-ignore - const outputFile = outputFiles.find(x => x.path.endsWith('.js')) - if (outputFile.hash === prevHash) { - // todo also check workers and css - console.log('Ignoring reload as contents the same') - return - } - prevHash = outputFile.hash - let outputText = outputFile.text - //@ts-ignore - if (['inline', 'both'].includes(build.initialOptions.sourcemap)) { - outputText = outputText.slice(0, outputText.indexOf('//# sourceMappingURL=data:application/json;base64,')) - } - console.log(`Done in ${elapsed}ms. Size: ${filesize(outputText.length)} (${build.initialOptions.minify ? 'minified' : 'without minify'})`) - - if (count++ === 0) { - return - } - - writeToClients({ update: { time: elapsed } }) - connectedClients.length = 0 - }) - } - }, - { - name: 'esbuild-readdir', - setup(build) { - build.onResolve({ - filter: /^esbuild-readdir:.+$/, - }, ({ resolveDir, path }) => { - return { - namespace: 'esbuild-readdir', - path, - pluginData: { - resolveDir: join(resolveDir, path.replace(/^esbuild-readdir:/, '')) - }, - } - }) - build.onLoad({ - filter: /.+/, - namespace: 'esbuild-readdir', - }, async ({ pluginData }) => { - const { resolveDir } = pluginData - const files = await fs.promises.readdir(resolveDir) - return { - contents: `module.exports = ${JSON.stringify(files)}`, - resolveDir, - loader: 'js', - } - }) - } - }, - { - name: 'esbuild-import-glob', - setup(build) { - build.onResolve({ - filter: /^esbuild-import-glob\(path:(.+),skipFiles:(.+)\)+$/, - }, ({ resolveDir, path }) => { - return { - namespace: 'esbuild-import-glob', - path, - pluginData: { - resolveDir - }, - } - }) - build.onLoad({ - filter: /.+/, - namespace: 'esbuild-import-glob', - }, async ({ pluginData, path }) => { - const { resolveDir } = pluginData - //@ts-ignore - const [, userPath, skipFiles] = /^esbuild-import-glob\(path:(.+),skipFiles:(.+)\)+$/g.exec(path) - const files = (await fs.promises.readdir(join(resolveDir, userPath))).filter(f => !skipFiles.includes(f)) - return { - contents: `module.exports = { ${files.map(f => `'${f}': require('./${join(userPath, f)}')`).join(',')} }`, - resolveDir, - loader: 'js', - } - }) - } - }, - { - 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', - setup(build) { - build.onLoad({ - filter: /.tsx$/, - }, async ({ path }) => { - let file = await fs.promises.readFile(path, 'utf8') - const fileName = basename(path, '.tsx') - let replaced = false - const varName = `__${fileName}_COMPONENT` - file = file.replace(/export default /, () => { - replaced = true - return `const ${varName} = ` - }) - if (replaced) { - file += `;${varName}.displayName = '${fileName}';export default ${varName};` - } - - return { - contents: file, - loader: 'tsx', - } - }) - } - }, - polyfillNode({ - 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, mesherSharedPlugins } +export { mesherSharedPlugins } diff --git a/scripts/gen-texturepack-files.mjs b/scripts/gen-texturepack-files.mjs deleted file mode 100644 index d996236e3..000000000 --- a/scripts/gen-texturepack-files.mjs +++ /dev/null @@ -1,52 +0,0 @@ -//@ts-check -import fs from 'fs' -import minecraftAssets from 'minecraft-assets' - -// why store another data? -// 1. want to make it compatible (at least for now) -// 2. don't want to read generated blockStates as it might change in future, and the current way was faster to implement - -const blockNames = [] -const indexesPerVersion = {} -/** @type {Map} */ -const allBlocksMap = new Map() -const getBlockIndex = (block) => { - if (allBlocksMap.has(block)) { - return allBlocksMap.get(block) - } - - const index = blockNames.length - allBlocksMap.set(block, index) - blockNames.push(block) - return index -} - -// const blocksFull = [] -// const allBlocks = [] -// // we can even optimize it even futher by doing prev-step resolving -// const blocksDiff = {} - -for (const [i, version] of minecraftAssets.versions.reverse().entries()) { - const assets = minecraftAssets(version) - const blocksDir = assets.directory + '/blocks' - const blocks = fs.readdirSync(blocksDir) - indexesPerVersion[version] = blocks.map(block => { - if (!block.endsWith('.png')) return undefined - return getBlockIndex(block) - }).filter(i => i !== undefined) - - // if (!blocksFull.length) { - // // first iter - // blocksFull.push(...blocks) - // } else { - // const missing = blocksFull.map((b, i) => !blocks.includes(b) ? i : -1).filter(i => i !== -1) - // const added = blocks.filter(b => !blocksFull.includes(b)) - // blocksDiff[version] = { - // missing, - // added - // } - // } -} - -fs.mkdirSync('./generated', { recursive: true, }) -fs.writeFileSync('./generated/blocks.json', JSON.stringify({ blockNames: blockNames, indexes: indexesPerVersion })) diff --git a/scripts/genShims.ts b/scripts/genShims.ts new file mode 100644 index 000000000..3fe416b35 --- /dev/null +++ b/scripts/genShims.ts @@ -0,0 +1,43 @@ +import fs from 'fs' +import MinecraftData from 'minecraft-data' +import MCProtocol from 'minecraft-protocol' +import { appReplacableResources } from '../src/resourcesSource' + +const { supportedVersions, defaultVersion } = MCProtocol + +// gen generated/minecraft-data-data.js + +const data = MinecraftData(defaultVersion) +const defaultVersionObj = { + [defaultVersion]: { + version: data.version, + protocol: data.protocol, + } +} + +const mcDataContents = `window.mcData ??= ${JSON.stringify(defaultVersionObj)};module.exports = { pc: window.mcData }` + +fs.writeFileSync('./generated/minecraft-data-data.js', mcDataContents, 'utf8') + +// app resources + +let headerImports = '' +let resourcesContent = 'export const appReplacableResources: { [key: string]: { content: any, resourcePackPath: string, cssVar?: string, cssVarRepeat?: number } } = {\n' + +for (const resource of appReplacableResources) { + const { path, ...rest } = resource + const name = path.split('/').slice(-4).join('_').replace('.png', '').replaceAll('-', '_').replaceAll('.', '_') + headerImports += `import ${name} from '${path.replace('../node_modules/', '')}'\n` + resourcesContent += ` + '${name}': { + content: ${name}, + resourcePackPath: 'minecraft/textures/${path.slice(path.indexOf('other-textures/') + 'other-textures/'.length).split('/').slice(1).join('/')}', + ...${JSON.stringify(rest)} + }, +` +} + +resourcesContent += '}' + +fs.mkdirSync('./src/generated', { recursive: true }) +fs.writeFileSync('./src/generated/resources.ts', headerImports + '\n' + resourcesContent, 'utf8') diff --git a/scripts/generateMoreCollisionShapes.mjs b/scripts/generateMoreCollisionShapes.mjs deleted file mode 100644 index ee1784788..000000000 --- a/scripts/generateMoreCollisionShapes.mjs +++ /dev/null @@ -1,209 +0,0 @@ -//@ts-check -import minecraftData from 'minecraft-data' -import minecraftAssets from 'minecraft-assets' -import fs from 'fs' - -const latestVersion = minecraftData.versions.pc[0] - -const latestData = minecraftData(latestVersion.minecraftVersion) - -// dont touch, these are the ones that are already full box -const fullBoxInteractionShapes = [ - 'dead_bush', - 'cave_vines_plant', - 'grass', - 'tall_seagrass', - 'spruce_sapling', - 'oak_sapling', - 'dark_oak_sapling', - 'birch_sapling', - 'seagrass', - 'nether_portal', - 'tall_grass', - 'lilac', - 'cobweb' -] - -const ignoreStates = [ - 'mangrove_propagule', - 'moving_piston' -] - -// const - -// to fix -const fullBoxInteractionShapesTemp = [ - 'moving_piston', - 'lime_wall_banner', - 'gray_wall_banner', - 'weeping_vines_plant', - 'pumpkin_stem', - 'red_wall_banner', - 'crimson_wall_sign', - 'magenta_wall_banner', - 'melon_stem', - 'gray_banner', - 'spruce_sign', - 'pink_wall_banner', - 'purple_banner', - 'bamboo_sapling', - 'mangrove_sign', - 'cyan_banner', - 'blue_banner', - 'green_wall_banner', - 'yellow_banner', - 'black_wall_banner', - 'green_banner', - 'oak_sign', - 'jungle_sign', - 'yellow_wall_banner', - 'lime_banner', - 'tube_coral', - 'red_banner', - 'magenta_banner', - 'brown_wall_banner', - 'white_wall_banner', -] - -const shapes = latestData.blockCollisionShapes -const fullShape = shapes.shapes[1] -const outputJson = {} - -let interestedBlocksNoStates = [] -let interestedBlocksStates = [] - -const stateIgnoreStates = ['waterlogged'] - -const isNonInteractive = block => block.name.includes('air') || block.name.includes('water') || block.name.includes('lava') || block.name.includes('void') -const interestedBlocks = latestData.blocksArray.filter(block => { - const shapeId = shapes.blocks[block.name] - // console.log('shapeId', shapeId, block.name) - if (!shapeId) return true - const shape = typeof shapeId === 'number' ? shapes.shapes[shapeId] : shapeId - if (shape.length === 0) return true - // console.log(shape) -}).filter(b => !isNonInteractive(b)).filter(b => { - if (fullBoxInteractionShapes.includes(b.name)) { - outputJson[b.name] = fullShape - return false - } - - if (!b.states?.length || ignoreStates.includes(b.name) || b.states.every(s => stateIgnoreStates.every(state => s.name === state))) { - interestedBlocksNoStates.push(b.name) - return false - } else { - interestedBlocksStates.push(b.name) - return false - } -}).map(d => d.name) - -const { blocksStates, blocksModels } = minecraftAssets(latestData.version.minecraftVersion) - -const getShapeFromModel = (block,) => { - const blockStates = JSON.parse(fs.readFileSync('./prismarine-viewer/public/blocksStates/1.19.1.json', 'utf8')) - const blockState = blockStates[block] - const perVariant = {} - for (const [key, variant] of Object.entries(blockState.variants)) { - // const shapes = (Array.isArray(variant) ? variant : [variant]).flatMap((v) => v.model?.elements).filter(Boolean).map(({ from, to }) => [...from, ...to]).reduce((acc, cur) => { - // return [ - // Math.min(acc[0], cur[0]), - // Math.min(acc[1], cur[1]), - // Math.min(acc[2], cur[2]), - // Math.max(acc[3], cur[3]), - // Math.max(acc[4], cur[4]), - // Math.max(acc[5], cur[5]) - // ] - // }) - console.log(variant) - const shapes = (Array.isArray(variant) ? variant : [variant]).flatMap((v) => v.model?.elements).filter(Boolean).map(({ from, to }) => [...from, ...to]) - perVariant[key] = shapes - break - } - return perVariant -} - -// console.log(getShapeFromModel('oak_button')) - -// const addShapeIf = { -// redstone: [ -// ['east', 'up', shape] -// ] -// } - -const needBlocksStated = {} - -const groupedBlocksRules = { - // button: block => block.includes('button'), - // pressure_plate: block => block.includes('pressure_plate'), - // sign: block => block.includes('_sign'), - // sapling: block => block.includes('_sapling'), -} -const groupedBlocksOutput = {} - -outer: for (const interestedBlock of [...interestedBlocksNoStates, ...interestedBlocksStates]) { - for (const [block, func] of Object.entries(groupedBlocksRules)) { - if (func(interestedBlock)) { - groupedBlocksOutput[block] ??= [] - groupedBlocksOutput[block].push(interestedBlock) - continue outer - } - } - - const hasStates = interestedBlocksStates.includes(interestedBlock) - if (hasStates) { - const states = blocksStates[interestedBlock] - if (!states) { - console.log('no states', interestedBlock) - continue - } - if (!states.variants) { - if (!states.multipart) { - console.log('no variants', interestedBlock) - continue - } - let outputStates = {} - for (const { when } of states.multipart) { - if (when) { - for (const [key, value] of Object.entries(when)) { - if (key === 'OR') { - for (const or of value) { - for (const [key, value] of Object.entries(or)) { - const str = `${key}=${value}` - outputStates[str] = true - } - } - continue - } - const str = `${key}=${value}` - outputStates[str] = true - } - } - } - needBlocksStated[interestedBlock] = outputStates - continue - } - if (Object.keys(states.variants).length === 1 && states.variants['']) { - needBlocksStated[interestedBlock] = false - } else { - needBlocksStated[interestedBlock] = Object.fromEntries(Object.entries(states.variants).map(([key, value]) => [key, true])) - } - } else { - needBlocksStated[interestedBlock] = false - } - // let vars = [] - // Object.keys(variants).forEach(variant => { - // if (variant !== '') vars.push(variant) - // }) - // needBlocksVariants.push({ - // block: interestedBlock, - // variants: vars - // }) -} - -fs.writeFileSync('scripts/needBlocks.json', JSON.stringify(needBlocksStated)) - -// console.log(interestedBlocks.includes('lever')) - -// read latest block states - -// read block model elements & combine diff --git a/scripts/optimizeBlockCollisions.ts b/scripts/optimizeBlockCollisions.ts index 8a87b3582..ac5e98668 100644 --- a/scripts/optimizeBlockCollisions.ts +++ b/scripts/optimizeBlockCollisions.ts @@ -49,6 +49,7 @@ for (const version of [...supportedVersions].reverse()) { const data = JSON.parse(fs.readFileSync(dataPath, 'utf8')) data.version = version processData(data) + fs.mkdirSync('./generated', { recursive: true }) fs.writeFileSync('./generated/latestBlockCollisionsShapes.json', JSON.stringify(data), 'utf8') break } diff --git a/scripts/test-texturepack-files.mjs b/scripts/test-texturepack-files.mjs deleted file mode 100644 index 0446a2fe8..000000000 --- a/scripts/test-texturepack-files.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import fs from 'fs' -import minecraftAssets from 'minecraft-assets' - -const gen = JSON.parse(fs.readFileSync('./blocks.json', 'utf8')) - -const version = '1.8.8' -const { blockNames, indexes } = gen - -const blocksActual = indexes[version].map((i) => blockNames[i]) - -const blocksExpected = fs.readdirSync(minecraftAssets(version).directory + '/blocks') -for (const [i, item] of blocksActual.entries()) { - if (item !== blocksExpected[i]) { - console.log('not equal at', i) - } -} diff --git a/server.js b/server.js index d757024b1..7adae4bbd 100644 --- a/server.js +++ b/server.js @@ -19,9 +19,6 @@ const isProd = process.argv.includes('--prod') app.use(compression()) app.use(netApi({ allowOrigin: '*' })) if (!isProd) { - app.use('/blocksStates', express.static(path.join(__dirname, './prismarine-viewer/public/blocksStates'))) - app.use('/textures', express.static(path.join(__dirname, './prismarine-viewer/public/textures'))) - app.use('/sounds', express.static(path.join(__dirname, './generated/sounds/'))) } // patch config @@ -40,23 +37,24 @@ app.get('/config.json', (req, res, next) => { 'defaultProxy': '', // use current url (this server) }) }) -// add headers to enable shared array buffer -app.use((req, res, next) => { - res.setHeader('Cross-Origin-Opener-Policy', 'same-origin') - res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') - next() -}) -app.use(express.static(path.join(__dirname, './dist'))) +if (isProd) { + // add headers to enable shared array buffer + app.use((req, res, next) => { + res.setHeader('Cross-Origin-Opener-Policy', 'same-origin') + res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + next() + }) + app.use(express.static(path.join(__dirname, './dist'))) +} -const portArg = process.argv.indexOf('--port') -const port = (require.main === module ? process.argv[2] : portArg !== -1 ? process.argv[portArg + 1] : undefined) || 8080 +const numArg = process.argv.find(x => x.match(/^\d+$/)) +const port = (require.main === module ? numArg : undefined) || 8080 // Start the server -const server = isProd ? - undefined : +const server = app.listen(port, async function () { - console.log('Server listening on port ' + server.address().port) - if (siModule) { + console.log('Proxy server listening on port ' + server.address().port) + if (siModule && isProd) { const _interfaces = await siModule.networkInterfaces() const interfaces = Array.isArray(_interfaces) ? _interfaces : [_interfaces] let netInterface = interfaces.find(int => int.default) diff --git a/src/basicSounds.ts b/src/basicSounds.ts index 53c86652b..48bdcac61 100644 --- a/src/basicSounds.ts +++ b/src/basicSounds.ts @@ -8,10 +8,10 @@ const sounds: Record = {} // load as many resources on page load as possible instead on demand as user can disable internet connection after he thinks the page is loaded const loadingSounds = [] as string[] const convertedSounds = [] as string[] -export async function loadSound (path: string) { +export async function loadSound (path: string, contents = path) { if (loadingSounds.includes(path)) return true loadingSounds.push(path) - const res = await window.fetch(path) + const res = await window.fetch(contents) if (!res.ok) { const error = `Failed to load sound ${path}` if (isCypress()) throw new Error(error) diff --git a/src/browserfs.ts b/src/browserfs.ts index ebe8acfdd..166919869 100644 --- a/src/browserfs.ts +++ b/src/browserfs.ts @@ -7,7 +7,7 @@ import * as browserfs from 'browserfs' import { options, resetOptions } from './optionsStorage' import { fsState, loadSave } from './loadSave' -import { installTexturePack, installTexturePackFromHandle, updateTexturePackInstalledState } from './texturePack' +import { installTexturePack, installTexturePackFromHandle, updateTexturePackInstalledState } from './resourcePack' import { miscUiState } from './globalState' import { setLoadingScreenStatus } from './utils' const { GoogleDriveFileSystem } = require('google-drive-browserfs/src/backends/GoogleDrive') // disable type checking @@ -531,7 +531,9 @@ export const openFilePicker = (specificCase?: 'resourcepack') => { if (!doContinue) return } if (specificCase === 'resourcepack') { - void installTexturePack(file) + void installTexturePack(file).catch((err) => { + setLoadingScreenStatus(err.message, true) + }) } else { void openWorldZip(file) } diff --git a/src/controls.ts b/src/controls.ts index 98cc6afb5..86a01151d 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -7,19 +7,20 @@ import { ControMax } from 'contro-max/build/controMax' import { CommandEventArgument, SchemaCommandInput } from 'contro-max/build/types' import { stringStartsWith } from 'contro-max/build/stringUtils' import { UserOverrideCommand, UserOverridesConfig } from 'contro-max/build/types/store' -import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCurrentModal, miscUiState } from './globalState' +import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCurrentModal, miscUiState, loadedGameState } from './globalState' import { goFullscreen, pointerLock, reloadChunks } from './utils' import { options } from './optionsStorage' import { openPlayerInventory } from './inventoryWindows' import { chatInputValueGlobal } from './react/Chat' import { fsState } from './loadSave' import { customCommandsConfig } from './customCommands' -import { CustomCommand } from './react/KeybindingsCustom' +import type { CustomCommand } from './react/KeybindingsCustom' import { showOptionsModal } from './react/SelectOption' import widgets from './react/widgets' import { getItemFromBlock } from './botUtils' import { gamepadUiCursorState, moveGamepadCursorByPx } from './react/GamepadUiCursor' -import { updateBinds } from './react/KeybindingsScreenProvider' +import { completeTexturePackInstall, resourcePackState } from './resourcePack' +import { showNotification } from './react/NotificationProvider' export const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}')) as UserOverridesConfig @@ -454,7 +455,7 @@ export const f3Keybinds = [ mobileTitle: 'Toggle chunk borders', }, { - key: 'KeyT', + key: 'KeyY', async action () { // waypoints const widgetNames = widgets.map(widget => widget.name) @@ -463,6 +464,17 @@ export const f3Keybinds = [ showModal({ reactType: `widget-${widget}` }) }, mobileTitle: 'Open Widget' + }, + { + key: 'KeyT', + async action () { + // TODO! + if (resourcePackState.resourcePackInstalled || loadedGameState.usingServerResourcePack) { + showNotification('Reloading textures...') + await completeTexturePackInstall('default', 'default') + } + }, + mobileTitle: 'Open Widget' } ] @@ -687,3 +699,30 @@ window.addEventListener('keydown', (e) => { } }) // #endregion + +export function updateBinds (commands: any) { + contro.inputSchema.commands.custom = Object.fromEntries(Object.entries(commands?.custom ?? {}).map(([key, value]) => { + return [key, { + keys: [], + gamepad: [], + type: '', + inputs: [] + }] + })) + + for (const [group, actions] of Object.entries(commands)) { + contro.userConfig![group] = Object.fromEntries(Object.entries(actions).map(([key, value]) => { + const newValue = { + keys: value?.keys ?? undefined, + gamepad: value?.gamepad ?? undefined, + } + + if (group === 'custom') { + newValue['type'] = (value).type + newValue['inputs'] = (value).inputs + } + + return [key, newValue] + })) + } +} diff --git a/src/devReload.ts b/src/devReload.ts index 19e502638..f30624e82 100644 --- a/src/devReload.ts +++ b/src/devReload.ts @@ -2,44 +2,11 @@ import { isMobile } from 'prismarine-viewer/viewer/lib/simpleUtils' import { WorldRendererThree } from 'prismarine-viewer/viewer/lib/worldrendererThree' if (process.env.NODE_ENV === 'development') { - if (sessionStorage.lastReload) { - const [rebuild, reloadStart] = sessionStorage.lastReload.split(',') - const now = Date.now() - console.log(`rebuild + reload:`, `${+rebuild} + ${now - reloadStart} = ${((+rebuild + (now - reloadStart)) / 1000).toFixed(1)}s`) - sessionStorage.lastReload = '' - } - - const autoRefresh = () => { - window.noAutoReload ??= false - new EventSource('/esbuild').onmessage = async ({ data: _data }) => { - if (!_data) return - const data = JSON.parse(_data) - if (data.update) { - console.log('[esbuild] Page is outdated') - document.title = `[O] ${document.title}` - if (window.noAutoReload || localStorage.noAutoReload) return - if (localStorage.autoReloadVisible && document.visibilityState !== 'visible') return - sessionStorage.lastReload = `${data.update.time},${Date.now()}` - location.reload() - } - if (data.replace) { - console.log('[esbuild hmr] Reloading', data.replace.type, data.replace.path) - switch (data.replace.type) { - case 'mesher': { - if (!worldView || !viewer.world.version || !(viewer.world instanceof WorldRendererThree)) return - void viewer.world.doHmr() - } - } - } - } - } - autoRefresh() - // mobile devtools if (isMobile()) { // can be changed to require('eruda') //@ts-expect-error void import('https://cdn.skypack.dev/eruda').then(({ default: eruda }) => eruda.init()) - console.log('JS Loaded in', Date.now() - window.startLoad) } } +console.log('JS Loaded in', Date.now() - window.startLoad) diff --git a/src/downloadAndOpenFile.ts b/src/downloadAndOpenFile.ts index 7ac154fcb..57e2f699c 100644 --- a/src/downloadAndOpenFile.ts +++ b/src/downloadAndOpenFile.ts @@ -1,6 +1,6 @@ import prettyBytes from 'pretty-bytes' import { openWorldZip } from './browserfs' -import { getResourcePackName, installTexturePack, resourcePackState, updateTexturePackInstalledState } from './texturePack' +import { getResourcePackNames, installTexturePack, resourcePackState, updateTexturePackInstalledState } from './resourcePack' import { setLoadingScreenStatus } from './utils' export const getFixedFilesize = (bytes: number) => { @@ -18,7 +18,7 @@ const inner = async () => { if (texturepack) { await updateTexturePackInstalledState() if (resourcePackState.resourcePackInstalled) { - if (!confirm(`You are going to install a new resource pack, which will REPLACE the current one: ${await getResourcePackName()} Continue?`)) return + if (!confirm(`You are going to install a new resource pack, which will REPLACE the current one: ${await getResourcePackNames()[0]} Continue?`)) return } } const name = mapUrl.slice(mapUrl.lastIndexOf('/') + 1).slice(-25) diff --git a/src/dragndrop.ts b/src/dragndrop.ts index 034b7b9b0..1f4b0e2b1 100644 --- a/src/dragndrop.ts +++ b/src/dragndrop.ts @@ -65,6 +65,8 @@ async function handleDroppedFile (file: File) { let versionDetected = false for (const [i, _] of Array.from({ length: 32 }).entries()) { for (const [k, _] of Array.from({ length: 32 }).entries()) { + // todo, may use faster reading, but features is not commonly used + // eslint-disable-next-line no-await-in-loop const nbt = await region.read(i, k) chunks[`${i},${k}`] = nbt if (nbt && !versionDetected) { diff --git a/src/globalState.ts b/src/globalState.ts index b7dc1602e..a332258bd 100644 --- a/src/globalState.ts +++ b/src/globalState.ts @@ -130,8 +130,6 @@ export type AppConfig = { export const miscUiState = proxy({ currentDisplayQr: null as string | null, currentTouch: null as boolean | null, - serverIp: null as string | null, - username: '', hasErrors: false, singleplayer: false, flyingSquid: false, @@ -148,6 +146,12 @@ export const miscUiState = proxy({ displaySearchInput: false, }) +export const loadedGameState = proxy({ + username: '', + serverIp: '' as string | null, + usingServerResourcePack: false, +}) + export const isGameActive = (foregroundCheck: boolean) => { if (foregroundCheck && activeModalStack.length) return false return miscUiState.gameLoaded diff --git a/src/index.ts b/src/index.ts index 2a190785a..3f964a9fd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,7 @@ import './devtools' import './entities' import './globalDomListeners' import initCollisionShapes from './getCollisionShapes' -import { itemsAtlases, onGameLoad } from './inventoryWindows' +import { onGameLoad } from './inventoryWindows' import { supportedVersions } from 'minecraft-protocol' import protocolMicrosoftAuth from 'minecraft-protocol/src/client/microsoftAuth' import microsoftAuthflow from './microsoftAuthflow' @@ -21,7 +21,7 @@ import PrismarineBlock from 'prismarine-block' import PrismarineItem from 'prismarine-item' import { options, watchValue } from './optionsStorage' -import './reactUi.jsx' +import './reactUi' import { contro, onBotCreate } from './controls' import './dragndrop' import { possiblyCleanHandle, resetStateAfterDisconnect } from './browserfs' @@ -51,6 +51,7 @@ import { hideModal, insertActiveModalStack, isGameActive, + loadedGameState, miscUiState, showModal } from './globalState' @@ -71,7 +72,7 @@ import { startLocalServer, unsupportedLocalServerFeatures } from './createLocalS import defaultServerOptions from './defaultLocalServerOptions' import dayCycle from './dayCycle' -import { genTexturePackTextures, watchTexturepackInViewer } from './texturePack' +import { onAppLoad, resourcepackOnWorldLoad } from './resourcePack' import { connectToPeer } from './localServerMultiplayer' import CustomChannelClient from './customClient' import { loadScript } from 'prismarine-viewer/viewer/lib/utils' @@ -98,6 +99,9 @@ import { signInMessageState } from './react/SignInMessageProvider' import { updateAuthenticatedAccountData, updateLoadedServerData } from './react/ServersListProvider' import { versionToNumber } from 'prismarine-viewer/viewer/prepare/utils' import packetsPatcher from './packetsPatcher' +import blockstatesModels from 'mc-assets/dist/blockStatesModels.json' +import { mainMenuState } from './react/MainMenuRenderApp' +import { ItemsRenderer } from 'mc-assets/dist/itemsRenderer' window.debug = debug window.THREE = THREE @@ -106,11 +110,14 @@ window.beforeRenderFrame = [] // ACTUAL CODE -void registerServiceWorker() +void registerServiceWorker().then(() => { + mainMenuState.serviceWorkerLoaded = true +}) watchFov() initCollisionShapes() initializePacketsReplay() packetsPatcher() +onAppLoad() // Create three.js context, add to page let renderer: THREE.WebGLRenderer @@ -149,46 +156,45 @@ if (isIphone) { // Create viewer const viewer: import('prismarine-viewer/viewer/lib/viewer').Viewer = new Viewer(renderer) window.viewer = viewer -new THREE.TextureLoader().load(itemsPng, (texture) => { - viewer.entities.itemsTexture = texture - // todo unify - viewer.entities.getItemUv = (id) => { - try { - const name = loadedData.items[id]?.name - const uv = itemsAtlases.latest.textures[name] - if (!uv) { - const variant = viewer.world.downloadedBlockStatesData[name]?.variants?.[''] - if (!variant) return - const faces = (Array.isArray(variant) ? variant[0] : variant).model?.elements?.[0]?.faces - const uvBlock = faces?.north?.texture ?? faces?.up?.texture ?? faces?.down?.texture ?? faces?.west?.texture ?? faces?.east?.texture ?? faces?.south?.texture - if (!uvBlock) return - return { - ...uvBlock, - size: Math.abs(uvBlock.su), - texture: viewer.world.material.map - } - } - return { - ...uv, - size: itemsAtlases.latest.size, - texture: viewer.entities.itemsTexture - } - } catch (err) { - reportError?.(err) - return { - u: 0, - v: 0, - size: 16 / viewer.world.material.map!.image.width, - texture: viewer.world.material.map - } +// todo unify +viewer.entities.getItemUv = (idOrName: number | string) => { + try { + const name = typeof idOrName === 'number' ? loadedData.items[idOrName]?.name : idOrName + // TODO + if (!viewer.world.itemsAtlasParser) throw new Error('itemsAtlasParser not loaded yet') + const itemsRenderer = new ItemsRenderer('latest', viewer.world.blockstatesModels, viewer.world.itemsAtlasParser, viewer.world.blocksAtlasParser) + const textureInfo = itemsRenderer.getItemTexture(name) + if (!textureInfo) throw new Error(`Texture not found for item ${name}`) + const tex = 'type' in textureInfo ? textureInfo : textureInfo.left + const [x, y, w, h] = tex.slice + const textureThree = tex.type === 'blocks' ? viewer.world.material.map! : viewer.entities.itemsTexture! + const img = textureThree.image + const [u, v, su, sv] = [x / img.width, y / img.height, (w / img.width), (h / img.height)] + const uvInfo = { + u, + v, + su, + sv + } + return { + ...uvInfo, + texture: textureThree + } + } catch (err) { + reportError?.(err) + return { + u: 0, + v: 0, + size: 16 / viewer.world.material.map!.image.width, + texture: viewer.world.material.map } } -}) +} + viewer.entities.entitiesOptions = { fontFamily: 'mojangles' } watchOptionsAfterViewerInit() -watchTexturepackInViewer(viewer) let mouseMovePostHandle = (e) => { } let lastMouseMove: number @@ -282,6 +288,9 @@ async function connect (connectOptions: ConnectOptions) { miscUiState.flyingSquid = singleplayer || p2pMultiplayer const { renderDistance: renderDistanceSingleplayer, multiplayerRenderDistance } = options const server = cleanConnectIp(connectOptions.server, '25565') + if (connectOptions.proxy?.startsWith(':')) { + connectOptions.proxy = `${location.protocol}//${location.hostname}${connectOptions.proxy}` + } const proxy = cleanConnectIp(connectOptions.proxy, undefined) let { username } = connectOptions @@ -393,7 +402,7 @@ async function connect (connectOptions: ConnectOptions) { await loadScript(`./mc-data/${toMajorVersion(version)}.js`) miscUiState.loadedDataVersion = version try { - await genTexturePackTextures(version) + await resourcepackOnWorldLoad(version) } catch (err) { console.error(err) const doContinue = confirm('Failed to apply texture pack. See errors in the console. Continue?') @@ -401,7 +410,8 @@ async function connect (connectOptions: ConnectOptions) { throw err } } - viewer.setVersion(version) + viewer.world.blockstatesModels = blockstatesModels + viewer.setVersion(version, options.useVersionsTextures === 'latest' ? version : options.useVersionsTextures) } const downloadVersion = connectOptions.botVersion || (singleplayer ? serverOptions.version : undefined) @@ -851,13 +861,8 @@ async function connect (connectOptions: ConnectOptions) { // todo onGameLoad(async () => { - if (!viewer.world.downloadedBlockStatesData && !viewer.world.customBlockStatesData) { - await new Promise(resolve => { - viewer.world.renderUpdateEmitter.once('blockStatesDownloaded', () => resolve()) - }) - } - miscUiState.serverIp = server.host as string | null - miscUiState.username = username + loadedGameState.serverIp = server.host ?? null + loadedGameState.username = username }) if (appStatusState.isError) return diff --git a/src/inventoryWindows.ts b/src/inventoryWindows.ts index fd213509a..5f4596b52 100644 --- a/src/inventoryWindows.ts +++ b/src/inventoryWindows.ts @@ -1,32 +1,29 @@ import { proxy, subscribe } from 'valtio' import { showInventory } from 'minecraft-inventory-gui/web/ext.mjs' -import InventoryGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/inventory.png' -import ChestLikeGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/shulker_box.png' -import LargeChestLikeGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/generic_54.png' -import FurnaceGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/furnace.png' -import CraftingTableGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/crafting_table.png' -import DispenserGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/dispenser.png' -import HopperGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/hopper.png' -import HorseGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/horse.png' -import VillagerGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/villager2.png' -import EnchantingGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/enchanting_table.png' -import AnvilGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/anvil.png' -import BeaconGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/container/beacon.png' -import WidgetsGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/widgets.png' - -import Dirt from 'minecraft-assets/minecraft-assets/data/1.17.1/blocks/dirt.png' +import InventoryGui from 'mc-assets/dist/other-textures/latest/gui/container/inventory.png' +import ChestLikeGui from 'mc-assets/dist/other-textures/latest/gui/container/shulker_box.png' +import LargeChestLikeGui from 'mc-assets/dist/other-textures/latest/gui/container/generic_54.png' +import FurnaceGui from 'mc-assets/dist/other-textures/latest/gui/container/furnace.png' +import CraftingTableGui from 'mc-assets/dist/other-textures/latest/gui/container/crafting_table.png' +import DispenserGui from 'mc-assets/dist/other-textures/latest/gui/container/dispenser.png' +import HopperGui from 'mc-assets/dist/other-textures/latest/gui/container/hopper.png' +import HorseGui from 'mc-assets/dist/other-textures/latest/gui/container/horse.png' +import VillagerGui from 'mc-assets/dist/other-textures/latest/gui/container/villager2.png' +import EnchantingGui from 'mc-assets/dist/other-textures/latest/gui/container/enchanting_table.png' +import AnvilGui from 'mc-assets/dist/other-textures/latest/gui/container/anvil.png' +import BeaconGui from 'mc-assets/dist/other-textures/latest/gui/container/beacon.png' +import WidgetsGui from 'mc-assets/dist/other-textures/latest/gui/widgets.png' + +// import Dirt from 'mc-assets/dist/other-textures/latest/blocks/dirt.png' import { RecipeItem } from 'minecraft-data' import { versionToNumber } from 'prismarine-viewer/viewer/prepare/utils' -import itemsPng from 'prismarine-viewer/public/textures/items.png' -import itemsLegacyPng from 'prismarine-viewer/public/textures/items-legacy.png' import _itemsAtlases from 'prismarine-viewer/public/textures/items.json' -import type { ItemsAtlasesOutputJson } from 'prismarine-viewer/viewer/prepare/genItemsAtlas' -import PrismarineBlockLoader from 'prismarine-block' import { flat } from '@xmcl/text-component' import mojangson from 'mojangson' import nbt from 'prismarine-nbt' import { splitEvery, equals } from 'rambda' import PItem, { Item } from 'prismarine-item' +import { ItemsRenderer } from 'mc-assets/dist/itemsRenderer' import Generic95 from '../assets/generic_95.png' import { activeModalStack, hideCurrentModal, hideModal, miscUiState, showModal } from './globalState' import invspriteJson from './invsprite.json' @@ -36,7 +33,6 @@ import { MessageFormatPart } from './botUtils' import { currentScaling } from './scaleInterface' import { descriptionGenerators, getItemDescription } from './itemsDescriptions' -export const itemsAtlases: ItemsAtlasesOutputJson = _itemsAtlases const loadedImagesCache = new Map() const cleanLoadedImagesCache = () => { loadedImagesCache.delete('blocks') @@ -63,28 +59,28 @@ export type BlockStates = Record /** bot version */ let version: string -let PrismarineBlock: typeof PrismarineBlockLoader.Block let PrismarineItem: typeof Item export const allImagesLoadedState = proxy({ value: false }) +let itemsRenderer: ItemsRenderer export const onGameLoad = (onLoad) => { allImagesLoadedState.value = false - let loaded = 0 - const onImageLoaded = () => { - loaded++ - if (loaded === 3) { - onLoad?.() - allImagesLoadedState.value = true - } - } version = bot.version - getImage({ path: 'invsprite' }, onImageLoaded) - getImage({ path: 'items' }, onImageLoaded) - getImage({ path: 'items-legacy' }, onImageLoaded) - PrismarineBlock = PrismarineBlockLoader(version) + + const checkIfLoaded = () => { + if (!viewer.world.itemsAtlasParser) return + itemsRenderer = new ItemsRenderer('latest', viewer.world.blockstatesModels, viewer.world.itemsAtlasParser, viewer.world.blocksAtlasParser) + globalThis.itemsRenderer = itemsRenderer + if (allImagesLoadedState.value) return + onLoad?.() + allImagesLoadedState.value = true + } + viewer.world.renderUpdateEmitter.on('textureDownloaded', checkIfLoaded) + checkIfLoaded() + PrismarineItem = PItem(version) bot.on('windowOpen', (win) => { @@ -144,65 +140,12 @@ export const onGameLoad = (onLoad) => { }) } -const findTextureInBlockStates = (name) => { - assertDefined(viewer) - const blockStates: BlockStates = viewer.world.customBlockStatesData || viewer.world.downloadedBlockStatesData - const vars = blockStates[name]?.variants - if (!vars) return - let firstVar = Object.values(vars)[0] - if (Array.isArray(firstVar)) firstVar = firstVar[0] - if (!firstVar) return - const elements = firstVar.model?.elements - if (elements?.length !== 1) return - return elements[0].faces -} - -const svSuToCoordinates = (path: string, u, v, su, sv = su) => { - const img = getImage({ path })! - if (!img.width) throw new Error(`Image ${path} is not loaded`) - return [u * img.width, v * img.height, su * img.width, sv * img.height] -} - -const getBlockData = (name) => { - const data = findTextureInBlockStates(name) - if (!data) return - - const getSpriteBlockSide = (side) => { - const d = data[side]?.texture - if (!d) return - const spriteSide = svSuToCoordinates('blocks', d.u, d.v, d.su, d.sv) - const blockSideData = { - slice: spriteSide, - path: 'blocks' - } - return blockSideData - } - - return { - // todo look at grass bug - top: getSpriteBlockSide('up') || getSpriteBlockSide('top'), - left: getSpriteBlockSide('east') || getSpriteBlockSide('side'), - right: getSpriteBlockSide('north') || getSpriteBlockSide('side'), - } -} - -const getInvspriteSlice = (name) => { - const invspriteImg = loadedImagesCache.get('invsprite') - if (!invspriteImg?.width) return - - const { x, y } = invspriteJson[name] ?? /* unknown item */ { x: 0, y: 0 } - const sprite = [x, y, 32, 32] - return sprite -} - const getImageSrc = (path): string | HTMLImageElement => { assertDefined(viewer) switch (path) { case 'gui/container/inventory': return InventoryGui - case 'blocks': return viewer.world.customTexturesDataUrl || viewer.world.downloadedTextureImage - case 'invsprite': return `invsprite.png` - case 'items': return itemsPng - case 'items-legacy': return itemsLegacyPng + case 'blocks': return viewer.world.blocksAtlasParser!.latestImage + case 'items': return viewer.world.itemsAtlasParser!.latestImage case 'gui/container/dispenser': return DispenserGui case 'gui/container/furnace': return FurnaceGui case 'gui/container/crafting_table': return CraftingTableGui @@ -217,7 +160,8 @@ const getImageSrc = (path): string | HTMLImageElement => { case 'gui/container/beacon': return BeaconGui case 'gui/widgets': return WidgetsGui } - return Dirt + // empty texture + return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=' } const getImage = ({ path = undefined as string | undefined, texture = undefined as string | undefined, blockData = undefined as any }, onLoad = () => { }) => { @@ -240,72 +184,28 @@ const getImage = ({ path = undefined as string | undefined, texture = undefined return loadedImagesCache.get(loadPath) } -const getItemVerToRender = (version: string, item: string, itemsMapSortedEntries: any[]) => { - const verNumber = versionToNumber(version) - for (const [itemsVer, items] of itemsMapSortedEntries) { - // 1.18 < 1.18.1 - // 1.13 < 1.13.2 - if (items.includes(item) && verNumber <= versionToNumber(itemsVer)) { - return itemsVer as string - } - } -} - -const isFullBlock = (block: string) => { - const blockData = loadedData.blocksByName[block] - if (!blockData) return false - const pBlock = new PrismarineBlock(blockData.id, 0, 0) - if (pBlock.shapes?.length !== 1) return false - const shape = pBlock.shapes[0]! - return shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1 -} - type RenderSlot = Pick -const renderSlot = (slot: RenderSlot, skipBlock = false): { texture: string, blockData?, scale?: number, slice?: number[] } | undefined => { +const renderSlot = (slot: RenderSlot, skipBlock = false): { + texture: string, + blockData?: Record, + scale?: number, + slice?: number[] +} | undefined => { const itemName = slot.name const isItem = loadedData.itemsByName[itemName] - const fullBlock = isFullBlock(itemName) - - if (isItem) { - const legacyItemVersion = getItemVerToRender(version, itemName, itemsAtlases.legacyMap) - const vuToSlice = ({ u, v }, size) => [...svSuToCoordinates('items', u, v, size).slice(0, 2), 16, 16] // item size is fixed - if (legacyItemVersion) { - const textureData = itemsAtlases.legacy.textures[`${legacyItemVersion}-${itemName}`]! - return { - texture: 'items-legacy', - slice: vuToSlice(textureData, itemsAtlases.legacy.size) - } - } - const textureData = itemsAtlases.latest.textures[itemName] - if (textureData) { - return { - texture: 'items', - slice: vuToSlice(textureData, itemsAtlases.latest.size) - } - } - } - if (fullBlock && !skipBlock) { - const blockData = getBlockData(itemName) - if (blockData) { - return { - texture: 'blocks', - blockData - } - } - } - const invspriteSlice = getInvspriteSlice(itemName) - if (invspriteSlice) { + + const itemTexture = itemsRenderer.getItemTexture(itemName) ?? itemsRenderer.getItemTexture('item/missing_texture')! + if ('type' in itemTexture) { + // is item return { - texture: 'invsprite', - scale: 0.5, - slice: invspriteSlice + texture: 'items', + slice: itemTexture.slice } - } - console.warn(`No render data for ${itemName}`) - if (isItem) { + } else { + // is block return { texture: 'blocks', - slice: [0, 0, 16, 16] + blockData: itemTexture } } } diff --git a/src/loadSave.ts b/src/loadSave.ts index 7ca454ff6..a0d2fdcbc 100644 --- a/src/loadSave.ts +++ b/src/loadSave.ts @@ -159,6 +159,7 @@ export const loadSave = async (root = '/world') => { // improve compatibility with community saves const rootRemapFiles = ['Warp files'] for (const rootRemapFile of rootRemapFiles) { + // eslint-disable-next-line no-await-in-loop if (await existsViaStats(path.join(root, '..', rootRemapFile))) { forceRedirectPaths[path.join(root, rootRemapFile)] = path.join(root, '..', rootRemapFile) } diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 76799a60e..f41d0e0c5 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -1,15 +1,16 @@ import { useState } from 'react' import { useSnapshot } from 'valtio' import { openURL } from 'prismarine-viewer/viewer/lib/simpleUtils' -import { miscUiState, openOptionsMenu, showModal } from './globalState' +import { loadedGameState, miscUiState, openOptionsMenu, showModal } from './globalState' import { AppOptions, options } from './optionsStorage' import Button from './react/Button' import { OptionMeta, OptionSlider } from './react/OptionsItems' import Slider from './react/Slider' import { getScreenRefreshRate, setLoadingScreenStatus } from './utils' import { openFilePicker, resetLocalStorageWithoutWorld } from './browserfs' -import { getResourcePackName, resourcePackState, uninstallTexturePack } from './texturePack' +import { completeTexturePackInstall, getResourcePackNames, resourcePackState, uninstallTexturePack } from './resourcePack' import { downloadPacketsReplay, packetsReplaceSessionState } from './packetsReplay' +import { showOptionsModal } from './react/SelectOption' export const guiOptionsScheme: { @@ -119,12 +120,30 @@ export const guiOptionsScheme: { { custom () { const { resourcePackInstalled } = useSnapshot(resourcePackState) - return )} - + }}>Cancel} } diff --git a/src/react/SharedHudVars.tsx b/src/react/SharedHudVars.tsx index 6cc0c54e9..7b9f2f2eb 100644 --- a/src/react/SharedHudVars.tsx +++ b/src/react/SharedHudVars.tsx @@ -1,6 +1,7 @@ -import { CSSProperties, useEffect } from 'react' -import icons from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/icons.png' -import widgets from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/widgets.png' +import { useEffect } from 'react' + +// appReplacableResources +import { appReplacableResources } from '../generated/resources' export default ({ children }): React.ReactElement => { useEffect(() => { @@ -9,8 +10,11 @@ export default ({ children }): React.ReactElement => { // 2. Easier application to globally override icons with custom image (eg from resourcepacks) const css = /* css */` html { - --widgets-gui-atlas: url(${widgets}); - --gui-icons: url(${icons}), url(${icons}); + ${Object.values(appReplacableResources).filter(r => r.cssVar).map(r => { + const repeat = r.cssVarRepeat ?? 1 + return `${r.cssVar}: ${repeatArr(`url('${r.content}')`, repeat).join(', ')};` + }).join('\n')} + --hud-bottom-max: 0px; --hud-bottom-raw: max(env(safe-area-inset-bottom), var(--hud-bottom-max)); --safe-area-inset-bottom: calc(var(--hud-bottom-raw) / 2); @@ -24,3 +28,8 @@ export default ({ children }): React.ReactElement => { return children } + +// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint +const repeatArr = (item: T, times: number): T[] => { + return Array.from({ length: times }, () => item) +} diff --git a/src/react/Singleplayer.tsx b/src/react/Singleplayer.tsx index 76a75e827..a78518358 100644 --- a/src/react/Singleplayer.tsx +++ b/src/react/Singleplayer.tsx @@ -2,7 +2,7 @@ import classNames from 'classnames' import { Fragment, useEffect, useMemo, useRef, useState } from 'react' // todo optimize size -import missingWorldPreview from 'minecraft-assets/minecraft-assets/data/1.10/gui/presets/isles.png' +import missingWorldPreview from 'mc-assets/dist/other-textures/latest/gui/presets/isles.png' import { filesize } from 'filesize' import useTypedEventListener from 'use-typed-event-listener' import { focusable } from 'tabbable' diff --git a/src/react/SingleplayerProvider.tsx b/src/react/SingleplayerProvider.tsx index 83d28637c..91aa23c0d 100644 --- a/src/react/SingleplayerProvider.tsx +++ b/src/react/SingleplayerProvider.tsx @@ -66,6 +66,7 @@ export const readWorlds = (abortController: AbortController) => { if (providersEnableFeatures[provider].calculateSize) { // todo use whole dir size for (const region of await fs.promises.readdir(`${worldsPath}/${folder}/region`)) { + // eslint-disable-next-line no-await-in-loop -- it's still fast enough, nobody complains about it const stat = await fs.promises.stat(`${worldsPath}/${folder}/region/${region}`) size += stat.size } diff --git a/src/react/XPBar.module.css b/src/react/XPBar.module.css index e9598f995..34aa59337 100644 --- a/src/react/XPBar.module.css +++ b/src/react/XPBar.module.css @@ -6,7 +6,7 @@ transform: translate(-50%); width: 182px; height: 5px; - background-image: url('minecraft-assets/minecraft-assets/data/1.16.4/gui/icons.png'); + background-image: var(--gui-icons); background-size: 256px; background-position-y: -64px; } @@ -14,7 +14,7 @@ .xp-bar { width: 182px; height: 5px; - background-image: url('minecraft-assets/minecraft-assets/data/1.17.1/gui/icons.png'); + background-image: var(--gui-icons); background-size: 256px; background-position-y: -69px; } diff --git a/src/react/XPBar.module.css.d.ts b/src/react/XPBar.module.css.d.ts new file mode 100644 index 000000000..890459855 --- /dev/null +++ b/src/react/XPBar.module.css.d.ts @@ -0,0 +1,12 @@ +// This file is automatically generated. +// Please do not change this file! +interface CssExports { + 'xp-bar': string; + 'xp-bar-bg': string; + 'xp-label': string; + xpBar: string; + xpBarBg: string; + xpLabel: string; +} +declare const cssExports: CssExports; +export default cssExports; diff --git a/src/react/appStatus.module.css.d.ts b/src/react/appStatus.module.css.d.ts new file mode 100644 index 000000000..2f78b153d --- /dev/null +++ b/src/react/appStatus.module.css.d.ts @@ -0,0 +1,10 @@ +// This file is automatically generated. +// Please do not change this file! +interface CssExports { + 'last-status': string; + lastStatus: string; + 'potential-problem': string; + potentialProblem: string; +} +declare const cssExports: CssExports; +export default cssExports; diff --git a/src/react/button.module.css.d.ts b/src/react/button.module.css.d.ts new file mode 100644 index 000000000..ae9aac73c --- /dev/null +++ b/src/react/button.module.css.d.ts @@ -0,0 +1,8 @@ +// This file is automatically generated. +// Please do not change this file! +interface CssExports { + button: string; + icon: string; +} +declare const cssExports: CssExports; +export default cssExports; diff --git a/src/react/createWorld.module.css.d.ts b/src/react/createWorld.module.css.d.ts new file mode 100644 index 000000000..42764730d --- /dev/null +++ b/src/react/createWorld.module.css.d.ts @@ -0,0 +1,10 @@ +// This file is automatically generated. +// Please do not change this file! +interface CssExports { + worldLayer: string; + worldLayersContainer: string; + world_layer: string; + world_layers_container: string; +} +declare const cssExports: CssExports; +export default cssExports; diff --git a/src/react/effectsImages.ts b/src/react/effectsImages.ts index 21421e0f6..832d96460 100644 --- a/src/react/effectsImages.ts +++ b/src/react/effectsImages.ts @@ -1,36 +1,36 @@ -import absorption from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/absorption.png' -import glowing from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/glowing.png' -import instant_health from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/instant_health.png' -import nausea from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/nausea.png' -import slow_falling from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/slow_falling.png' -import weakness from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/weakness.png' -import bad_omen from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/bad_omen.png' -import haste from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/haste.png' -import invisibility from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/invisibility.png' -import night_vision from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/night_vision.png' -import slowness from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/slowness.png' -import wither from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/wither.png' -import blindness from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/blindness.png' -import health_boost from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/health_boost.png' -import jump_boost from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/jump_boost.png' -import poison from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/poison.png' -import speed from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/speed.png' -import conduit_power from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/conduit_power.png' -import hero_of_the_village from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/hero_of_the_village.png' -import levitation from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/levitation.png' -import regeneration from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/regeneration.png' -import strength from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/strength.png' -import dolphins_grace from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/dolphins_grace.png' -import hunger from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/hunger.png' -import luck from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/luck.png' -import resistance from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/resistance.png' -import unluck from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/unluck.png' -import fire_resistance from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/fire_resistance.png' -import instant_damage from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/instant_damage.png' -import mining_fatigue from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/mining_fatigue.png' -import saturation from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/saturation.png' -import water_breathing from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/water_breathing.png' -import darkness from 'minecraft-assets/minecraft-assets/data/1.20.2/mob_effect/darkness.png' +import absorption from 'mc-assets/dist/other-textures/latest/mob_effect/absorption.png' +import glowing from 'mc-assets/dist/other-textures/latest/mob_effect/glowing.png' +import instant_health from 'mc-assets/dist/other-textures/latest/mob_effect/instant_health.png' +import nausea from 'mc-assets/dist/other-textures/latest/mob_effect/nausea.png' +import slow_falling from 'mc-assets/dist/other-textures/latest/mob_effect/slow_falling.png' +import weakness from 'mc-assets/dist/other-textures/latest/mob_effect/weakness.png' +import bad_omen from 'mc-assets/dist/other-textures/latest/mob_effect/bad_omen.png' +import haste from 'mc-assets/dist/other-textures/latest/mob_effect/haste.png' +import invisibility from 'mc-assets/dist/other-textures/latest/mob_effect/invisibility.png' +import night_vision from 'mc-assets/dist/other-textures/latest/mob_effect/night_vision.png' +import slowness from 'mc-assets/dist/other-textures/latest/mob_effect/slowness.png' +import wither from 'mc-assets/dist/other-textures/latest/mob_effect/wither.png' +import blindness from 'mc-assets/dist/other-textures/latest/mob_effect/blindness.png' +import health_boost from 'mc-assets/dist/other-textures/latest/mob_effect/health_boost.png' +import jump_boost from 'mc-assets/dist/other-textures/latest/mob_effect/jump_boost.png' +import poison from 'mc-assets/dist/other-textures/latest/mob_effect/poison.png' +import speed from 'mc-assets/dist/other-textures/latest/mob_effect/speed.png' +import conduit_power from 'mc-assets/dist/other-textures/latest/mob_effect/conduit_power.png' +import hero_of_the_village from 'mc-assets/dist/other-textures/latest/mob_effect/hero_of_the_village.png' +import levitation from 'mc-assets/dist/other-textures/latest/mob_effect/levitation.png' +import regeneration from 'mc-assets/dist/other-textures/latest/mob_effect/regeneration.png' +import strength from 'mc-assets/dist/other-textures/latest/mob_effect/strength.png' +import dolphins_grace from 'mc-assets/dist/other-textures/latest/mob_effect/dolphins_grace.png' +import hunger from 'mc-assets/dist/other-textures/latest/mob_effect/hunger.png' +import luck from 'mc-assets/dist/other-textures/latest/mob_effect/luck.png' +import resistance from 'mc-assets/dist/other-textures/latest/mob_effect/resistance.png' +import unluck from 'mc-assets/dist/other-textures/latest/mob_effect/unluck.png' +import fire_resistance from 'mc-assets/dist/other-textures/latest/mob_effect/fire_resistance.png' +import instant_damage from 'mc-assets/dist/other-textures/latest/mob_effect/instant_damage.png' +import mining_fatigue from 'mc-assets/dist/other-textures/latest/mob_effect/mining_fatigue.png' +import saturation from 'mc-assets/dist/other-textures/latest/mob_effect/saturation.png' +import water_breathing from 'mc-assets/dist/other-textures/latest/mob_effect/water_breathing.png' +import darkness from 'mc-assets/dist/other-textures/latest/mob_effect/darkness.png' interface Images { [key: string]: string; diff --git a/src/react/globals.d.ts b/src/react/globals.d.ts index 62494f9f1..b9d647553 100644 --- a/src/react/globals.d.ts +++ b/src/react/globals.d.ts @@ -33,6 +33,10 @@ declare module '*.webp' { const svg: string export default svg } +declare module '*.mp3' { + const mp3: any + export default mp3 +} interface PromiseConstructor { withResolvers (): { diff --git a/src/react/input.module.css.d.ts b/src/react/input.module.css.d.ts new file mode 100644 index 000000000..10b86cad2 --- /dev/null +++ b/src/react/input.module.css.d.ts @@ -0,0 +1,8 @@ +// This file is automatically generated. +// Please do not change this file! +interface CssExports { + container: string; + input: string; +} +declare const cssExports: CssExports; +export default cssExports; diff --git a/src/react/mainMenu.module.css b/src/react/mainMenu.module.css index a6241806a..d4a7e3a5d 100644 --- a/src/react/mainMenu.module.css +++ b/src/react/mainMenu.module.css @@ -5,7 +5,9 @@ .game-title { position: fixed; top: var(--top-offset); - left: calc(50% - 137px); + width: 100%; + display: flex; + justify-content: center; } .game-title .minec { @@ -18,6 +20,14 @@ width: 155px; height: 44px; } +.game-title .minecraft { + display: block; + position: relative; + background-image: var(--title-gui); + background-size: 256px; + width: 256px; + height: 44px; +} .game-title .raft { display: block; @@ -36,7 +46,7 @@ position: absolute; top: 37px; left: calc(88px + 5px); - background-image: url('extra-textures/edition.png'); + background-image: url('../../assets/edition.png'); background-size: 128px; width: 88px; height: 14px; diff --git a/src/react/mainMenu.module.css.d.ts b/src/react/mainMenu.module.css.d.ts new file mode 100644 index 000000000..8cc84b947 --- /dev/null +++ b/src/react/mainMenu.module.css.d.ts @@ -0,0 +1,26 @@ +// This file is automatically generated. +// Please do not change this file! +interface CssExports { + 'bottom-info': string; + bottomInfo: string; + edition: string; + 'game-title': string; + gameTitle: string; + 'maps-provider': string; + mapsProvider: string; + menu: string; + 'menu-row': string; + menuRow: string; + minec: string; + minecraft: string; + 'product-description': string; + 'product-info': string; + productDescription: string; + productInfo: string; + raft: string; + root: string; + splash: string; + splashAnim: string; +} +declare const cssExports: CssExports; +export default cssExports; diff --git a/src/react/singleplayer.module.css.d.ts b/src/react/singleplayer.module.css.d.ts new file mode 100644 index 000000000..7dbf98a32 --- /dev/null +++ b/src/react/singleplayer.module.css.d.ts @@ -0,0 +1,29 @@ +// This file is automatically generated. +// Please do not change this file! +interface CssExports { + content: string; + contentLoading: string; + content_loading: string; + imageMissing: string; + image_missing: string; + root: string; + title: string; + worldFocused: string; + worldImage: string; + worldInfo: string; + worldInfoDescriptionLine: string; + worldInfoFormatted: string; + worldRoot: string; + worldTitle: string; + worldTitleRight: string; + world_focused: string; + world_image: string; + world_info: string; + world_info_description_line: string; + world_info_formatted: string; + world_root: string; + world_title: string; + world_title_right: string; +} +declare const cssExports: CssExports; +export default cssExports; diff --git a/src/react/slider.module.css.d.ts b/src/react/slider.module.css.d.ts new file mode 100644 index 000000000..8a6b8933a --- /dev/null +++ b/src/react/slider.module.css.d.ts @@ -0,0 +1,13 @@ +// This file is automatically generated. +// Please do not change this file! +interface CssExports { + disabled: string; + label: string; + slider: string; + 'slider-container': string; + 'slider-thumb': string; + sliderContainer: string; + sliderThumb: string; +} +declare const cssExports: CssExports; +export default cssExports; diff --git a/src/resourcePack.ts b/src/resourcePack.ts new file mode 100644 index 000000000..0409fda4c --- /dev/null +++ b/src/resourcePack.ts @@ -0,0 +1,345 @@ +import { join, dirname, basename } from 'path' +import fs from 'fs' +import JSZip from 'jszip' +import { proxy, ref } from 'valtio' +import type { BlockStates } from './inventoryWindows' +import { copyFilesAsync, copyFilesAsyncWithProgress, mkdirRecursive, removeFileRecursiveAsync } from './browserfs' +import { setLoadingScreenStatus } from './utils' +import { showNotification } from './react/NotificationProvider' +import { options } from './optionsStorage' +import { showOptionsModal } from './react/SelectOption' +import { appStatusState } from './react/AppStatusProvider' +import { appReplacableResources } from './generated/resources' + +export const resourcePackState = proxy({ + resourcePackInstalled: false, + currentTexturesDataUrl: undefined as string | undefined, + currentTexturesBlockStates: undefined as BlockStates | undefined, +}) + +const getLoadedImage = async (url: string) => { + const img = new Image() + img.src = url + await new Promise((resolve, reject) => { + img.onload = resolve + img.onerror = reject + }) + return img +} + +const texturePackBasePath2 = '/data/resourcePacks/' +export const uninstallTexturePack = async (name = 'default') => { + const basePath = texturePackBasePath2 + name + await removeFileRecursiveAsync(basePath) + options.enabledResourcepack = null + await updateTexturePackInstalledState() +} + +export const getResourcePackNames = async () => { + // TODO + try { + return { [await fs.promises.readFile(join(texturePackBasePath2, 'default', 'name.txt'), 'utf8')]: true } + } catch (err) { + return {} + } +} + +export const fromTexturePackPath = (path) => { + // return join(texturePackBasePath, path) +} + +export const updateTexturePackInstalledState = async () => { + try { + resourcePackState.resourcePackInstalled = await existsAsync(texturePackBasePath2 + 'default') + } catch { + } +} + +export const installTexturePackFromHandle = async () => { + // await mkdirRecursive(texturePackBasePath) + // await copyFilesAsyncWithProgress('/world', texturePackBasePath) + // await completeTexturePackInstall() +} + +export const installTexturePack = async (file: File | ArrayBuffer, displayName = file['name'], name = 'default') => { + try { + await uninstallTexturePack(name) + } catch (err) { + } + 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() + const zipFile = await zip.loadAsync(file) + if (!zipFile.file('pack.mcmeta')) throw new Error('Not a resource pack: missing /pack.mcmeta') + const basePath = texturePackBasePath2 + name + await mkdirRecursive(basePath) + + const allFilesArr = Object.entries(zipFile.files) + let done = 0 + const upStatus = () => { + setLoadingScreenStatus(`${status} ${Math.round(done / allFilesArr.length * 100)}%`) + } + const createdDirs = new Set() + const copyTasks = [] as Array> + await Promise.all(allFilesArr.map(async ([path, file]) => { + // ignore dot files and __MACOSX + if (path.startsWith('.') || path.startsWith('_') || path.startsWith('/')) return + const writePath = join(basePath, path) + if (path.endsWith('/')) return + const dir = dirname(writePath) + if (!createdDirs.has(dir)) { + await mkdirRecursive(dir) + createdDirs.add(dir) + } + if (copyTasks.length > 100) { + await Promise.all(copyTasks) + copyTasks.length = 0 + } + const promise = fs.promises.writeFile(writePath, Buffer.from(await file.async('arraybuffer'))) + copyTasks.push(promise) + await promise + done++ + upStatus() + })) + console.log('done') + await completeTexturePackInstall(displayName, name) +} + +// or enablement +export const completeTexturePackInstall = async (displayName: string, name: string) => { + const basePath = texturePackBasePath2 + name + await fs.promises.writeFile(join(basePath, 'name.txt'), displayName, 'utf8') + + if (viewer?.world.active) { + await updateTextures() + } + setLoadingScreenStatus(undefined) + showNotification('Texturepack installed & enabled') + await updateTexturePackInstalledState() + options.enabledResourcepack = name +} + +const existsAsync = async (path) => { + try { + await fs.promises.stat(path) + return true + } catch (err) { + return false + } +} + +const arrEqual = (a: any[], b: any[]) => a.length === b.length && a.every((x) => b.includes(x)) + +const getSizeFromImage = async (filePath: string) => { + const probeImg = new Image() + const file = await fs.promises.readFile(filePath, 'base64') + probeImg.src = `data:image/png;base64,${file}` + await new Promise((resolve, reject) => { + probeImg.addEventListener('load', resolve) + }) + if (probeImg.width !== probeImg.height) throw new Error(`Probe texture ${filePath} is not square`) + return probeImg.width +} + +export const getActiveTexturepackBasePath = async () => { + if (await existsAsync('/data/resourcePacks/server/pack.mcmeta')) { + return '/data/resourcePacks/server' + } + const { enabledResourcepack } = options + // const enabledResourcepack = 'default' + if (!enabledResourcepack) { + return null + } + if (await existsAsync(`/data/resourcePacks/${enabledResourcepack}/pack.mcmeta`)) { + return `/data/resourcePacks/${enabledResourcepack}` + } + return null +} + +export const getResourcepackTiles = async (type: 'blocks' | 'items', existingTextures: string[]) => { + const basePath = await getActiveTexturepackBasePath() + if (!basePath) return + const texturesCommonBasePath = `${basePath}/assets/minecraft/textures` + let texturesBasePath = `${texturesCommonBasePath}/${type === 'blocks' ? 'block' : 'item'}` + const texturesBasePathAlt = `${texturesCommonBasePath}/${type === 'blocks' ? 'blocks' : 'items'}` + if (!(await existsAsync(texturesBasePath))) { + if (await existsAsync(texturesBasePathAlt)) { + texturesBasePath = texturesBasePathAlt + } + } + const allInterestedPaths = existingTextures.map(tex => { + if (tex.includes('/')) { + return join(`${texturesCommonBasePath}/${tex}`) + } + return join(texturesBasePath, tex) + }) + const allInterestedPathsPerDir = new Map() + for (const path of allInterestedPaths) { + const dir = dirname(path) + if (!allInterestedPathsPerDir.has(dir)) { + allInterestedPathsPerDir.set(dir, []) + } + const file = basename(path) + allInterestedPathsPerDir.get(dir)!.push(file) + } + // filter out by readdir each dir + const allInterestedImages = [] as string[] + for (const [dir, paths] of allInterestedPathsPerDir) { + if (!await existsAsync(dir)) { + continue + } + const dirImages = (await fs.promises.readdir(dir)).filter(f => f.endsWith('.png')).map(f => f.replace('.png', '')) + allInterestedImages.push(...dirImages.filter(image => paths.includes(image)).map(image => `${dir}/${image}`)) + } + + if (allInterestedImages.length === 0) { + return + } + + if (appStatusState.status) { + setLoadingScreenStatus(`Generating atlas texture for ${type}`) + } + + const firstImageFile = allInterestedImages[0]! + + let firstTextureSize: number | undefined + try { + // todo compare sizes from atlas + firstTextureSize = await getSizeFromImage(`${firstImageFile}.png`) + } catch (err) { } + const textures = Object.fromEntries( + await Promise.all(allInterestedImages.map(async (image) => { + const imagePath = `${image}.png` + const contents = await fs.promises.readFile(imagePath, 'base64') + const img = await getLoadedImage(`data:image/png;base64,${contents}`) + const imageRelative = image.replace(`${texturesBasePath}/`, '').replace(`${texturesCommonBasePath}/`, '') + return [imageRelative, img] + })) + ) + return { + firstTextureSize, + textures + } +} + +const prepareBlockstatesAndModels = async () => { + viewer.world.customBlockStates = undefined + viewer.world.customModels = undefined + const basePath = await getActiveTexturepackBasePath() + if (!basePath) return + if (appStatusState.status) { + setLoadingScreenStatus('Reading resource pack blockstates and models') + } + const readData = async (namespaceDir: string) => { + const blockstatesPath = `${basePath}/assets/${namespaceDir}/blockstates` + const modelsPath = `${basePath}/assets/${namespaceDir}/models/block` // todo also models/item + const getAllJson = async (path: string, type: 'models' | 'blockstates') => { + if (!(await existsAsync(path))) return + const files = await fs.promises.readdir(path) + const jsons = {} as Record + await Promise.all(files.map(async (file) => { + const filePath = `${path}/${file}` + if (file.endsWith('.json')) { + const contents = await fs.promises.readFile(filePath, 'utf8') + let name = file.replace('.json', '') + if (type === 'models') { + name = `block/${name}` + } + if (namespaceDir !== 'minecraft') { + name = `${namespaceDir}:${name}` + } + jsons[name] = JSON.parse(contents) + } + })) + return jsons + } + viewer.world.customBlockStates = await getAllJson(blockstatesPath, 'blockstates') + viewer.world.customModels = await getAllJson(modelsPath, 'models') + } + try { + const assetsDirs = await fs.promises.readdir(join(basePath, 'assets')) + for (const assetsDir of assetsDirs) { + await readData(assetsDir) + } + } catch (err) { + console.error('Failed to read some of resource pack blockstates and models', err) + viewer.world.customBlockStates = undefined + viewer.world.customModels = undefined + } +} + +const downloadAndUseResourcePack = async (url) => { + console.log('downloadAndUseResourcePack', url) +} + +export const onAppLoad = () => { + customEvents.on('gameLoaded', () => { + // todo also handle resourcePack + bot._client.on('resource_pack_send', async (packet) => { + if (options.serverResourcePacks === 'never') return + const promptMessage = 'promptMessage' in packet ? JSON.stringify(packet.promptMessage) : 'Do you want to use server resource pack?' + // TODO! + const hash = 'hash' in packet ? packet.hash : '-' + const forced = 'forced' in packet ? packet.forced : false + const choice = options.serverResourcePacks === 'always' + ? true + : await showOptionsModal(promptMessage, ['Download & Install'], { + cancel: !forced + }) + if (!choice) return + await downloadAndUseResourcePack(packet.url) + bot.acceptResourcePack() + }) + }) +} + +const setOtherTexturesCss = async () => { + const basePath = await getActiveTexturepackBasePath() + // TODO! fallback to default + const setCustomCss = async (path: string | null, varName: string, repeat = 1) => { + if (path && await existsAsync(path)) { + const contents = await fs.promises.readFile(path, 'base64') + const dataUrl = `data:image/png;base64,${contents}` + document.body.style.setProperty(varName, repeatArr(`url(${dataUrl})`, repeat).join(', ')) + } else { + document.body.style.setProperty(varName, '') + } + } + const vars = Object.values(appReplacableResources).filter(x => x.cssVar) + for (const { cssVar, cssVarRepeat, resourcePackPath } of vars) { + // eslint-disable-next-line no-await-in-loop + await setCustomCss(`${basePath}/assets/${resourcePackPath}`, cssVar!, cssVarRepeat ?? 1) + } +} + +const repeatArr = (arr, i) => Array.from({ length: i }, () => arr) + +const updateTextures = async () => { + const blocksFiles = Object.keys(viewer.world.blocksAtlases.latest.textures) + const itemsFiles = Object.keys(viewer.world.itemsAtlases.latest.textures) + const blocksData = await getResourcepackTiles('blocks', blocksFiles) + const itemsData = await getResourcepackTiles('items', itemsFiles) + await setOtherTexturesCss() + await prepareBlockstatesAndModels() + viewer.world.customTextures = {} + if (blocksData) { + viewer.world.customTextures.blocks = { + tileSize: blocksData.firstTextureSize, + textures: blocksData.textures + } + } + if (itemsData) { + viewer.world.customTextures.items = { + tileSize: itemsData.firstTextureSize, + textures: itemsData.textures + } + } + if (viewer.world.active) { + await viewer.world.updateTexturesData() + } +} + +export const resourcepackOnWorldLoad = async (version) => { + await updateTextures() +} diff --git a/src/resourcesSource.ts b/src/resourcesSource.ts new file mode 100644 index 000000000..3ca9eeb58 --- /dev/null +++ b/src/resourcesSource.ts @@ -0,0 +1,23 @@ +export const appReplacableResources: Array<{ + path: string + cssVar?: string + cssVarRepeat?: number +}> = [ + { + path: '../node_modules/mc-assets/dist/other-textures/latest/gui/title/minecraft.png', + cssVar: '--title-gui', + }, + { + path: '../node_modules/mc-assets/dist/other-textures/1.19/gui/icons.png', + cssVar: '--gui-icons', + cssVarRepeat: 2, + }, + { + path: '../node_modules/mc-assets/dist/other-textures/latest/gui/widgets.png', + cssVar: '--widgets-gui-atlas', + }, + { + path: '../node_modules/mc-assets/dist/other-textures/latest/gui/bars.png', + cssVar: '--bars-gui-atlas', + } +] \ No newline at end of file diff --git a/src/serviceWorker.ts b/src/serviceWorker.ts index cbb7a42af..c64ba0f68 100644 --- a/src/serviceWorker.ts +++ b/src/serviceWorker.ts @@ -1,13 +1,17 @@ import { isCypress } from './standaloneUtils' +// might not resolve at all export const registerServiceWorker = async () => { if (!('serviceWorker' in navigator)) return if (!isCypress() && process.env.NODE_ENV !== 'development') { - window.addEventListener('load', () => { - navigator.serviceWorker.register('./service-worker.js').then(registration => { - console.log('SW registered:', registration) - }).catch(registrationError => { - console.log('SW registration failed:', registrationError) + return new Promise(resolve => { + window.addEventListener('load', async () => { + await navigator.serviceWorker.register('./service-worker.js').then(registration => { + console.log('SW registered:', registration) + resolve() + }).catch(registrationError => { + console.log('SW registration failed:', registrationError) + }) }) }) } else { diff --git a/src/shims.js b/src/shims.js deleted file mode 100644 index 3a4cf7b68..000000000 --- a/src/shims.js +++ /dev/null @@ -1,3 +0,0 @@ -const BrowserFS = require('browserfs') - -export { BrowserFS } diff --git a/src/crypto.js b/src/shims/crypto.js similarity index 100% rename from src/crypto.js rename to src/shims/crypto.js diff --git a/src/dns.js b/src/shims/dns.js similarity index 100% rename from src/dns.js rename to src/shims/dns.js diff --git a/src/shims/empty.ts b/src/shims/empty.ts new file mode 100644 index 000000000..f0a766d36 --- /dev/null +++ b/src/shims/empty.ts @@ -0,0 +1 @@ +export { } diff --git a/src/shims/fs.js b/src/shims/fs.js new file mode 100644 index 000000000..b238a3760 --- /dev/null +++ b/src/shims/fs.js @@ -0,0 +1,3 @@ +const BrowserFS = require('browserfs') + +module.exports = BrowserFS.BFSRequire('fs') diff --git a/src/perf_hooks_replacement.js b/src/shims/perf_hooks_replacement.js similarity index 100% rename from src/perf_hooks_replacement.js rename to src/shims/perf_hooks_replacement.js diff --git a/src/yggdrasilReplacement.ts b/src/shims/yggdrasilReplacement.ts similarity index 100% rename from src/yggdrasilReplacement.ts rename to src/shims/yggdrasilReplacement.ts diff --git a/src/styles.css b/src/styles.css index f924a0c6a..9b3fdd3ab 100644 --- a/src/styles.css +++ b/src/styles.css @@ -30,11 +30,7 @@ html { color: white; } -body { - --title-gui: url('minecraft-assets/minecraft-assets/data/1.17.1/gui/title/minecraft.png'); -} - -body.disable-assets { +html.disable-assets { --widgets-gui-atlas: none; --title-gui: none; } @@ -80,7 +76,7 @@ body { position: absolute; top: 0; left: 0; - background: url('minecraft-assets/minecraft-assets/data/1.17.1/gui/options_background.png'), rgba(0, 0, 0, 0.7); + background: url('mc-assets/dist/other-textures/latest/gui/options_background.png'), rgba(0, 0, 0, 0.7); background-size: 16px; background-repeat: repeat; width: 100%; @@ -115,12 +111,12 @@ body { @font-face { font-family: minecraft; - src: url(minecraftia.woff); + src: url(../assets/minecraftia.woff); } @font-face { font-family: mojangles; - src: url(mojangles.ttf); + src: url(../assets/mojangles.ttf); } #ui-root { diff --git a/src/texturePack.ts b/src/texturePack.ts deleted file mode 100644 index 566e10dab..000000000 --- a/src/texturePack.ts +++ /dev/null @@ -1,278 +0,0 @@ -import { join, dirname } from 'path' -import fs from 'fs' -import JSZip from 'jszip' -import type { Viewer } from 'prismarine-viewer/viewer/lib/viewer' -import { subscribeKey } from 'valtio/utils' -import { proxy, ref } from 'valtio' -import { getVersion } from 'prismarine-viewer/viewer/lib/version' -import blocksFileNames from '../generated/blocks.json' -import type { BlockStates } from './inventoryWindows' -import { copyFilesAsync, copyFilesAsyncWithProgress, mkdirRecursive, removeFileRecursiveAsync } from './browserfs' -import { setLoadingScreenStatus } from './utils' -import { showNotification } from './react/NotificationProvider' - -export const resourcePackState = proxy({ - resourcePackInstalled: false, - currentTexturesDataUrl: undefined as string | undefined, - currentTexturesBlockStates: undefined as BlockStates | undefined, -}) - -function nextPowerOfTwo (n) { - if (n === 0) return 1 - n-- - n |= n >> 1 - n |= n >> 2 - n |= n >> 4 - n |= n >> 8 - n |= n >> 16 - return n + 1 -} - -const texturePackBasePath = '/data/resourcePacks/default' -export const uninstallTexturePack = async () => { - await removeFileRecursiveAsync(texturePackBasePath) - setCustomTexturePackData(undefined, undefined) -} - -export const getResourcePackName = async () => { - // temp - try { - return await fs.promises.readFile(join(texturePackBasePath, 'name.txt'), 'utf8') - } catch (err) { - return '???' - } -} - -export const fromTexturePackPath = (path) => { - return join(texturePackBasePath, path) -} - -export const updateTexturePackInstalledState = async () => { - try { - resourcePackState.resourcePackInstalled = await existsAsync(texturePackBasePath) - } catch { - } -} - -export const installTexturePackFromHandle = async () => { - await mkdirRecursive(texturePackBasePath) - await copyFilesAsyncWithProgress('/world', texturePackBasePath) - await completeTexturePackInstall() -} - -export const installTexturePack = async (file: File | ArrayBuffer, name = file['name']) => { - try { - await uninstallTexturePack() - } catch (err) { - } - 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() - const zipFile = await zip.loadAsync(file) - 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 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'))) - done++ - upStatus() - })) - await completeTexturePackInstall(name) -} - -export const completeTexturePackInstall = async (name?: string) => { - await fs.promises.writeFile(join(texturePackBasePath, 'name.txt'), name ?? '??', 'utf8') - - if (viewer?.world.active) { - await genTexturePackTextures(viewer.world.version!) - } - setLoadingScreenStatus(undefined) - showNotification('Texturepack installed') - await updateTexturePackInstalledState() -} - -const existsAsync = async (path) => { - try { - await fs.promises.stat(path) - return true - } catch (err) { - return false - } -} - -type TextureResolvedData = { - blockSize: number - // itemsUrlContent: string -} - -const arrEqual = (a: any[], b: any[]) => a.length === b.length && a.every((x) => b.includes(x)) - -const applyTexturePackData = async (version: string, { blockSize }: TextureResolvedData, blocksUrlContent: string) => { - const result = await fetch(`blocksStates/${getVersion(version)}.json`) - const blockStates: BlockStates = await result.json() - const factor = blockSize / 16 - - // this will be refactored with generateTextures refactor - const processObj = (x) => { - if (typeof x !== 'object' || !x) return - if (Array.isArray(x)) { - for (const v of x) { - processObj(v) - } - - } else { - const actual = Object.keys(x) - const needed = ['u', 'v', 'su', 'sv'] - - if (!arrEqual(actual, needed)) { - for (const v of Object.values(x)) { - processObj(v) - } - return - } - for (const k of needed) { - x[k] *= factor - } - } - } - processObj(blockStates) - setCustomTexturePackData(blocksUrlContent, blockStates) -} - -const setCustomTexturePackData = (blockTextures, blockStates) => { - resourcePackState.currentTexturesBlockStates = blockStates && ref(blockStates) - resourcePackState.currentTexturesDataUrl = blockTextures - resourcePackState.resourcePackInstalled = blockTextures !== undefined -} - -const getSizeFromImage = async (filePath: string) => { - const probeImg = new Image() - const file = await fs.promises.readFile(filePath, 'base64') - probeImg.src = `data:image/png;base64,${file}` - await new Promise((resolve, reject) => { - probeImg.addEventListener('load', resolve) - }) - if (probeImg.width !== probeImg.height) throw new Error(`Probe texture ${filePath} is not square`) - return probeImg.width -} - -export const genTexturePackTextures = async (version: string) => { - setCustomTexturePackData(undefined, undefined) - let blocksBasePath = '/data/resourcePacks/default/assets/minecraft/textures/block' - // todo not clear why this is needed - const blocksBasePathAlt = '/data/resourcePacks/default/assets/minecraft/textures/blocks' - const blocksGeneratedPath = `/data/resourcePacks/default/${version}.png` - const generatedPathData = `/data/resourcePacks/default/${version}.json` - if (!(await existsAsync(blocksBasePath))) { - if (await existsAsync(blocksBasePathAlt)) { - blocksBasePath = blocksBasePathAlt - } else { - return - } - } - if (await existsAsync(blocksGeneratedPath)) { - // make sure we await it, so we set properties in world renderer and it won't try to load default textures - await applyTexturePackData(version, JSON.parse(await fs.promises.readFile(generatedPathData, 'utf8')), await fs.promises.readFile(blocksGeneratedPath, 'utf8')) - return - } - - setLoadingScreenStatus('Generating custom textures') - - const textureFiles = blocksFileNames.indexes[version].map(k => blocksFileNames.blockNames[k]) - textureFiles.unshift('missing_texture.png') - - const texSize = nextPowerOfTwo(Math.ceil(Math.sqrt(textureFiles.length))) - const originalTileSize = 16 - - const firstBlockFile = (await fs.promises.readdir(blocksBasePath)).find(f => f.endsWith('.png')) - if (!firstBlockFile) { - return - } - - // we get the size of image from the first block file, which is not ideal but works in 99% cases - const tileSize = Math.max(originalTileSize, await getSizeFromImage(join(blocksBasePath, firstBlockFile))) - - const imgSize = texSize * tileSize - - const MAX_CANVAS_SIZE = 16_384 - if (imgSize > MAX_CANVAS_SIZE) { - throw new Error(`Texture pack texture resolution is too big, max size is ${MAX_CANVAS_SIZE}x${MAX_CANVAS_SIZE}`) - // texSize = nextPowerOfTwo(Math.ceil(Math.sqrt(textureFiles.length / 2))) - } - const canvas = document.createElement('canvas') - canvas.width = imgSize - canvas.height = imgSize - const src = `textures/${getVersion(version)}.png` - const ctx = canvas.getContext('2d')! - ctx.imageSmoothingEnabled = false - const img = new Image() - img.src = src - await new Promise((resolve, reject) => { - img.onerror = reject - img.addEventListener('load', resolve) - }) - for (const [i, fileName] of textureFiles.entries()) { - const x = (i % texSize) * tileSize - const y = Math.floor(i / texSize) * tileSize - const xOrig = (i % texSize) * originalTileSize - const yOrig = Math.floor(i / texSize) * originalTileSize - let imgCustom!: HTMLImageElement - try { - const fileBase64 = await fs.promises.readFile(join(blocksBasePath, fileName), 'base64') - const _imgCustom = new Image() - // I think it can crash otherwise - // eslint-disable-next-line no-await-in-loop - await new Promise(resolve => { - _imgCustom.addEventListener('load', () => { - imgCustom = _imgCustom - resolve() - }) - _imgCustom.onerror = () => { - console.log('Skipping issued texture', fileName) - resolve() - } - _imgCustom.src = `data:image/png;base64,${fileBase64}` - }) - } catch { - console.log('Skipping not found texture', fileName) - } - - if (imgCustom) { - ctx.drawImage(imgCustom, x, y, tileSize, tileSize) - } else { - // todo this involves incorrect mappings for existing textures when the size is different - ctx.drawImage(img, xOrig, yOrig, originalTileSize, originalTileSize, x, y, tileSize, tileSize) - } - } - const blockDataUrl = canvas.toDataURL('image/png') - const newData: TextureResolvedData = { - blockSize: tileSize, - } - await fs.promises.writeFile(generatedPathData, JSON.stringify(newData), 'utf8') - await fs.promises.writeFile(blocksGeneratedPath, blockDataUrl, 'utf8') - await applyTexturePackData(version, newData, blockDataUrl) - - // const a = document.createElement('a') - // a.href = dataUrl - // a.download = 'pack.png' - // a.click() -} - -export const watchTexturepackInViewer = (viewer: Viewer) => { - subscribeKey(resourcePackState, 'currentTexturesDataUrl', () => { - console.log('applying resourcepack world data') - viewer.world.customTexturesDataUrl = resourcePackState.currentTexturesDataUrl - viewer.world.customBlockStatesData = resourcePackState.currentTexturesBlockStates - if (!viewer?.world.active) return - viewer.world.updateTexturesData() - }) -} diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 6d517ac24..ffb5fa4a0 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -3,20 +3,20 @@ import * as THREE from 'three' // wouldn't better to create atlas instead? -import destroyStage0 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/destroy_stage_0.png' -import destroyStage1 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/destroy_stage_1.png' -import destroyStage2 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/destroy_stage_2.png' -import destroyStage3 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/destroy_stage_3.png' -import destroyStage4 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/destroy_stage_4.png' -import destroyStage5 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/destroy_stage_5.png' -import destroyStage6 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/destroy_stage_6.png' -import destroyStage7 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/destroy_stage_7.png' -import destroyStage8 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/destroy_stage_8.png' -import destroyStage9 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/destroy_stage_9.png' - import { Vec3 } from 'vec3' import { LineMaterial, Wireframe, LineSegmentsGeometry } from 'three-stdlib' import { Entity } from 'prismarine-entity' +import destroyStage0 from '../assets/destroy_stage_0.png' +import destroyStage1 from '../assets/destroy_stage_1.png' +import destroyStage2 from '../assets/destroy_stage_2.png' +import destroyStage3 from '../assets/destroy_stage_3.png' +import destroyStage4 from '../assets/destroy_stage_4.png' +import destroyStage5 from '../assets/destroy_stage_5.png' +import destroyStage6 from '../assets/destroy_stage_6.png' +import destroyStage7 from '../assets/destroy_stage_7.png' +import destroyStage8 from '../assets/destroy_stage_8.png' +import destroyStage9 from '../assets/destroy_stage_9.png' + import { hideCurrentModal, isGameActive, showModal } from './globalState' import { assertDefined } from './utils' import { options } from './optionsStorage' @@ -291,7 +291,10 @@ class WorldInteraction { } else if (!stop) { const offhand = activate ? false : activatableItems(bot.inventory.slots[45]?.name ?? '') bot.activateItem(offhand) // todo offhand - customEvents.emit('activateItem', offhand ? bot.inventory.slots[45] : bot.heldItem, offhand ? 45 : bot.quickBarSlot, offhand) + const item = offhand ? bot.inventory.slots[45] : bot.heldItem + if (item) { + customEvents.emit('activateItem', item, offhand ? 45 : bot.quickBarSlot, offhand) + } itemBeingUsed.name = (offhand ? bot.inventory.slots[45]?.name : bot.heldItem?.name) ?? null itemBeingUsed.hand = offhand ? 1 : 0 } diff --git a/tsconfig.json b/tsconfig.json index 454e60cb7..8ecff3bd6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,7 @@ // this the only options that allows smooth transition from js to ts (by not dropping types from js files) // however might need to consider includeing *only needed libraries* instead of using this "maxNodeModuleJsDepth": 1, - "strictNullChecks": true + "strictNullChecks": true, }, "include": [ "src",