diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ca74a57d3..6c66309eb 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -25,10 +25,20 @@ }, }, { - "label": "viewer server+esbuild", + "label": "webgl-worker", + "type": "shell", + "command": "node buildWorkers.mjs -w", + "problemMatcher": "$esbuild-watch", + "presentation": { + "reveal": "silent" + }, + }, + { + "label": "viewer server+esbuild+workers", "dependsOn": [ "viewer-server", - "viewer-esbuild" + "viewer-esbuild", + "webgl-worker" ], "dependsOrder": "parallel", } diff --git a/buildWorkers.mjs b/buildWorkers.mjs new file mode 100644 index 000000000..24e986309 --- /dev/null +++ b/buildWorkers.mjs @@ -0,0 +1,61 @@ +// main worker file intended for computing world geometry is built using prismarine-viewer/buildWorker.mjs +import { build, context } from 'esbuild' +import fs from 'fs' +import path from 'path' + +const watch = process.argv.includes('-w') + +const result = await (watch ? context : build)({ + bundle: true, + platform: 'browser', + entryPoints: ['prismarine-viewer/examples/webglRendererWorker.ts'], + outdir: 'prismarine-viewer/public/', + sourcemap: watch ? 'inline' : 'external', + minify: !watch, + treeShaking: true, + logLevel: 'info', + alias: { + 'three': './node_modules/three/src/Three.js', + events: 'events', // make explicit + buffer: 'buffer', + 'fs': 'browserfs/dist/shims/fs.js', + http: 'http-browserify', + perf_hooks: './src/perf_hooks_replacement.js', + crypto: './src/crypto.js', + stream: 'stream-browserify', + net: 'net-browserify', + assert: 'assert', + dns: './src/dns.js' + }, + inject: [ + './src/shims.js' + ], + plugins: [ + { + name: 'writeOutput', + setup (build) { + build.onEnd(({ outputFiles }) => { + for (const file of outputFiles) { + for (const dir of ['prismarine-viewer/public', 'dist']) { + const baseName = path.basename(file.path) + fs.writeFileSync(path.join(dir, baseName), file.contents) + } + } + }) + } + } + ], + loader: { + '.vert': 'text', + '.frag': 'text' + }, + mainFields: [ + 'browser', 'module', 'main' + ], + keepNames: true, + write: false, +}) + +if (watch) { + await result.watch() +} diff --git a/cypress/e2e/index.spec.ts b/cypress/e2e/index.spec.ts index 8b168bf12..e9d97ab06 100644 --- a/cypress/e2e/index.spec.ts +++ b/cypress/e2e/index.spec.ts @@ -1,15 +1,5 @@ /// -import type { AppOptions } from '../../src/optionsStorage' - -const cleanVisit = (url?) => { - cy.clearLocalStorage() - visit(url) -} - -const visit = (url = '/') => { - window.localStorage.cypress = 'true' - cy.visit(url) -} +import { setOptions, cleanVisit, visit } from './shared' // todo use ssl @@ -31,12 +21,6 @@ const testWorldLoad = () => { }) } -const setOptions = (options: Partial) => { - cy.window().then(win => { - Object.assign(win['options'], options) - }) -} - it('Loads & renders singleplayer', () => { cleanVisit('/?singleplayer=1') setOptions({ diff --git a/cypress/e2e/performance.spec.ts b/cypress/e2e/performance.spec.ts new file mode 100644 index 000000000..f2fc4d46e --- /dev/null +++ b/cypress/e2e/performance.spec.ts @@ -0,0 +1,25 @@ +import { cleanVisit, setOptions } from './shared' + +it('Loads & renders singleplayer', () => { + cleanVisit('/?singleplayer=1') + setOptions({ + renderDistance: 2 + }) + // wait for .initial-loader to disappear + cy.get('.initial-loader', { timeout: 20_000 }).should('not.exist') + cy.window() + .its('performance') + .invoke('mark', 'worldLoad') + + cy.document().then({ timeout: 20_000 }, doc => { + return new Cypress.Promise(resolve => { + doc.addEventListener('cypress-world-ready', resolve) + }) + }).then(() => { + const duration = cy.window() + .its('performance') + .invoke('measure', 'modalOpen') + .its('duration') + cy.log('Duration', duration) + }) +}) diff --git a/cypress/e2e/shared.ts b/cypress/e2e/shared.ts new file mode 100644 index 000000000..9292a8d55 --- /dev/null +++ b/cypress/e2e/shared.ts @@ -0,0 +1,15 @@ +import { AppOptions } from '../../src/optionsStorage' + +export const cleanVisit = (url?) => { + cy.clearLocalStorage() + visit(url) +} +export const visit = (url = '/') => { + window.localStorage.cypress = 'true' + cy.visit(url) +} +export const setOptions = (options: Partial) => { + cy.window().then(win => { + Object.assign(win['options'], options) + }) +} diff --git a/esbuild.mjs b/esbuild.mjs index 2d18ae3a0..6f7f903ee 100644 --- a/esbuild.mjs +++ b/esbuild.mjs @@ -11,7 +11,9 @@ import { build } from 'esbuild' //@ts-ignore try { await import('./localSettings.mjs') } catch { } -fs.writeFileSync('dist/index.html', fs.readFileSync('index.html', 'utf8').replace('', ''), 'utf8') +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') @@ -30,7 +32,7 @@ const buildingVersion = new Date().toISOString().split(':')[0] /** @type {import('esbuild').BuildOptions} */ const buildOptions = { bundle: true, - entryPoints: ['src/index.ts'], + entryPoints: [`src/${entrypoint}`], target: ['es2020'], jsx: 'automatic', jsxDev: dev, @@ -76,7 +78,9 @@ const buildOptions = { loader: { // todo use external or resolve issues with duplicating '.png': 'dataurl', - '.map': 'empty' + '.map': 'empty', + '.vert': 'text', + '.frag': 'text' }, write: false, // todo would be better to enable? diff --git a/experiments/texture-render.html b/experiments/texture-render.html index be406102a..2a2716bde 100644 --- a/experiments/texture-render.html +++ b/experiments/texture-render.html @@ -10,8 +10,8 @@ diff --git a/package.json b/package.json index 881be9cc6..04cf44adb 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,10 @@ "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", + "build": "node scripts/build.js copyFiles && node scripts/prepareData.mjs -f && node esbuild.mjs --minify --prod && node buildWorkers.mjs", "check-build": "tsc && pnpm test-unit && pnpm build", "test:cypress": "cypress run", + "test:cypress:perf": "cypress run --spec cypress/e2e/perf.spec.ts --browser edge", "test-unit": "vitest", "test:e2e": "start-test http-get://localhost:8080 test:cypress", "prod-start": "node server.js", @@ -17,7 +18,12 @@ "storybook": "storybook dev -p 6006", "build-storybook": "storybook build && node scripts/build.js moveStorybookFiles", "start-experiments": "vite --config experiments/vite.config.ts", - "watch-worker": "node prismarine-viewer/buildWorker.mjs -w" + "watch-worker": "node prismarine-viewer/buildWorker.mjs -w", + "watch-other-workers": "node buildWorkers.mjs -w", + "run-playground": "run-p watch-worker watch-other-workers playground-server watch-playground", + "run-all": "run-p start run-playground", + "playground-server": "live-server --port=9090 prismarine-viewer/public", + "watch-playground": "node prismarine-viewer/esbuild.mjs -w" }, "keywords": [ "prismarine", @@ -56,6 +62,7 @@ "jszip": "^3.10.1", "lit": "^2.8.0", "lodash-es": "^4.17.21", + "math.gl": "^4.0.0", "minecraft-assets": "^1.12.2", "minecraft-data": "3.62.0", "net-browserify": "github:zardoy/prismarinejs-net-browserify", @@ -79,6 +86,7 @@ "stats.js": "^0.17.0", "tabbable": "^6.2.0", "title-case": "3.x", + "twgl.js": "^5.5.4", "ua-parser-js": "^1.0.37", "valtio": "^1.11.1", "workbox-build": "^7.0.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 483f0277f..81363a742 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -105,6 +105,9 @@ importers: lodash-es: specifier: ^4.17.21 version: 4.17.21 + math.gl: + specifier: ^4.0.0 + version: 4.0.1 minecraft-assets: specifier: ^1.12.2 version: 1.12.2 @@ -174,6 +177,9 @@ importers: title-case: specifier: 3.x version: 3.0.3 + twgl.js: + specifier: ^5.5.4 + version: 5.5.4 ua-parser-js: specifier: ^1.0.37 version: 1.0.37 @@ -350,6 +356,9 @@ importers: lil-gui: specifier: ^0.18.2 version: 0.18.2 + live-server: + specifier: ^1.2.2 + version: 1.2.2 looks-same: specifier: ^8.2.3 version: 8.2.3 @@ -3220,6 +3229,16 @@ packages: - supports-color dev: false + /@math.gl/core@4.0.1: + resolution: {integrity: sha512-9IewNjR9V66o+gYIIq5agFoHy6ZT6DRpRGQBfsUpZz4glAqOjVt64he8GGzjpmqfT+kKT4qwQ7nQl/hZLF15qA==} + dependencies: + '@math.gl/types': 4.0.1 + dev: false + + /@math.gl/types@4.0.1: + resolution: {integrity: sha512-E9qBKAjVBiZD8Is7TbygiLGtYBP3GSLus6RUJSuzFQegdYXeVagvrs4UkBJxhrRAxw4crfH0Tq7IhTMKuuJNQw==} + dev: false + /@mdx-js/react@2.3.0(react@18.2.0): resolution: {integrity: sha512-zQH//gdOmuu7nt2oJR29vFhDv88oGPmVw6BggmrHeMI+xgEkp1B2dX9/bMBSYtK0dyLX/aOmesKS09g222K1/g==} peerDependencies: @@ -5718,7 +5737,7 @@ packages: prismarine-nbt: 2.5.0 prismarine-provider-anvil: github.com/zardoy/prismarine-provider-anvil/0ddcd9d48574113308e1fbebef60816aced0846f(minecraft-data@3.62.0) prismarine-windows: 2.9.0 - prismarine-world: github.com/zardoy/prismarine-world/c358222204d21fe7d45379fbfcefb047f926c786 + prismarine-world: github.com/zardoy/prismarine-world/6ae6f009d38460de284f8c226c665f04cbad9465 random-seed: 0.3.0 range: 0.0.3 readline: 1.3.0 @@ -5933,6 +5952,15 @@ packages: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} dev: false + /anymatch@2.0.0: + resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==} + dependencies: + micromatch: 3.1.10 + normalize-path: 2.1.1 + transitivePeerDependencies: + - supports-color + dev: false + /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -5941,6 +5969,18 @@ packages: picomatch: 2.3.1 dev: true + /apache-crypt@1.2.6: + resolution: {integrity: sha512-072WetlM4blL8PREJVeY+WHiUh1R5VNt2HfceGS8aKqttPHcmqE5pkKuXPz/ULmJOFkc8Hw3kfKl6vy7Qka6DA==} + engines: {node: '>=8'} + dependencies: + unix-crypt-td-js: 1.1.4 + dev: false + + /apache-md5@1.1.8: + resolution: {integrity: sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA==} + engines: {node: '>=8'} + dev: false + /app-root-dir@1.0.2: resolution: {integrity: sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==} dev: true @@ -5986,6 +6026,21 @@ packages: tslib: 2.6.2 dev: true + /arr-diff@4.0.0: + resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} + engines: {node: '>=0.10.0'} + dev: false + + /arr-flatten@1.1.0: + resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} + engines: {node: '>=0.10.0'} + dev: false + + /arr-union@3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + dev: false + /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: @@ -6019,6 +6074,11 @@ packages: engines: {node: '>=8'} dev: true + /array-unique@0.3.2: + resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} + engines: {node: '>=0.10.0'} + dev: false + /array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} @@ -6121,6 +6181,11 @@ packages: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} dev: true + /assign-symbols@1.0.0: + resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} + engines: {node: '>=0.10.0'} + dev: false + /ast-types@0.14.2: resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} engines: {node: '>=4'} @@ -6146,6 +6211,10 @@ packages: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} + /async-each@1.0.6: + resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==} + dev: false + /async-limiter@1.0.1: resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} @@ -6170,6 +6239,12 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} + /atob@2.1.2: + resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} + engines: {node: '>= 4.5.0'} + hasBin: true + dev: false + /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} @@ -6279,18 +6354,38 @@ packages: engines: {node: ^4.5.0 || >= 5.9} dev: false + /base@0.11.2: + resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} + engines: {node: '>=0.10.0'} + dependencies: + cache-base: 1.0.1 + class-utils: 0.3.6 + component-emitter: 1.3.0 + define-property: 1.0.0 + isobject: 3.0.1 + mixin-deep: 1.3.2 + pascalcase: 0.1.1 + dev: false + /basic-auth@2.0.1: resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} engines: {node: '>= 0.8'} dependencies: safe-buffer: 5.1.2 - dev: true + + /batch@0.6.1: + resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} + dev: false /bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} dependencies: tweetnacl: 0.14.5 + /bcryptjs@2.4.3: + resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} + dev: false + /better-opn@3.0.2: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} @@ -6303,6 +6398,11 @@ packages: engines: {node: '>=0.6'} dev: true + /binary-extensions@1.13.1: + resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} + engines: {node: '>=0.10.0'} + dev: false + /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -6412,6 +6512,24 @@ packages: dependencies: balanced-match: 1.0.2 + /braces@2.3.2: + resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} + engines: {node: '>=0.10.0'} + dependencies: + arr-flatten: 1.1.0 + array-unique: 0.3.2 + extend-shallow: 2.0.1 + fill-range: 4.0.0 + isobject: 3.0.1 + repeat-element: 1.1.4 + snapdragon: 0.8.2 + snapdragon-node: 2.1.1 + split-string: 3.1.0 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + dev: false + /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} @@ -6602,6 +6720,21 @@ packages: dev: false optional: true + /cache-base@1.0.1: + resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} + engines: {node: '>=0.10.0'} + dependencies: + collection-visit: 1.0.0 + component-emitter: 1.3.0 + get-value: 2.0.6 + has-value: 1.0.0 + isobject: 3.0.1 + set-value: 2.0.1 + to-object-path: 0.3.0 + union-value: 1.0.1 + unset-value: 1.0.0 + dev: false + /cachedir@2.4.0: resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==} engines: {node: '>=6'} @@ -6765,6 +6898,27 @@ packages: resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} engines: {node: '>= 0.8.0'} + /chokidar@2.1.8: + resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} + deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies + dependencies: + anymatch: 2.0.0 + async-each: 1.0.6 + braces: 2.3.2 + glob-parent: 3.1.0 + inherits: 2.0.4 + is-binary-path: 1.0.1 + is-glob: 4.0.3 + normalize-path: 3.0.0 + path-is-absolute: 1.0.1 + readdirp: 2.2.1 + upath: 1.2.0 + optionalDependencies: + fsevents: 1.2.13 + transitivePeerDependencies: + - supports-color + dev: false + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -6798,6 +6952,16 @@ packages: safe-buffer: 5.2.1 dev: true + /class-utils@0.3.6: + resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} + engines: {node: '>=0.10.0'} + dependencies: + arr-union: 3.1.0 + define-property: 0.2.5 + isobject: 3.0.1 + static-extend: 0.1.2 + dev: false + /classnames@2.3.2: resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} dev: false @@ -6880,6 +7044,14 @@ packages: engines: {node: '>=6'} dev: false + /collection-visit@1.0.0: + resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} + engines: {node: '>=0.10.0'} + dependencies: + map-visit: 1.0.0 + object-visit: 1.0.1 + dev: false + /color-convert@0.5.3: resolution: {integrity: sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling==} dev: false @@ -7012,6 +7184,18 @@ packages: resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} dev: true + /connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: false + /console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} dev: false @@ -7069,6 +7253,11 @@ packages: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} + /copy-descriptor@0.1.1: + resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} + engines: {node: '>=0.10.0'} + dev: false + /copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} dependencies: @@ -7392,6 +7581,11 @@ packages: character-entities: 2.0.2 dev: false + /decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + dev: false + /decompress-response@4.2.1: resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==} engines: {node: '>=8'} @@ -7471,6 +7665,28 @@ packages: has-property-descriptors: 1.0.0 object-keys: 1.1.1 + /define-property@0.2.5: + resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} + engines: {node: '>=0.10.0'} + dependencies: + is-descriptor: 0.1.7 + dev: false + + /define-property@1.0.0: + resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} + engines: {node: '>=0.10.0'} + dependencies: + is-descriptor: 1.0.3 + dev: false + + /define-property@2.0.2: + resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} + engines: {node: '>=0.10.0'} + dependencies: + is-descriptor: 1.0.3 + isobject: 3.0.1 + dev: false + /defu@6.1.2: resolution: {integrity: sha512-+uO4+qr7msjNNWKYPHqN/3+Dx3NFkmIzayk2L1MyZQlvgZb/J1A0fo410dpKrN2SnqFjt8n4JL8fDJE0wIgjFQ==} dev: true @@ -7497,6 +7713,11 @@ packages: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} dev: false + /depd@1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + dev: false + /depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -7685,6 +7906,10 @@ packages: resolution: {integrity: sha512-+3NaRjWktb5r61ZFoDejlykPEFKT5N/LkbXsaddlw6xNSXBanUYpFc2AXXpbJDilPHazcSreU/DpQIaxfX0NfQ==} dev: false + /duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + dev: false + /duplexify@3.7.1: resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} dependencies: @@ -8616,6 +8841,18 @@ packages: promise: 5.0.0 dev: false + /event-stream@3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + dev: false + /event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -8681,6 +8918,21 @@ packages: engines: {node: '>=6'} dev: false + /expand-brackets@2.1.4: + resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} + engines: {node: '>=0.10.0'} + dependencies: + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + posix-character-classes: 0.1.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + dev: false + /expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} @@ -8744,9 +8996,40 @@ packages: transitivePeerDependencies: - supports-color + /extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + dependencies: + is-extendable: 0.1.1 + dev: false + + /extend-shallow@3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + dependencies: + assign-symbols: 1.0.0 + is-extendable: 1.0.1 + dev: false + /extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + /extglob@2.0.4: + resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} + engines: {node: '>=0.10.0'} + dependencies: + array-unique: 0.3.2 + define-property: 1.0.0 + expand-brackets: 2.1.4 + extend-shallow: 2.0.1 + fragment-cache: 0.2.1 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + dev: false + /extract-zip@1.7.0: resolution: {integrity: sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==} hasBin: true @@ -8815,6 +9098,13 @@ packages: reusify: 1.0.4 dev: true + /faye-websocket@0.11.4: + resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} + engines: {node: '>=0.8.0'} + dependencies: + websocket-driver: 0.7.4 + dev: false + /fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} dependencies: @@ -8873,6 +9163,16 @@ packages: resolution: {integrity: sha512-6RS9gDchbn+qWmtV2uSjo5vmKizgfCQeb5jKmqx8HyzA3MoLqqyQxN+QcjkGBJt7FjJ9qFce67Auyya5rRRbpw==} engines: {node: '>= 10.4.0'} + /fill-range@4.0.0: + resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 2.0.1 + is-number: 3.0.0 + repeat-string: 1.6.1 + to-regex-range: 2.1.1 + dev: false + /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -8880,6 +9180,21 @@ packages: to-regex-range: 5.0.1 dev: true + /finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + /finalhandler@1.2.0: resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} engines: {node: '>= 0.8'} @@ -8989,6 +9304,11 @@ packages: dependencies: is-callable: 1.2.7 + /for-in@1.0.2: + resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} + engines: {node: '>=0.10.0'} + dev: false + /foreground-child@2.0.0: resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} engines: {node: '>=8.0.0'} @@ -9029,10 +9349,21 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} + /fragment-cache@0.2.1: + resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} + engines: {node: '>=0.10.0'} + dependencies: + map-cache: 0.2.2 + dev: false + /fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + /from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + dev: false + /fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -9080,6 +9411,18 @@ packages: /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + /fsevents@1.2.13: + resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} + engines: {node: '>= 4.0'} + os: [darwin] + deprecated: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2 + requiresBuild: true + dependencies: + bindings: 1.5.0 + nan: 2.18.0 + dev: false + optional: true + /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -9223,6 +9566,11 @@ packages: resolve-pkg-maps: 1.0.0 dev: false + /get-value@2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} + dev: false + /getos@3.2.1: resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} dependencies: @@ -9275,6 +9623,13 @@ packages: dev: false optional: true + /glob-parent@3.1.0: + resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} + dependencies: + is-glob: 3.1.0 + path-dirname: 1.0.2 + dev: false + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -9486,6 +9841,37 @@ packages: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} dev: false + /has-value@0.3.1: + resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} + engines: {node: '>=0.10.0'} + dependencies: + get-value: 2.0.6 + has-values: 0.1.4 + isobject: 2.1.0 + dev: false + + /has-value@1.0.0: + resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} + engines: {node: '>=0.10.0'} + dependencies: + get-value: 2.0.6 + has-values: 1.0.0 + isobject: 3.0.1 + dev: false + + /has-values@0.1.4: + resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} + engines: {node: '>=0.10.0'} + dev: false + + /has-values@1.0.0: + resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} + engines: {node: '>=0.10.0'} + dependencies: + is-number: 3.0.0 + kind-of: 4.0.0 + dev: false + /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} @@ -9569,6 +9955,16 @@ packages: engines: {node: '>=8'} dev: true + /http-auth@3.1.3: + resolution: {integrity: sha512-Jbx0+ejo2IOx+cRUYAGS1z6RGc6JfYUNkysZM4u4Sfk1uLlGv814F7/PIjQQAuThLdAWxb74JMGd5J8zex1VQg==} + engines: {node: '>=4.6.1'} + dependencies: + apache-crypt: 1.2.6 + apache-md5: 1.1.8 + bcryptjs: 2.4.3 + uuid: 3.4.0 + dev: false + /http-browserify@1.7.0: resolution: {integrity: sha512-Irf/LJXmE3cBzU1eaR4+NEX6bmVLqt1wkmDiA7kBwH7zmb0D8kBAXsDmQ88hhj/qv9iEZKlyGx/hrMcFi8sOHw==} dependencies: @@ -9579,6 +9975,16 @@ packages: /http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + /http-errors@1.6.3: + resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} + engines: {node: '>= 0.6'} + dependencies: + depd: 1.1.2 + inherits: 2.0.3 + setprototypeof: 1.1.0 + statuses: 1.5.0 + dev: false + /http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -9589,6 +9995,10 @@ packages: statuses: 2.0.1 toidentifier: 1.0.1 + /http-parser-js@0.5.8: + resolution: {integrity: sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==} + dev: false + /http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} @@ -9779,6 +10189,10 @@ packages: once: 1.4.0 wrappy: 1.0.2 + /inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + dev: false + /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -9833,6 +10247,13 @@ packages: engines: {node: '>=8'} dev: true + /is-accessor-descriptor@1.0.1: + resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} + engines: {node: '>= 0.10'} + dependencies: + hasown: 2.0.1 + dev: false + /is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} @@ -9874,6 +10295,13 @@ packages: dependencies: has-bigints: 1.0.2 + /is-binary-path@1.0.1: + resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==} + engines: {node: '>=0.10.0'} + dependencies: + binary-extensions: 1.13.1 + dev: false + /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -9888,6 +10316,10 @@ packages: call-bind: 1.0.2 has-tostringtag: 1.0.0 + /is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + dev: false + /is-builtin-module@3.2.1: resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} engines: {node: '>=6'} @@ -9916,6 +10348,13 @@ packages: hasown: 2.0.1 dev: true + /is-data-descriptor@1.0.1: + resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.1 + dev: false + /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} @@ -9926,16 +10365,43 @@ packages: resolution: {integrity: sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==} dev: true + /is-descriptor@0.1.7: + resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==} + engines: {node: '>= 0.4'} + dependencies: + is-accessor-descriptor: 1.0.1 + is-data-descriptor: 1.0.1 + dev: false + + /is-descriptor@1.0.3: + resolution: {integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==} + engines: {node: '>= 0.4'} + dependencies: + is-accessor-descriptor: 1.0.1 + is-data-descriptor: 1.0.1 + dev: false + /is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} hasBin: true dev: true + /is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + dev: false + + /is-extendable@1.0.1: + resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} + engines: {node: '>=0.10.0'} + dependencies: + is-plain-object: 2.0.4 + dev: false + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - dev: true /is-finalizationregistry@1.0.2: resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} @@ -9957,12 +10423,18 @@ packages: dependencies: has-tostringtag: 1.0.0 + /is-glob@3.1.0: + resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: false + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 - dev: true /is-gzip@1.0.0: resolution: {integrity: sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==} @@ -10012,6 +10484,13 @@ packages: dependencies: has-tostringtag: 1.0.0 + /is-number@3.0.0: + resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 3.2.2 + dev: false + /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -10046,7 +10525,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: isobject: 3.0.1 - dev: true /is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} @@ -10126,6 +10604,16 @@ packages: get-intrinsic: 1.2.4 dev: true + /is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + dev: false + + /is-wsl@1.1.0: + resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} + engines: {node: '>=4'} + dev: false + /is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -10152,10 +10640,16 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + /isobject@2.1.0: + resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} + engines: {node: '>=0.10.0'} + dependencies: + isarray: 1.0.0 + dev: false + /isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - dev: true /isstream@0.1.2: resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} @@ -10500,10 +10994,23 @@ packages: json-buffer: 3.0.1 dev: true + /kind-of@3.2.2: + resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} + engines: {node: '>=0.10.0'} + dependencies: + is-buffer: 1.1.6 + dev: false + + /kind-of@4.0.0: + resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} + engines: {node: '>=0.10.0'} + dependencies: + is-buffer: 1.1.6 + dev: false + /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - dev: true /kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} @@ -10596,6 +11103,28 @@ packages: lit-element: 3.3.3 lit-html: 2.8.0 + /live-server@1.2.2: + resolution: {integrity: sha512-t28HXLjITRGoMSrCOv4eZ88viHaBVIjKjdI5PO92Vxlu+twbk6aE0t7dVIaz6ZWkjPilYFV6OSdMYl9ybN2B4w==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + chokidar: 2.1.8 + colors: 1.4.0 + connect: 3.7.0 + cors: 2.8.5 + event-stream: 3.3.4 + faye-websocket: 0.11.4 + http-auth: 3.1.3 + morgan: 1.10.0 + object-assign: 4.1.1 + opn: 6.0.0 + proxy-middleware: 0.15.0 + send: 0.18.0 + serve-index: 1.9.1 + transitivePeerDependencies: + - supports-color + dev: false + /load-bmfont@1.4.1: resolution: {integrity: sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA==} dependencies: @@ -10848,6 +11377,11 @@ packages: tmpl: 1.0.5 dev: true + /map-cache@0.2.2: + resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} + engines: {node: '>=0.10.0'} + dev: false + /map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -10862,6 +11396,17 @@ packages: resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} dev: true + /map-stream@0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + dev: false + + /map-visit@1.0.0: + resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} + engines: {node: '>=0.10.0'} + dependencies: + object-visit: 1.0.1 + dev: false + /markdown-it@14.0.0: resolution: {integrity: sha512-seFjF0FIcPt4P9U39Bq1JYblX0KZCjDLFFQPHpL5AzHpqPEKtosxmdq/LTVZnjfH7tjt9BxStm+wXcDBNuYmzw==} hasBin: true @@ -10883,6 +11428,12 @@ packages: react: 18.2.0 dev: true + /math.gl@4.0.1: + resolution: {integrity: sha512-Yvw1HfmsDePxwhCBvGT8teyPN0mwxcxUaWLoDaRuZYxoUYa9HRg+6ywBS+yXopC0wIS9MFi+BCVKP8hdJpaJjw==} + dependencies: + '@math.gl/core': 4.0.1 + dev: false + /md5-file@4.0.0: resolution: {integrity: sha512-UC0qFwyAjn4YdPpKaDNw6gNxRf7Mcx7jC1UGCY4boCzgvU2Aoc1mOGzTtrjjLKhM5ivsnhoKpQVxKPp+1j1qwg==} engines: {node: '>=6.0'} @@ -11190,6 +11741,27 @@ packages: - supports-color dev: false + /micromatch@3.1.10: + resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} + engines: {node: '>=0.10.0'} + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + braces: 2.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + extglob: 2.0.4 + fragment-cache: 0.2.1 + kind-of: 6.0.3 + nanomatch: 1.2.13 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + dev: false + /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} @@ -11411,6 +11983,14 @@ packages: minipass: 3.3.6 yallist: 4.0.0 + /mixin-deep@1.3.2: + resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} + engines: {node: '>=0.10.0'} + dependencies: + for-in: 1.0.2 + is-extendable: 1.0.1 + dev: false + /mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} @@ -11457,6 +12037,19 @@ packages: /moo@0.5.2: resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==} + /morgan@1.10.0: + resolution: {integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==} + engines: {node: '>= 0.8.0'} + dependencies: + basic-auth: 2.0.1 + debug: 2.6.9 + depd: 2.0.0 + on-finished: 2.3.0 + on-headers: 1.0.2 + transitivePeerDependencies: + - supports-color + dev: false + /mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -11512,6 +12105,25 @@ packages: hasBin: true dev: true + /nanomatch@1.2.13: + resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} + engines: {node: '>=0.10.0'} + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + fragment-cache: 0.2.1 + is-windows: 1.0.2 + kind-of: 6.0.3 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2 + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color + dev: false + /napi-build-utils@1.0.2: resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} requiresBuild: true @@ -11721,10 +12333,16 @@ packages: validate-npm-package-license: 3.0.4 dev: true + /normalize-path@2.1.1: + resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} + engines: {node: '>=0.10.0'} + dependencies: + remove-trailing-separator: 1.1.0 + dev: false + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - dev: true /npm-run-all@4.1.5: resolution: {integrity: sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==} @@ -11779,6 +12397,15 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + /object-copy@0.1.0: + resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} + engines: {node: '>=0.10.0'} + dependencies: + copy-descriptor: 0.1.1 + define-property: 0.2.5 + kind-of: 3.2.2 + dev: false + /object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} @@ -11796,6 +12423,13 @@ packages: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + /object-visit@1.0.1: + resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + dev: false + /object.assign@4.1.4: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} engines: {node: '>= 0.4'} @@ -11840,6 +12474,13 @@ packages: es-abstract: 1.22.4 dev: true + /object.pick@1.3.0: + resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + dev: false + /object.values@1.1.7: resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} engines: {node: '>= 0.4'} @@ -11853,6 +12494,13 @@ packages: resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==} dev: false + /on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: false + /on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -11888,6 +12536,14 @@ packages: hasBin: true dev: true + /opn@6.0.0: + resolution: {integrity: sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ==} + engines: {node: '>=8'} + deprecated: The package has been renamed to `open` + dependencies: + is-wsl: 1.1.0 + dev: false + /optionator@0.9.3: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} @@ -12070,6 +12726,11 @@ packages: tslib: 2.6.2 dev: false + /pascalcase@0.1.1: + resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} + engines: {node: '>=0.10.0'} + dev: false + /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} dev: true @@ -12081,6 +12742,10 @@ packages: tslib: 2.6.2 dev: false + /path-dirname@1.0.2: + resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} + dev: false + /path-exists-cli@2.0.0: resolution: {integrity: sha512-qGr0A87KYCznmvabblxyxnzA/MtPZ28wH+4SCMP4tjTFAbzqwvs5xpUZExAYzq5OgHe5vIswzdH5iosCb8YF/Q==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -12151,6 +12816,12 @@ packages: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true + /pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + dependencies: + through: 2.3.8 + dev: false + /pbkdf2@3.1.2: resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} engines: {node: '>=0.12'} @@ -12296,6 +12967,11 @@ packages: - supports-color dev: true + /posix-character-classes@0.1.1: + resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} + engines: {node: '>=0.10.0'} + dev: false + /postcss@8.4.31: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} @@ -12483,7 +13159,7 @@ packages: minecraft-data: 3.62.0 prismarine-block: github.com/zardoy/prismarine-block/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-nbt: 2.2.1 - prismarine-world: github.com/zardoy/prismarine-world/c358222204d21fe7d45379fbfcefb047f926c786 + prismarine-world: github.com/zardoy/prismarine-world/6ae6f009d38460de284f8c226c665f04cbad9465 vec3: 0.1.8 dev: false @@ -12695,6 +13371,11 @@ packages: /proxy-from-env@1.0.0: resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} + /proxy-middleware@0.15.0: + resolution: {integrity: sha512-EGCG8SeoIRVMhsqHQUdDigB2i7qU7fCsWASwn54+nPutYO8n4q6EiwMzyfWlC+dzRFExP+kvcnDFdBDHoZBU7Q==} + engines: {node: '>=0.8.0'} + dev: false + /psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} @@ -13203,6 +13884,17 @@ packages: process: 0.11.10 string_decoder: 1.3.0 + /readdirp@2.2.1: + resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} + engines: {node: '>=0.10'} + dependencies: + graceful-fs: 4.2.11 + micromatch: 3.1.10 + readable-stream: 2.3.8 + transitivePeerDependencies: + - supports-color + dev: false + /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -13277,6 +13969,14 @@ packages: dependencies: '@babel/runtime': 7.22.11 + /regex-not@1.0.2: + resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 3.0.2 + safe-regex: 1.1.0 + dev: false + /regexp-tree@0.1.27: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true @@ -13377,6 +14077,20 @@ packages: - supports-color dev: false + /remove-trailing-separator@1.1.0: + resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} + dev: false + + /repeat-element@1.1.4: + resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} + engines: {node: '>=0.10.0'} + dev: false + + /repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + dev: false + /request-progress@3.0.0: resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} dependencies: @@ -13411,6 +14125,11 @@ packages: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} dev: false + /resolve-url@0.2.1: + resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} + deprecated: https://github.com/lydell/resolve-url#deprecated + dev: false + /resolve@1.22.4: resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} hasBin: true @@ -13578,6 +14297,12 @@ packages: is-regex: 1.1.4 dev: true + /safe-regex@1.1.0: + resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + dependencies: + ret: 0.1.15 + dev: false + /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -13670,6 +14395,21 @@ packages: randombytes: 2.1.0 dev: false + /serve-index@1.9.1: + resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} + engines: {node: '>= 0.8.0'} + dependencies: + accepts: 1.3.8 + batch: 0.6.1 + debug: 2.6.9 + escape-html: 1.0.3 + http-errors: 1.6.3 + mime-types: 2.1.35 + parseurl: 1.3.3 + transitivePeerDependencies: + - supports-color + dev: false + /serve-static@1.15.0: resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} engines: {node: '>= 0.8.0'} @@ -13709,9 +14449,23 @@ packages: engines: {node: '>=6.9'} dev: false + /set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 2.0.1 + is-extendable: 0.1.1 + is-plain-object: 2.0.4 + split-string: 3.1.0 + dev: false + /setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + /setprototypeof@1.1.0: + resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} + dev: false + /setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -13880,6 +14634,38 @@ packages: tslib: 2.6.2 dev: false + /snapdragon-node@2.1.1: + resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} + engines: {node: '>=0.10.0'} + dependencies: + define-property: 1.0.0 + isobject: 3.0.1 + snapdragon-util: 3.0.1 + dev: false + + /snapdragon-util@3.0.1: + resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 3.2.2 + dev: false + + /snapdragon@0.8.2: + resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} + engines: {node: '>=0.10.0'} + dependencies: + base: 0.11.2 + debug: 2.6.9 + define-property: 0.2.5 + extend-shallow: 2.0.1 + map-cache: 0.2.2 + source-map: 0.5.7 + source-map-resolve: 0.5.3 + use: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: false + /socket.io-adapter@1.1.2: resolution: {integrity: sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==} dev: false @@ -14017,12 +14803,28 @@ packages: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} + /source-map-resolve@0.5.3: + resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} + deprecated: See https://github.com/lydell/source-map-resolve#deprecated + dependencies: + atob: 2.1.2 + decode-uri-component: 0.2.2 + resolve-url: 0.2.1 + source-map-url: 0.4.1 + urix: 0.1.0 + dev: false + /source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + /source-map-url@0.4.1: + resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} + deprecated: See https://github.com/lydell/source-map-url#deprecated + dev: false + /source-map@0.5.6: resolution: {integrity: sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==} engines: {node: '>=0.10.0'} @@ -14075,6 +14877,19 @@ packages: resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} dev: true + /split-string@3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 3.0.2 + dev: false + + /split@0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} + dependencies: + through: 2.3.8 + dev: false + /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true @@ -14132,6 +14947,14 @@ packages: stacktrace-gps: 3.1.2 dev: false + /static-extend@0.1.2: + resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} + engines: {node: '>=0.10.0'} + dependencies: + define-property: 0.2.5 + object-copy: 0.1.0 + dev: false + /stats-gl@1.0.5: resolution: {integrity: sha512-XimMxvwnf1Qf5KwebhcoA34kcX+fWEkIl0QjNkCbu4IpoyDMMsOajExn7FIq5w569k45+LhmsuRlGSrsvmGdNw==} dev: false @@ -14140,6 +14963,11 @@ packages: resolution: {integrity: sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==} dev: false + /statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + dev: false + /statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} @@ -14171,6 +14999,12 @@ packages: readable-stream: 3.6.2 dev: true + /stream-combiner@0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + dependencies: + duplexer: 0.1.2 + dev: false + /stream-shift@1.0.1: resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==} dev: true @@ -14571,6 +15405,21 @@ packages: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} + /to-object-path@0.3.0: + resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} + engines: {node: '>=0.10.0'} + dependencies: + kind-of: 3.2.2 + dev: false + + /to-regex-range@2.1.1: + resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} + engines: {node: '>=0.10.0'} + dependencies: + is-number: 3.0.0 + repeat-string: 1.6.1 + dev: false + /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -14578,6 +15427,16 @@ packages: is-number: 7.0.0 dev: true + /to-regex@3.0.2: + resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} + engines: {node: '>=0.10.0'} + dependencies: + define-property: 2.0.2 + extend-shallow: 3.0.2 + regex-not: 1.0.2 + safe-regex: 1.1.0 + dev: false + /tocbot@4.21.2: resolution: {integrity: sha512-R5Muhi/TUu4i4snWVrMgNoXyJm2f8sJfdgIkQvqb+cuIXQEIMAiWGWgCgYXHqX4+XiS/Bnm7IYZ9Zy6NVe6lhw==} dev: true @@ -14676,6 +15535,10 @@ packages: /tweetnacl@0.14.5: resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + /twgl.js@5.5.4: + resolution: {integrity: sha512-6kFOmijOpmblTN9CCwOTCxK4lPg7rCyQjLuub6EMOlEp89Ex6yUcsMjsmH7andNPL2NE3XmHdqHeP5gVKKPhxw==} + dev: false + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -14867,6 +15730,16 @@ packages: vfile: 6.0.1 dev: false + /union-value@1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} + dependencies: + arr-union: 3.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + set-value: 2.0.1 + dev: false + /union@0.5.0: resolution: {integrity: sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==} engines: {node: '>= 0.8.0'} @@ -14957,6 +15830,10 @@ packages: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} + /unix-crypt-td-js@1.1.4: + resolution: {integrity: sha512-8rMeVYWSIyccIJscb9NdCfZKSRBKYTeVnwmiRYT2ulE3qd1RaDQ0xQDP+rI3ccIWbhu/zuo5cgN8z73belNZgw==} + dev: false + /unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -14970,6 +15847,14 @@ packages: webpack-virtual-modules: 0.5.0 dev: true + /unset-value@1.0.0: + resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} + engines: {node: '>=0.10.0'} + dependencies: + has-value: 0.3.1 + isobject: 3.0.1 + dev: false + /untildify@4.0.0: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} engines: {node: '>=8'} @@ -15006,6 +15891,11 @@ packages: dependencies: punycode: 2.3.0 + /urix@0.1.0: + resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} + deprecated: Please see https://github.com/lydell/urix#deprecated + dev: false + /url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} dev: true @@ -15090,6 +15980,11 @@ packages: use-deep-compare: 1.1.0(react@18.2.0) dev: true + /use@3.1.1: + resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} + engines: {node: '>=0.10.0'} + dev: false + /utf8-byte-length@1.0.4: resolution: {integrity: sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==} dev: false @@ -15121,6 +16016,12 @@ packages: dependencies: macaddress: 0.5.3 + /uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + dev: false + /uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true @@ -15403,6 +16304,20 @@ packages: sdp: 3.2.0 dev: false + /websocket-driver@0.7.4: + resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} + engines: {node: '>=0.8.0'} + dependencies: + http-parser-js: 0.5.8 + safe-buffer: 5.2.1 + websocket-extensions: 0.1.4 + dev: false + + /websocket-extensions@0.1.4: + resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} + engines: {node: '>=0.8.0'} + dev: false + /whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} @@ -15929,7 +16844,7 @@ packages: prismarine-recipe: 1.3.1(prismarine-registry@1.7.0) prismarine-registry: 1.7.0 prismarine-windows: 2.9.0 - prismarine-world: github.com/zardoy/prismarine-world/c358222204d21fe7d45379fbfcefb047f926c786 + prismarine-world: github.com/zardoy/prismarine-world/6ae6f009d38460de284f8c226c665f04cbad9465 protodef: 1.15.0 typed-emitter: 1.4.0 vec3: 0.1.8 @@ -16037,8 +16952,8 @@ packages: - minecraft-data dev: false - github.com/zardoy/prismarine-world/c358222204d21fe7d45379fbfcefb047f926c786: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-world/tar.gz/c358222204d21fe7d45379fbfcefb047f926c786} + github.com/zardoy/prismarine-world/6ae6f009d38460de284f8c226c665f04cbad9465: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465} name: prismarine-world version: 3.6.2 engines: {node: '>=8.0.0'} diff --git a/prismarine-viewer/buildWorker.mjs b/prismarine-viewer/buildWorker.mjs index a8a5c1381..9be06cf23 100644 --- a/prismarine-viewer/buildWorker.mjs +++ b/prismarine-viewer/buildWorker.mjs @@ -21,7 +21,7 @@ const buildOptions = { }, platform: 'browser', entryPoints: [path.join(__dirname, './viewer/lib/worker.js')], - minify: true, + // minify: true, logLevel: 'info', drop: !watch ? [ 'debugger' @@ -101,7 +101,7 @@ const buildOptions = { resolveDir: process.cwd(), } }) - build.onEnd(({metafile, outputFiles}) => { + build.onEnd(({ metafile, outputFiles }) => { if (!metafile) return fs.writeFileSync(path.join(__dirname, './public/metafile.json'), JSON.stringify(metafile)) for (const outDir of ['../dist/', './public/']) { diff --git a/prismarine-viewer/esbuild.mjs b/prismarine-viewer/esbuild.mjs index 91b787db9..de1a3b25f 100644 --- a/prismarine-viewer/esbuild.mjs +++ b/prismarine-viewer/esbuild.mjs @@ -47,11 +47,14 @@ const buildOptions = { http: 'http-browserify', stream: 'stream-browserify', net: 'net-browserify', + 'stats.js': 'stats.js/src/Stats.js', }, inject: [], metafile: true, loader: { '.png': 'dataurl', + '.vert': 'text', + '.frag': 'text' }, plugins: [ { diff --git a/prismarine-viewer/examples/TextureAnimation.ts b/prismarine-viewer/examples/TextureAnimation.ts new file mode 100644 index 000000000..dfa004624 --- /dev/null +++ b/prismarine-viewer/examples/TextureAnimation.ts @@ -0,0 +1,69 @@ +export type AnimationControlSwitches = { + tick: number + interpolationTick: number // next one +} + +type Data = { + interpolate: boolean; + frametime: number; + frames: ({ + index: number; + time: number; + } | number)[] | undefined; +}; + +export class TextureAnimation { + data: Data; + frameImages: number; + frameDelta: number; + frameTime: number; + framesToSwitch: number; + frameIndex: number; + + constructor(public animationControl: AnimationControlSwitches, data: Data, public framesImages: number) { + this.data = { + interpolate: false, + frametime: 1, + ...data + }; + this.frameImages = 1; + this.frameDelta = 0; + this.frameTime = this.data.frametime * 50; + this.frameIndex = 0; + + this.framesToSwitch = this.frameImages; + if (this.data.frames) { + this.framesToSwitch = this.data.frames.length; + } + } + + step (deltaMs: number) { + this.frameDelta += deltaMs; + + if (this.frameDelta > this.frameTime) { + this.frameDelta -= this.frameTime; + this.frameDelta %= this.frameTime; + + this.frameIndex++; + this.frameIndex %= this.framesToSwitch; + + const frames = this.data.frames.map(frame => typeof frame === 'number' ? { index: frame, time: this.data.frametime } : frame); + if (frames) { + let frame = frames[this.frameIndex] + let nextFrame = frames[(this.frameIndex + 1) % this.framesToSwitch]; + + this.animationControl.tick = frame.index; + this.animationControl.interpolationTick = nextFrame.index; + this.frameTime = frame.time * 50; + } else { + this.animationControl.tick = this.frameIndex; + this.animationControl.interpolationTick = (this.frameIndex + 1) % this.framesToSwitch; + } + } + + if (this.data.interpolate) { + this.animationControl.interpolationTick = this.frameDelta / this.frameTime; + } + } + +} diff --git a/prismarine-viewer/examples/TouchControls2.tsx b/prismarine-viewer/examples/TouchControls2.tsx new file mode 100644 index 000000000..5d1b4459f --- /dev/null +++ b/prismarine-viewer/examples/TouchControls2.tsx @@ -0,0 +1,63 @@ +import React, { useEffect } from 'react' +import { LeftTouchArea, RightTouchArea, useInterfaceState } from '@dimaka/interface' +import { css } from '@emotion/css' +import { Viewer } from '../viewer/lib/viewer' +import { renderToDom } from '@zardoy/react-util' +import { Vec3 } from 'vec3' +import * as THREE from 'three' + +declare const viewer: Viewer +const Controls = () => { + // todo setting + const usingTouch = navigator.maxTouchPoints > 0 + + useEffect(() => { + let vec3 = new Vec3(0, 0, 0) + + setInterval(() => { + viewer.camera.position.add(new THREE.Vector3(vec3.x, vec3.y, vec3.z)) + }, 1000 / 30) + + useInterfaceState.setState({ + isFlying: false, + uiCustomization: { + touchButtonSize: 40, + }, + updateCoord ([coord, state]) { + vec3 = new Vec3(0, 0, 0) + vec3[coord] = state + } + }) + }, []) + + if (!usingTouch) return null + return ( + div { + pointer-events: auto; + } + `} + > + + + + + ) +} + +export const renderPlayground = () => { + renderToDom(, { + // selector: 'body', + }) +} diff --git a/prismarine-viewer/examples/_FragmentShader.frag b/prismarine-viewer/examples/_FragmentShader.frag new file mode 100644 index 000000000..ca0c9f4dc --- /dev/null +++ b/prismarine-viewer/examples/_FragmentShader.frag @@ -0,0 +1,31 @@ +#version 300 es +precision highp float; + +out vec4 FragColor; + +in vec2 TexCoord; +flat in float TextureIndex; +flat in vec3 BiomeColor; + +uniform sampler2D texture1; + +void main() +{ + ivec2 texSize = textureSize(texture1, 0); + int TilesPerRow = texSize.x / 16; + + ivec2 coord = ivec2(16,16) * ivec2(int(TextureIndex)%TilesPerRow,int(TextureIndex)/TilesPerRow); + coord = coord + ivec2(TexCoord * 16.0f); + + vec4 t = texelFetch(texture1, coord, 0); + if (abs(t.x-t.y) <=0.010 || abs(t.x-t.z)<=0.010 ||abs(t.y-t.z) <=0.010) + { + FragColor = vec4(BiomeColor,1.0f)*t; + } + else + { + FragColor = t; + //FragColor = mix(t, vec4(BiomeColor, 1.0f), 0.5f); + } + +} diff --git a/prismarine-viewer/examples/_VertexShader.vert b/prismarine-viewer/examples/_VertexShader.vert new file mode 100644 index 000000000..0acdacf94 --- /dev/null +++ b/prismarine-viewer/examples/_VertexShader.vert @@ -0,0 +1,87 @@ +#version 300 es +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; +layout (location = 2) in float CubeSide; + +layout (location = 3) in vec3 aOffset; +layout (location = 4) in float aTextureIndex; +layout (location = 6) in vec3 aBiomeColor; + +//#Define + +out vec2 TexCoord; +flat out float TextureIndex; +flat out vec3 BiomeColor; + +uniform mat4 view; +uniform mat4 projection; +uniform int tick; + +mat4 rotationX( in float angle ) { + return mat4( 1.0, 0, 0, 0, + 0, cos(angle), -sin(angle), 0, + 0, sin(angle), cos(angle), 0, + 0, 0, 0, 1); +} + +mat4 rotationY( in float angle ) { + return mat4( cos(angle), 0, sin(angle), 0, + 0, 1.0, 0, 0, + -sin(angle), 0, cos(angle), 0, + 0, 0, 0, 1); +} + +void main() +{ + //vec3 TransitionedPos = aPos; + vec3 TransitionedPos ;//= (vec4(aPos,0.0f) *rotationX(radians(180.0f))).xyz; + + TexCoord = vec2(aTexCoord.x, (1.0 - aTexCoord.y)); // Flipping image for opengl coordinates + TextureIndex = aTextureIndex; //Passing texture index to fragment shader + switch (int(CubeSide)) { + case 0: + TexCoord = vec2((1.0f-aTexCoord.x), (1.0 - aTexCoord.y)); + //TextureIndex = aTextureIndex.x; + //TransitionedPos = (vec4(aPos,0.0f) *rotationY(radians(90.0f))).xyz; + + TransitionedPos = (vec4(aPos,0.0f) *rotationX(radians(-90.0f))).xyz; + break; + case 1: + //TextureIndex = aTextureIndex.y; + TransitionedPos = (vec4(aPos,0.0f) *rotationX(radians(90.0f))).xyz; + break; + case 2: + //TextureIndex = aTextureIndex.z; + //TexCoord = vec2((1.0f-aTexCoord.y), (1.0f - aTexCoord.x)); + TransitionedPos = vec4(aPos,0.0f).xyz; + break; + case 3: + //TextureIndex = aTextureIndex.z; + //TexCoord = vec2(aTexCoord.y, (1.0f - aTexCoord.x)); + TexCoord = vec2(aTexCoord); + //TransitionedPos = (vec4(aPos,0.0f) *rotationX(radians(-90.0f))).xyz; + //TransitionedPos = (vec4(aPos,0.0f) *rotationY(radians(90.0f))).xyz; + TransitionedPos = (vec4(aPos,0.0f) *rotationX(radians(180.0f))).xyz; + break; + case 4: + //TextureIndex = aTextureIndexPlus.x; + //TransitionedPos = vec4(aPos,0.0f).xyz; + //TransitionedPos = (vec4(aPos,0.0f) *rotationY(radians(-90.0f))).xyz; + TransitionedPos = (vec4(aPos,0.0f) *rotationY(radians(90.0f))).xyz; + break; + case 5: + //TextureIndex = aTextureIndexPlus.y; + //TransitionedPos = vec4(aPos,0.0f).xyz; + + //TransitionedPos = (vec4(aPos,0.0f) *rotationX(radians(180.0f))).xyz; + //TransitionedPos = (vec4(aPos,0.0f) *rotationY(radians(90.0f))).xyz; + TransitionedPos = (vec4(aPos,0.0f) *rotationY(radians(-90.0f))).xyz; + break; + } + TextureIndex += float(tick); + + BiomeColor = aBiomeColor; + + gl_Position = projection * view * vec4(TransitionedPos + aOffset + vec3(0.5f,0.5f,0.5f), 1.0f); //Offseting by 0.5 to center the cube + //CubeSideIndex = CubeSide; //Passing cube side index to fragment shader +} diff --git a/prismarine-viewer/examples/newStats.ts b/prismarine-viewer/examples/newStats.ts new file mode 100644 index 000000000..fb363484f --- /dev/null +++ b/prismarine-viewer/examples/newStats.ts @@ -0,0 +1,35 @@ +let rightOffset = 0 + +const stats = {} + +export const addNewStat = (id: string, width = 80, x = rightOffset, y = 0) => { + const pane = document.createElement('div') + pane.id = 'fps-counter' + pane.style.position = 'fixed' + pane.style.top = `${y}px` + pane.style.right = `${x}px` + // gray bg + pane.style.backgroundColor = 'rgba(0, 0, 0, 0.5)' + pane.style.color = 'white' + pane.style.padding = '2px' + pane.style.fontFamily = 'monospace' + pane.style.fontSize = '12px' + pane.style.zIndex = '10000' + pane.style.pointerEvents = 'none' + document.body.appendChild(pane) + stats[id] = pane + if (y === 0) { // otherwise it's a custom position + rightOffset += width + } + + return { + updateText: (text: string) => { + pane.innerText = text + } + } +} + +export const updateStatText = (id, text) => { + if (!stats[id]) return + stats[id].innerText = text +} diff --git a/prismarine-viewer/examples/playground.ts b/prismarine-viewer/examples/playground.ts index a1bd6d0f1..a5c9f6720 100644 --- a/prismarine-viewer/examples/playground.ts +++ b/prismarine-viewer/examples/playground.ts @@ -12,10 +12,17 @@ import { loadScript } from '../viewer/lib/utils' import JSZip from 'jszip' import { TWEEN_DURATION } from '../viewer/lib/entities' import Entity from '../viewer/lib/entity/Entity' +// import * as Mathgl from 'math.gl' +import { findTextureInBlockStates } from '../../src/playerWindows' +import { initWebglRenderer, loadFixtureSides, setAnimationTick } from './webglRenderer' +import { renderToDom } from '@zardoy/react-util' globalThis.THREE = THREE //@ts-ignore import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { renderPlayground } from './TouchControls2' +import { WorldRendererWebgl } from '../viewer/lib/worldrendererWebgl' +import { TextureAnimation } from './TextureAnimation' const gui = new GUI() @@ -39,7 +46,8 @@ const params = { entityRotate: false, camera: '', playSound () { }, - blockIsomorphicRenderBundle () { } + blockIsomorphicRenderBundle () { }, + animationTick: 0 } const qs = new URLSearchParams(window.location.search) @@ -59,10 +67,20 @@ const setQs = () => { let ignoreResize = false +const enableControls = new URLSearchParams(window.location.search).get('controls') === 'true' + async function main () { let continuousRender = false - const { version } = params + // const { version } = params + let fixtureUrl = qs.get('fixture') + let fixture: undefined | Record + if (fixtureUrl) { + console.log('Loading fixture') + fixture = await fetch(fixtureUrl).then(r => r.json()) + console.log('Loaded fixture') + } + const version = fixture?.version ?? '1.20.2' // temporary solution until web worker is here, cache data for faster reloads const globalMcData = window['mcData'] if (!globalMcData['version']) { @@ -92,6 +110,7 @@ async function main () { gui.add(params, 'skip') gui.add(params, 'playSound') gui.add(params, 'blockIsomorphicRenderBundle') + const animationController = gui.add(params, 'animationTick', -1, 20, 1).listen() gui.open(false) let metadataFolder = gui.addFolder('metadata') // let entityRotationFolder = gui.addFolder('entity metadata') @@ -112,8 +131,12 @@ async function main () { const chunk1 = new Chunk() //@ts-ignore const chunk2 = new Chunk() - chunk1.setBlockStateId(targetPos, 34) - chunk2.setBlockStateId(targetPos.offset(1, 0, 0), 34) + chunk1.setBlockStateId(targetPos, 1) + chunk2.setBlockStateId(targetPos.offset(1, 0, 0), 1) + chunk1.setBlockStateId(targetPos.offset(0, 1, 1), 2) + // chunk1.setBlockStateId(targetPos.offset(0, 1, 0), 1) + // chunk1.setBlockStateId(targetPos.offset(1, 1, 0), 1) + // chunk1.setBlockStateId(targetPos.offset(-1, 1, 0), 1) const world = new World((chunkX, chunkZ) => { // if (chunkX === 0 && chunkZ === 0) return chunk1 // if (chunkX === 1 && chunkZ === 0) return chunk2 @@ -122,185 +145,126 @@ async function main () { return chunk }) + let stopUpdate = false + // let stopUpdate = true + // await schem.paste(world, new Vec3(0, 60, 0)) const worldView = new WorldDataEmitter(world, viewDistance, targetPos) - - // Create three.js context, add to page - const renderer = new THREE.WebGLRenderer({ alpha: true, ...localStorage['renderer'] }) - renderer.setPixelRatio(window.devicePixelRatio || 1) - renderer.setSize(window.innerWidth, window.innerHeight) - document.body.appendChild(renderer.domElement) - - // Create viewer - const viewer = new Viewer(renderer, 1) - viewer.entities.setDebugMode('basic') + const nullRenderer = new THREE.WebGLRenderer({ antialias: true }) + const viewer = new Viewer(nullRenderer, 1) + viewer.world.stopBlockUpdate = stopUpdate viewer.setVersion(version) - viewer.entities.onSkinUpdate = () => { - viewer.update() - viewer.render() - } - - viewer.listen(worldView) - // Load chunks - await worldView.init(targetPos) - window['worldView'] = worldView - window['viewer'] = viewer - - params.blockIsomorphicRenderBundle = () => { - const canvas = renderer.domElement - const onlyCurrent = !confirm('Ok - render all blocks, Cancel - render only current one') - const sizeRaw = prompt('Size', '512') - if (!sizeRaw) return - const size = parseInt(sizeRaw) - // const size = 512 - - ignoreResize = true - canvas.width = size - canvas.height = size - renderer.setSize(size, size) - - //@ts-ignore - viewer.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 10) - viewer.scene.background = null - - const rad = THREE.MathUtils.degToRad(-120) - viewer.directionalLight.position.set( - Math.cos(rad), - Math.sin(rad), - 0.2 - ).normalize() - viewer.directionalLight.intensity = 1 - - const cameraPos = targetPos.offset(2, 2, 2) - const pitch = THREE.MathUtils.degToRad(-30) - const yaw = THREE.MathUtils.degToRad(45) - viewer.camera.rotation.set(pitch, yaw, 0, 'ZYX') - // viewer.camera.lookAt(center.x + 0.5, center.y + 0.5, center.z + 0.5) - viewer.camera.position.set(cameraPos.x + 1, cameraPos.y + 0.5, cameraPos.z + 1) - - const allBlocks = mcData.blocksArray.map(b => b.name) - // const allBlocks = ['stone', 'warped_slab'] - - let blockCount = 1 - let blockName = allBlocks[0] - - const updateBlock = () => { - - //@ts-ignore - // viewer.setBlockStateId(targetPos, mcData.blocksByName[blockName].minStateId) - params.block = blockName - // todo cleanup (introduce getDefaultState) - onUpdate.block() - applyChanges(false, true) - } - viewer.waitForChunksToRender().then(async () => { - // wait for next macro task - await new Promise(resolve => { - setTimeout(resolve, 0) - }) - if (onlyCurrent) { - viewer.render() - onWorldUpdate() - } else { - // will be called on every render update - viewer.world.renderUpdateEmitter.addListener('update', onWorldUpdate) - updateBlock() + globalThis.viewer = viewer + + await initWebglRenderer(version, () => { }, !enableControls && !fixture, true) + const simpleControls = () => { + let pressedKeys = new Set() + const loop = () => { + // Create a vector that points in the direction the camera is looking + let direction = new THREE.Vector3(0, 0, 0); + if (pressedKeys.has('KeyW')) { + direction.z = -0.5; + } + if (pressedKeys.has('KeyS')) { + direction.z += 0.5 + } + if (pressedKeys.has('KeyA')) { + direction.x -= 0.5 + } + if (pressedKeys.has('KeyD')) { + direction.x += 0.5 } - }) - - const zip = new JSZip() - zip.file('description.txt', 'Generated with prismarine-viewer') - - const end = async () => { - // download zip file - const a = document.createElement('a') - const blob = await zip.generateAsync({ type: 'blob' }) - const dataUrlZip = URL.createObjectURL(blob) - a.href = dataUrlZip - a.download = 'blocks_render.zip' - a.click() - URL.revokeObjectURL(dataUrlZip) - console.log('end') - viewer.world.renderUpdateEmitter.removeListener('update', onWorldUpdate) + if (pressedKeys.has('ShiftLeft')) { + viewer.camera.position.y -= 0.5 + } + if (pressedKeys.has('Space')) { + viewer.camera.position.y += 0.5 + } + direction.applyQuaternion(viewer.camera.quaternion); + direction.y = 0; + // Add the vector to the camera's position to move the camera + viewer.camera.position.add(direction); } - - async function onWorldUpdate () { - // await new Promise(resolve => { - // setTimeout(resolve, 50) - // }) - const dataUrl = canvas.toDataURL('image/png') - - zip.file(`${blockName}.png`, dataUrl.split(',')[1], { base64: true }) - - if (onlyCurrent) { - end() + setInterval(loop, 1000 / 30) + const keys = (e) => { + const code = e.code + const pressed = e.type === 'keydown' + if (pressed) { + pressedKeys.add(code) } else { - nextBlock() + pressedKeys.delete(code) } } - const nextBlock = async () => { - blockName = allBlocks[blockCount++] - console.log(allBlocks.length, '/', blockCount, blockName) - if (blockCount % 5 === 0) { - await new Promise(resolve => { - setTimeout(resolve, 100) - }) + window.addEventListener('keydown', keys) + window.addEventListener('keyup', keys) + + // mouse + const mouse = { x: 0, y: 0 } + const mouseMove = (e: PointerEvent) => { + if ((e.target as HTMLElement).closest('.lil-gui')) return + if (e.buttons === 1 || e.pointerType === 'touch') { + viewer.camera.rotation.x -= e.movementY / 100 + //viewer.camera. + viewer.camera.rotation.y -= e.movementX / 100 + if (viewer.camera.rotation.x < -Math.PI / 2) viewer.camera.rotation.x = -Math.PI / 2 + if (viewer.camera.rotation.x > Math.PI / 2) viewer.camera.rotation.x = Math.PI / 2 + + // yaw += e.movementY / 20; + // pitch += e.movementX / 20; } - if (blockName) { - updateBlock() - } else { - end() + if (e.buttons === 2) { + viewer.camera.position.set(0, 0, 0) } } + window.addEventListener('pointermove', mouseMove) + } + simpleControls() + renderPlayground() + + const writeToIndexedDb = async (name, data) => { + const db = await window.indexedDB.open(name, 1) + db.onupgradeneeded = (e) => { + const db = (e.target as any).result + db.createObjectStore(name) + } + db.onsuccess = (e) => { + const db = (e.target as any).result + const tx = db.transaction(name, 'readwrite') + const store = tx.objectStore(name) + store.add(data, name) + } } - // const jsonData = await fetch('https://bluecolored.de/bluemap/maps/overworld/tiles/0/x-2/2/z1/6.json?584662').then(r => r.json()) - - // const uniforms = { - // distance: { value: 0 }, - // sunlightStrength: { value: 1 }, - // ambientLight: { value: 0 }, - // skyColor: { value: new THREE.Color(0.5, 0.5, 1) }, - // voidColor: { value: new THREE.Color(0, 0, 0) }, - // hiresTileMap: { - // value: { - // map: null, - // size: 100, - // scale: new THREE.Vector2(1, 1), - // translate: new THREE.Vector2(), - // pos: new THREE.Vector2(), - // } - // } - - // } - - // const shader1 = new THREE.ShaderMaterial({ - // uniforms: uniforms, - // vertexShader: [0, 0, 0, 0], - // fragmentShader: fragmentShader, - // transparent: false, - // depthWrite: true, - // depthTest: true, - // vertexColors: true, - // side: THREE.FrontSide, - // wireframe: false - // }) + if (fixture) { + loadFixtureSides(fixture.sides) + const pos = fixture.camera[0] + viewer.camera.position.set(pos[0], pos[1], pos[2]) + } + + if (!enableControls) return + + // Create viewer + viewer.listen(worldView) + // Load chunks + await worldView.init(targetPos) + window['worldView'] = worldView + window['viewer'] = viewer //@ts-ignore - const controls = new OrbitControls(viewer.camera, renderer.domElement) - controls.target.set(targetPos.x + 0.5, targetPos.y + 0.5, targetPos.z + 0.5) + // const controls = new OrbitControls(viewer.camera, nullRenderer.domElement) + // controls.target.set(targetPos.x + 0.5, targetPos.y + 0.5, targetPos.z + 0.5) const cameraPos = targetPos.offset(2, 2, 2) const pitch = THREE.MathUtils.degToRad(-45) const yaw = THREE.MathUtils.degToRad(45) viewer.camera.rotation.set(pitch, yaw, 0, 'ZYX') - viewer.camera.lookAt(targetPos.x + 0.5, targetPos.y + 0.5, targetPos.z + 0.5) - viewer.camera.position.set(cameraPos.x + 0.5, cameraPos.y + 0.5, cameraPos.z + 0.5) - controls.update() + // viewer.camera.lookAt(targetPos.x + 0.5, targetPos.y + 0.5, targetPos.z + 0.5) + viewer.camera.position.set(cameraPos.x, cameraPos.y, cameraPos.z) + // controls.update() let blockProps = {} let entityOverrides = {} @@ -315,7 +279,7 @@ async function main () { id: 'id', name: params.entity, pos: targetPos.offset(0.5, 1, 0.5), width: 1, height: 1, username: localStorage.testUsername, yaw: Math.PI, pitch: 0 }) const enableSkeletonDebug = (obj) => { - const {children, isSkeletonHelper} = obj + const { children, isSkeletonHelper } = obj if (!Array.isArray(children)) return if (isSkeletonHelper) { obj.visible = true @@ -332,6 +296,9 @@ async function main () { }, TWEEN_DURATION) } + params.block ||= 'stone' + + let textureAnimation: TextureAnimation | undefined const onUpdate = { block () { metadataFolder.destroy() @@ -398,6 +365,26 @@ async function main () { }, supportBlock () { viewer.setBlockStateId(targetPos.offset(0, -1, 0), params.supportBlock ? 1 : 0) + }, + animationTick () { + const webgl = (viewer.world as WorldRendererWebgl).playgroundGetWebglData() + if (!webgl?.animation) { + setAnimationTick(0) + return + } + if (params.animationTick === -1) { + textureAnimation = new TextureAnimation(new Proxy({} as any, { + set (t, p, v) { + if (p === 'tick') { + setAnimationTick(v) + } + return true + } + }), webgl.animation, webgl.animation.framesCount) + } else { + setAnimationTick(params.animationTick) + textureAnimation = undefined + } } } @@ -435,7 +422,9 @@ async function main () { if (object === params) { if (property === 'camera') return onUpdate[property]?.() - applyChanges(property === 'metadata') + if (property !== 'animationTick') { + applyChanges(property === 'metadata') + } } else { applyChanges() } @@ -448,26 +437,36 @@ async function main () { update() } applyChanges(true) - gui.openAnimated() + // gui.openAnimated() }) - const animate = () => { + const animate = () => { } + const animate2 = () => { // if (controls) controls.update() // worldView.updatePosition(controls.target) viewer.update() viewer.render() - // window.requestAnimationFrame(animate) + window.requestAnimationFrame(animate2) } viewer.world.renderUpdateEmitter.addListener('update', () => { - animate() + // const frames = viewer.world.hasWithFrames ? viewer.world.hasWithFrames - 1 : 0; + const webgl = (viewer.world as WorldRendererWebgl).playgroundGetWebglData() + if (webgl?.animation) { + params.animationTick = -1 + animationController.show() + animationController.max(webgl.animation.framesCount) + } else { + animationController.hide() + } + onUpdate.animationTick() }) - animate() + animate2() // #region camera rotation param if (params.camera) { const [x, y] = params.camera.split(',') viewer.camera.rotation.set(parseFloat(x), parseFloat(y), 0, 'ZYX') - controls.update() + // controls.update() console.log(viewer.camera.rotation.x, parseFloat(x)) } const throttledCamQsUpdate = _.throttle(() => { @@ -475,16 +474,16 @@ async function main () { // params.camera = `${camera.rotation.x.toFixed(2)},${camera.rotation.y.toFixed(2)}` setQs() }, 200) - controls.addEventListener('change', () => { - throttledCamQsUpdate() - animate() - }) + // controls.addEventListener('change', () => { + // throttledCamQsUpdate() + // animate() + // }) // #endregion + let time = performance.now() const continuousUpdate = () => { - if (continuousRender) { - animate() - } + textureAnimation?.step(performance.now() - time) + time = performance.now() requestAnimationFrame(continuousUpdate) } continuousUpdate() @@ -499,7 +498,7 @@ async function main () { const { camera } = viewer viewer.camera.aspect = window.innerWidth / window.innerHeight viewer.camera.updateProjectionMatrix() - renderer.setSize(window.innerWidth, window.innerHeight) + nullRenderer.setSize(window.innerWidth, window.innerHeight) animate() } diff --git a/prismarine-viewer/examples/shared.ts b/prismarine-viewer/examples/shared.ts new file mode 100644 index 000000000..318396fae --- /dev/null +++ b/prismarine-viewer/examples/shared.ts @@ -0,0 +1,11 @@ +export type BlockFaceType = { + face: number + textureIndex: number + textureName?: string + tint?: [number, number, number] + isTransparent?: boolean +} + +export type BlockType = { + sides: BlockFaceType[] +} diff --git a/prismarine-viewer/examples/webglRenderer.ts b/prismarine-viewer/examples/webglRenderer.ts new file mode 100644 index 000000000..1047a50f2 --- /dev/null +++ b/prismarine-viewer/examples/webglRenderer.ts @@ -0,0 +1,215 @@ +import { generateSpiralMatrix } from 'flying-squid/dist/utils' +import { Viewer } from '../viewer/lib/viewer' +import { options } from '../../src/optionsStorage' +import { addNewStat } from './newStats' + +let worker + +declare const viewer: Viewer + +export const sendWorkerMessage = (message: any, transfer?: Transferable[]) => { + worker.postMessage(message, transfer) + // replacable by onmessage +} + +let allReceived = false +declare const customEvents +declare const bot +if (typeof customEvents !== 'undefined') { + customEvents.on('gameLoaded', () => { + const chunksExpected = generateSpiralMatrix(options.renderDistance) + let received = 0 + bot.on('chunkColumnLoad', (data) => { + received++ + if (received === chunksExpected.length) { + allReceived = true + // addBlocksSection('all', viewer.world.newChunks) + } + }) + }) +} + + +let isWaitingToUpload = false +export const addBlocksSection = (key, data) => { + sendWorkerMessage({ + type: 'addBlocksSection', data, key + }) + if (playground && !isWaitingToUpload) { + isWaitingToUpload = true + // viewer.waitForChunksToRender().then(() => { + // isWaitingToUpload = false + // sendWorkerMessage({ + // type: 'addBlocksSectionDone' + // }) + // }) + } +} + +export const loadFixtureSides = (json) => { + sendWorkerMessage({ + type: 'loadFixture', json + }) +} + +export const sendCameraToWorker = () => { + const cameraData = ['rotation', 'position'].reduce((acc, key) => { + acc[key] = ['x', 'y', 'z'].reduce((acc2, key2) => { + acc2[key2] = viewer.camera[key][key2] + return acc2 + }, {}) + return acc + }, {}) + sendWorkerMessage({ + type: 'camera', + camera: cameraData + }) +} + +export const removeBlocksSection = (key) => { + sendWorkerMessage({ + type: 'removeBlocksSection', key + }) +} + +let playground = false +export const initWebglRenderer = async (version: string, postRender = () => { }, playgroundModeInWorker = false, actuallyPlayground = false) => { + playground = actuallyPlayground + await new Promise(resolve => { + // console.log('viewer.world.material.map!.image', viewer.world.material.map!.image) + // viewer.world.material.map!.image.onload = () => { + // console.log(this.material.map!.image) + // resolve() + // } + viewer.world.renderUpdateEmitter.once('blockStatesDownloaded', resolve) + }) + const imageBlob = await fetch(`./textures/${version}.png`).then((res) => res.blob()) + const canvas = document.createElement('canvas') + canvas.width = window.innerWidth * window.devicePixelRatio + canvas.height = window.innerHeight * window.devicePixelRatio + document.body.appendChild(canvas) + canvas.id = 'viewer-canvas' + + const offscreen = canvas.transferControlToOffscreen() + + // replacable by initWebglRenderer + worker = new Worker('./webglRendererWorker.js') + addFpsCounters() + sendWorkerMessage({ + canvas: offscreen, + imageBlob, + isPlayground: playgroundModeInWorker, + FragShaderOverride: localStorage.FragShader + }, [offscreen]) + + let oldWidth = window.innerWidth + let oldHeight = window.innerHeight + let oldCamera = { + position: { x: 0, y: 0, z: 0 }, + rotation: { x: 0, y: 0, z: 0 } + } + let focused = true + window.addEventListener('focus', () => { + focused = true + sendWorkerMessage({ type: 'startRender' }) + }) + window.addEventListener('blur', () => { + focused = false + sendWorkerMessage({ type: 'stopRender' }) + }) + const mainLoop = () => { + requestAnimationFrame(mainLoop) + //@ts-ignore + if (!focused || window.stopRender) return + + if (oldWidth !== window.innerWidth || oldHeight !== window.innerHeight) { + oldWidth = window.innerWidth + oldHeight = window.innerHeight + sendWorkerMessage({ + type: 'resize', + newWidth: window.innerWidth * window.devicePixelRatio, + height: window.innerHeight * window.devicePixelRatio + }) + } + postRender() + // TODO! do it in viewer to avoid possible delays + if (actuallyPlayground && ['rotation', 'position'].some((key) => oldCamera[key] !== viewer.camera[key])) { + // TODO fix + for (const [key, val] of Object.entries(oldCamera)) { + for (const key2 of Object.keys(val)) { + oldCamera[key][key2] = viewer.camera[key][key2] + } + } + sendCameraToWorker() + } + } + + requestAnimationFrame(mainLoop) +} + +export const setAnimationTick = (tick: number, frames?: number) => { + sendWorkerMessage({ + type: 'animationTick', + tick, + frames + }) +} + +globalThis.exportFixture = () => { + worker.postMessage({ type: 'exportData' }) + const controller = new AbortController() + worker.addEventListener('message', async (e) => { + const receivedData = e.data.data; + console.log('received fixture') + // await new Promise(resolve => { + // setTimeout(resolve, 0) + // }) + try { + const a = document.createElement('a') + type Vec3 = [number, number, number] + type PlayTimeline = [pos: Vec3, rot: Vec3, time: number] + const vec3ToArr = (vec3: { x, y, z }) => [vec3.x, vec3.y, vec3.z] as Vec3 + // const dataObj = { + // ...receivedData, + // version: viewer.version, + // camera: [vec3ToArr(viewer.camera.position), vec3ToArr(viewer.camera.rotation)], + // playTimeline: [] as PlayTimeline[] + // } + // split into two chunks + const objectURL = URL.createObjectURL(new Blob([receivedData.sides.buffer], { type: 'application/octet-stream' })) + a.href = objectURL + a.download = 'fixture.bin' + a.click() + URL.revokeObjectURL(objectURL) + } finally { + controller.abort() + } + }, { signal: controller.signal }) +} + + +const addFpsCounters = () => { + const { updateText } = addNewStat('fps') + let prevTimeout + worker.addEventListener('message', (e) => { + if (e.data.type === 'fps') { + updateText(`FPS: ${e.data.fps}`) + if (prevTimeout) clearTimeout(prevTimeout); + prevTimeout = setTimeout(() => { + updateText('') + }, 1002) + } + }) + + const { updateText: updateText2 } = addNewStat('fps-main', 90, 0, 20) + let updates = 0 + const mainLoop = () => { + requestAnimationFrame(mainLoop) + updates++ + } + mainLoop() + setInterval(() => { + updateText2(`Main Loop: ${updates}`) + updates = 0 + }, 1000) +} diff --git a/prismarine-viewer/examples/webglRendererWorker.ts b/prismarine-viewer/examples/webglRendererWorker.ts new file mode 100644 index 000000000..40f145dbb --- /dev/null +++ b/prismarine-viewer/examples/webglRendererWorker.ts @@ -0,0 +1,601 @@ +import * as THREE from 'three' + +//@ts-ignore +import VertShader from './_VertexShader.vert' +//@ts-ignore +import FragShader from './_FragmentShader.frag' +import { BlockFaceType, BlockType } from './shared' +import * as tweenJs from '@tweenjs/tween.js' + +let allSides = [] as ([number, number, number, BlockFaceType] | undefined)[] +let allSidesAdded = 0 +let needsSidesUpdate = false + +let chunksArrIndexes = {} +let freeArrayIndexes = [] as [number, number][] +let rendering = true +let sidePositions +let updateCubes: (startIndex: any, forceUpdate?) => void +let lastNotUpdatedIndex +let lastNotUpdatedArrSize +let animationTick = 0; + +const updateCubesWhenAvailable = (pos) => { + if (updateCubes) { + updateCubes(pos) + } else { + setTimeout(updateCubesWhenAvailable, 100) + } +} + +const camera = new THREE.PerspectiveCamera(75, 1 / 1, 0.1, 1000) + +let renderedFrames = 0 +setInterval(() => { + // console.log('FPS:', renderedFrames) + postMessage({ type: 'fps', fps: renderedFrames }) + renderedFrames = 0 +}, 1000) + +const updateSize = (width, height) => { + camera.aspect = width / height + camera.updateProjectionMatrix() +} + + +export const initWebglRenderer = async (canvas: HTMLCanvasElement, imageBlob: ImageBitmapSource, isPlayground: boolean, FragShaderOverride?) => { + // isPlayground = false + // blockStates = blockStatesJson + const textureBitmap = await createImageBitmap(imageBlob) + const textureWidth = textureBitmap.width + const textureHeight = textureBitmap.height + + const gl = canvas.getContext('webgl2')! + + const program = createProgram(gl, VertShader, FragShaderOverride || FragShader) + + let CubeMesh = new Float32Array([ + -0.5, -0.5, -0.5, 0.0, 0.0, 0.0, // Bottom-let + 0.5, -0.5, -0.5, 1.0, 0.0, 0.0, // bottom-right + 0.5, 0.5, -0.5, 1.0, 1.0, 0.0, // top-right + 0.5, 0.5, -0.5, 1.0, 1.0, 0.0, // top-right + -0.5, 0.5, -0.5, 0.0, 1.0, 0.0, // top-let + -0.5, -0.5, -0.5, 0.0, 0.0, 0.0, // bottom-let + // ront ace + -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, // bottom-let + 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, // top-right + 0.5, -0.5, 0.5, 1.0, 0.0, 1.0, // bottom-right + 0.5, 0.5, 0.5, 1.0, 1.0, 1.0,// top-right + -0.5, -0.5, 0.5, 0.0, 0.0, 1.0,// bottom-let + -0.5, 0.5, 0.5, 0.0, 1.0, 1.0,// top-let + // Let ace + -0.5, 0.5, 0.5, 1.0, 0.0, 2.0,// top-right + -0.5, -0.5, -0.5, 0.0, 1.0, 2.0,// bottom-let + -0.5, 0.5, -0.5, 1.0, 1.0, 2.0,// top-let + -0.5, -0.5, -0.5, 0.0, 1.0, 2.0,// bottom-let + -0.5, 0.5, 0.5, 1.0, 0.0, 2.0, // top-right + -0.5, -0.5, 0.5, 0.0, 0.0, 2.0,// bottom-right + // Right ace + 0.5, 0.5, 0.5, 1.0, 0.0, 3.0,// top-let + 0.5, 0.5, -0.5, 1.0, 1.0, 3.0,// top-right + 0.5, -0.5, -0.5, 0.0, 1.0, 3.0,// bottom-right + 0.5, -0.5, -0.5, 0.0, 1.0, 3.0,// bottom-right + 0.5, -0.5, 0.5, 0.0, 0.0, 3.0,// bottom-let + 0.5, 0.5, 0.5, 1.0, 0.0, 3.0, // top-let + // Bottom ace + -0.5, -0.5, -0.5, 0.0, 1.0, 4.0,// top-right + 0.5, -0.5, 0.5, 1.0, 0.0, 4.0,// bottom-let + 0.5, -0.5, -0.5, 1.0, 1.0, 4.0,// top-let + 0.5, -0.5, 0.5, 1.0, 0.0, 4.0, // bottom-let + -0.5, -0.5, -0.5, 0.0, 1.0, 4.0, // top-right + -0.5, -0.5, 0.5, 0.0, 0.0, 4.0, // bottom-right + // Top ace + -0.5, 0.5, -0.5, 0.0, 1.0, 5.0,// top-let + 0.5, 0.5, -0.5, 1.0, 1.0, 5.0,// top-right + 0.5, 0.5, 0.5, 1.0, 0.0, 5.0,// bottom-right + 0.5, 0.5, 0.5, 1.0, 0.0, 5.0,// bottom-right + -0.5, 0.5, 0.5, 0.0, 0.0, 5.0,// bottom-let + -0.5, 0.5, -0.5, 0.0, 1.0, 5.0// top-let + ]) + + let SideMesh = new Float32Array([ + -0.5, -0.5, -0.5, 0.0, 0.0, // Bottom-let + 0.5, -0.5, -0.5, 1.0, 0.0, // bottom-right + -0.5, 0.5, -0.5, 0.0, 1.0, // top-let + 0.5, 0.5, -0.5, 1.0, 1.0, // top-right + // 0.5, 0.5, -0.5, 1.0, 1.0, // top-right + // -0.5, -0.5, -0.5, 0.0, 0.0, // bottom-let + // ront ace + ]) + + + + let NumberOfCube = isPlayground ? 10_000 : 16_000_000 + + sidePositions = new Float32Array(NumberOfCube * 3 * 6) + let sideTextureIndices = new Float32Array(NumberOfCube * 1 * 6); + let sideIndexes = new Float32Array(NumberOfCube * 1 * 6); + let sideBiomeColor = new Float32Array(NumberOfCube * 3 * 6); + + + // write random coordinates to cube positions xyz ten cubes; + if (isPlayground) { + for (let i = 0; i < NumberOfCube * 18; i += 18) { + + sidePositions[i] = Math.floor(Math.random() * 1000) - 500; + sidePositions[i + 1] = Math.floor(Math.random() * 1000) - 500; + sidePositions[i + 2] = Math.floor(Math.random() * 100) - 100; + + sideBiomeColor[i] = (Math.random()); + sideBiomeColor[i + 1] = (Math.random()); + sideBiomeColor[i + 2] = (Math.random()); + for (let j = 1; j <= 6; j++) { + + if (j != 6) { + sidePositions[j * 3 + i] = sidePositions[i] + sidePositions[j * 3 + i + 1] = sidePositions[i + 1] + sidePositions[j * 3 + i + 2] = sidePositions[i + 2] + + sideBiomeColor[j * 3 + i] = sideBiomeColor[i] + sideBiomeColor[j * 3 + i + 1] = sideBiomeColor[i + 1] + sideBiomeColor[j * 3 + i + 2] = sideBiomeColor[i + 2] + } + + sideIndexes[i / 3 + j - 1] = j - 1; + sideTextureIndices[i / 3 + j - 1] = Math.floor(Math.random() * 800); + //sideTextureIndices[i / 3 + j - 1] = 1; + } + + } + + } + let VAO = gl.createVertexArray(); + + + let instanceVBO = gl.createBuffer(); + let instanceTextureID = gl.createBuffer(); + let instanceBiomeColor = gl.createBuffer(); + let instanceCubeSide = gl.createBuffer(); + + gl.bindBuffer(gl.ARRAY_BUFFER, instanceVBO); + gl.bufferData(gl.ARRAY_BUFFER, sidePositions, gl.DYNAMIC_DRAW); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + + gl.bindBuffer(gl.ARRAY_BUFFER, instanceTextureID); + gl.bufferData(gl.ARRAY_BUFFER, sideTextureIndices, gl.DYNAMIC_DRAW); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + + gl.bindBuffer(gl.ARRAY_BUFFER, instanceBiomeColor); + gl.bufferData(gl.ARRAY_BUFFER, sideBiomeColor, gl.DYNAMIC_DRAW); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + + gl.bindBuffer(gl.ARRAY_BUFFER, instanceCubeSide); + gl.bufferData(gl.ARRAY_BUFFER, sideIndexes, gl.DYNAMIC_DRAW); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + VAO = gl.createVertexArray(); + let VBO = gl.createBuffer(); + // let VBO_sides = gl.createBuffer(); + //EBO = gl.createBuffer(); + + gl.bindVertexArray(VAO); + gl.bindBuffer(gl.ARRAY_BUFFER, VBO) + // gl.bindBuffer(gl.ARRAY_BUFFER, VBO_sides) + gl.bufferData(gl.ARRAY_BUFFER, SideMesh, gl.STATIC_DRAW) + + gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 5 * 4, 0) + gl.enableVertexAttribArray(0) + + gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 5 * 4, 3 * 4) + gl.enableVertexAttribArray(1) + + gl.enableVertexAttribArray(2); + gl.bindBuffer(gl.ARRAY_BUFFER, instanceCubeSide); + gl.vertexAttribPointer(2, 1, gl.FLOAT, false, 4, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + gl.vertexAttribDivisor(2, 1); + + gl.enableVertexAttribArray(3); + gl.bindBuffer(gl.ARRAY_BUFFER, instanceVBO); + gl.vertexAttribPointer(3, 3, gl.FLOAT, false, 3 * 4, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + gl.vertexAttribDivisor(3, 1); + + gl.enableVertexAttribArray(4); + gl.bindBuffer(gl.ARRAY_BUFFER, instanceTextureID); + gl.vertexAttribPointer(4, 1, gl.FLOAT, false, 4 * 1, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + gl.vertexAttribDivisor(4, 1); + + gl.enableVertexAttribArray(6); + gl.bindBuffer(gl.ARRAY_BUFFER, instanceBiomeColor); + gl.vertexAttribPointer(6, 3, gl.FLOAT, false, 3 * 4, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + gl.vertexAttribDivisor(6, 1); + + updateCubes = (startIndex, forceUpdate) => { + // up2 + const newSides = allSides.slice(startIndex, lastNotUpdatedArrSize ? startIndex + lastNotUpdatedArrSize : undefined) + newSides.sort((a, b) => { + if (!a || !b) return 0 + const getScore = (b: BlockFaceType) => b.isTransparent ? 1 : 0 + return getScore(a[3]) - getScore(b[3]) + }) + globalThis.allSidesSize = allSides.length + sidePositions = new Float32Array(newSides.length * 3) + sideTextureIndices = new Float32Array(newSides.length * 1); + sideIndexes = new Float32Array(newSides.length * 1); + sideBiomeColor = new Float32Array(newSides.length * 3); + for (let i = 0; i < newSides.length * 3; i += 3) { + const newSide = newSides[i / 3]; + if (!newSide) continue + sidePositions[i] = newSide[0] + sidePositions[i + 1] = newSide[1] + sidePositions[i + 2] = newSide[2] + const block = newSide[3] as BlockFaceType + if (block.tint) { + const [r, g, b] = block.tint + sideBiomeColor[i] = r + sideBiomeColor[i + 1] = g + sideBiomeColor[i + 2] = b + } else { + sideBiomeColor[i] = 1 + sideBiomeColor[i + 1] = 1 + sideBiomeColor[i + 2] = 1 + } + sideTextureIndices[i / 3] = block.textureIndex + sideIndexes[i / 3] = block.face + } + + + // startIndex = 0 // TODO! + console.log('startIndex', startIndex, sidePositions.length, allSides.length) + const prepareBuffersUpdate = allSides.length > NumberOfCube || globalThis.testUpdate + globalThis.testUpdate = false + if (prepareBuffersUpdate) { + NumberOfCube += 1_000_000 + updateCubes(0, true) + return + } + globalThis.NumberOfCube = NumberOfCube + + const supplyData = (data, step) => { + if (forceUpdate) { + globalThis.updatedBufferSize = NumberOfCube + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(NumberOfCube * step), gl.STATIC_DRAW); + } + gl.bufferSubData(gl.ARRAY_BUFFER, startIndex * 4 * step, data); // update buffer content + const error = gl.getError() + if (error) throw new Error("SUBDATA ERROR") + gl.bindBuffer(gl.ARRAY_BUFFER, null); + } + + gl.bindBuffer(gl.ARRAY_BUFFER, instanceVBO); + supplyData(sidePositions, 3) + + gl.bindBuffer(gl.ARRAY_BUFFER, instanceTextureID); + supplyData(sideTextureIndices, 1) + + gl.bindBuffer(gl.ARRAY_BUFFER, instanceBiomeColor); + supplyData(sideBiomeColor, 3) + + gl.bindBuffer(gl.ARRAY_BUFFER, instanceCubeSide); + supplyData(sideIndexes, 1) + + allSidesAdded = allSides.length + needsSidesUpdate = true + lastNotUpdatedArrSize = undefined + } + + globalThis.updateCubes = updateCubes + globalThis.resetHalfScene = () => { + for (let i = 0; i < allSides.length / 2; i++) { + allSides[i] = undefined + } + lastNotUpdatedIndex = 0 + lastNotUpdatedArrSize = allSides.length / 2 + updateCubes(0) + } + const cleanupFirstChunks = () => { + allSides = [] + gl.bindBuffer(gl.ARRAY_BUFFER, instanceVBO); + // empty the buffer + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(NumberOfCube * 3), gl.STATIC_DRAW); // todo + gl.bindBuffer(gl.ARRAY_BUFFER, null); + + gl.bindBuffer(gl.ARRAY_BUFFER, instanceTextureID); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(NumberOfCube * 3), gl.STATIC_DRAW); // todo + // gl.bufferSubData(gl.ARRAY_BUFFER, startIndex * 4, cubeTextureIndices); // update buffer content + gl.bindBuffer(gl.ARRAY_BUFFER, null); + } + + fullReset = () => { + cleanupFirstChunks() + lastNotUpdatedIndex = undefined + lastNotUpdatedArrSize = undefined + } + + + + //gl.bindBuffer(gl.ARRAY_BUFFER, null); + //gl.bindVertexArray(null) + + // viewer.world.updateTexturesData() + // await new Promise(resolve => { + // // console.log('viewer.world.material.map!.image', viewer.world.material.map!.image) + // // viewer.world.material.map!.image.onload = () => { + // // console.log(this.material.map!.image) + // // resolve() + // // } + // viewer.world.renderUpdateEmitter.once('blockStatesDownloaded', resolve) + // }) + // const names = Object.keys(viewer.world.downloadedBlockStatesData) + + let texture1 = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture1); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, textureWidth, textureHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, textureBitmap); + + gl.useProgram(program) + + gl.uniform1i(gl.getUniformLocation(program, "texture1"), 0); + gl.uniform1i(gl.getUniformLocation(program, "texture2"), 1); + + + gl.enable(gl.DEPTH_TEST) + gl.frontFace(gl.CCW) + gl.enable(gl.CULL_FACE) + gl.enable(gl.BLEND) + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + + + //gl.generateMipmap() + //gl.enable(gl) + //gl.clearColor(0, 0, 0, 1) + //gl.clear(gl.COLOR_BUFFER_BIT) + camera.up = new THREE.Vector3(0, 1, 0) + + let ViewUniform = gl.getUniformLocation(program, "view") + let ProjectionUniform = gl.getUniformLocation(program, "projection") + let TickUniform = gl.getUniformLocation(program, "tick") + + gl.cullFace(gl.FRONT) + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, texture1); + + gl.bindVertexArray(VAO) + gl.useProgram(program) + updateSize(gl.canvas.width, gl.canvas.height) + const renderLoop = (performance) => { + requestAnimationFrame(renderLoop) + if (!rendering && !needsSidesUpdate) return + // gl.canvas.width = window.innerWidth * window.devicePixelRatio + // gl.canvas.height = window.innerHeight * window.devicePixelRatio + if (newWidth || newHeight) { + gl.canvas.width = newWidth ?? gl.canvas.width + gl.canvas.height = newHeight ?? gl.canvas.height + newWidth = undefined + newHeight = undefined + updateSize(gl.canvas.width, gl.canvas.height) + + gl.viewport(0, 0, gl.canvas.width, gl.canvas.height) + } + + + gl.clearColor(0.6784313725490196, 0.8470588235294118, 0.9019607843137255, 1); + gl.clear(gl.COLOR_BUFFER_BIT) + gl.clear(gl.DEPTH_BUFFER_BIT) + + + tweenJs.update() + camera.updateMatrix() + gl.uniformMatrix4fv(ViewUniform, false, camera.matrix.invert().elements); + gl.uniformMatrix4fv(ProjectionUniform, false, camera.projectionMatrix.elements); + gl.uniform1i(TickUniform, animationTick); + + if (!globalThis.stopRendering) { + gl.drawArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, (isPlayground ? NumberOfCube * 6 : allSidesAdded)); + needsSidesUpdate = false + } + + renderedFrames++ + } + requestAnimationFrame(renderLoop) + + // gl.deleteVertexArray(VAO); + // gl.deleteBuffer(VBO) + // gl.deleteBuffer(EBO) + // gl.deleteProgram(program) + + return canvas +} + +let fullReset + +const createProgram = (gl: WebGL2RenderingContext, vertexShader: string, fragmentShader: string) => { + const createShader = (gl: WebGL2RenderingContext, type: number, source: string) => { + const shaderName = type === gl.VERTEX_SHADER ? 'vertex' : 'fragment' + const shader = gl.createShader(type)! + gl.shaderSource(shader, source) + gl.compileShader(shader) + + const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS) + if (!success) { + const info = gl.getShaderInfoLog(shader) + gl.deleteShader(shader) + throw new Error(`Shader ${shaderName} compile error: ` + info) + } + return shader + } + + + + const program = gl.createProgram()! + gl.attachShader(program, createShader(gl, gl.VERTEX_SHADER, vertexShader)!) + gl.attachShader(program, createShader(gl, gl.FRAGMENT_SHADER, fragmentShader)!) + gl.linkProgram(program) + const linkSuccess = gl.getProgramParameter(program, gl.LINK_STATUS) + if (!linkSuccess) { + const info = gl.getProgramInfoLog(program) + gl.deleteProgram(program) + throw new Error('Program link error: ' + info) + } + return program +} + +let started = false +let newWidth: number | undefined +let newHeight: number | undefined +let autoTickUpdate = undefined as number | undefined +onmessage = function (e) { + if (!started) { + started = true + initWebglRenderer(e.data.canvas, e.data.imageBlob, e.data.isPlayground, e.data.FragShaderOverride) + return + } + if (e.data.type === 'startRender') { + rendering = true + } + if (e.data.type === 'stopRender') { + rendering = false + } + if (e.data.type === 'resize') { + newWidth = e.data.newWidth + newHeight = e.data.newHeight + } + if (e.data.type === 'addBlocksSection') { + const currentLength = allSides.length; + // in: object - name, out: [x, y, z, name] + const newData = Object.entries(e.data.data.blocks).flatMap(([key, value]) => { + const [x, y, z] = key.split(',').map(Number) + const block = value as BlockType + return block.sides.map((side) => { + return [x, y, z, side] as [number, number, number, BlockFaceType] + }) + }) + // find freeIndexes if possible + const freeArea = freeArrayIndexes.find(([startIndex, endIndex]) => endIndex - startIndex >= newData.length) + if (freeArea) { + const [startIndex, endIndex] = freeArea + allSides.splice(startIndex, newData.length, ...newData) + lastNotUpdatedIndex ??= startIndex + const freeAreaIndex = freeArrayIndexes.indexOf(freeArea) + freeArrayIndexes[freeAreaIndex] = [startIndex + newData.length, endIndex] + if (freeArrayIndexes[freeAreaIndex][0] >= freeArrayIndexes[freeAreaIndex][1]) { + freeArrayIndexes.splice(freeAreaIndex, 1) + // todo merge + } + lastNotUpdatedArrSize = newData.length + console.log('using free area', freeArea) + } + + chunksArrIndexes[e.data.key] = [currentLength, currentLength + newData.length] + allSides.push(...newData) + lastNotUpdatedIndex ??= currentLength + // updateCubes?.(currentLength) + } + if (e.data.type === 'addBlocksSectionDone') { + // if (pendingUpdate) { + // console.log('Already pending') + // return + // } + updateCubesWhenAvailable(lastNotUpdatedIndex) + lastNotUpdatedIndex = undefined + lastNotUpdatedArrSize = undefined + } + if (e.data.type === 'removeBlocksSection') { + // fill data with 0 + const [startIndex, endIndex] = chunksArrIndexes[e.data.key] + for (let i = startIndex; i < endIndex; i++) { + allSides[i] = undefined + } + lastNotUpdatedArrSize = endIndex - startIndex + updateCubes(startIndex) + + // freeArrayIndexes.push([startIndex, endIndex]) + + // // merge freeArrayIndexes TODO + // if (freeArrayIndexes.at(-1)[0] === freeArrayIndexes.at(-2)?.[1]) { + // const [startIndex, endIndex] = freeArrayIndexes.pop()! + // const [startIndex2, endIndex2] = freeArrayIndexes.pop()! + // freeArrayIndexes.push([startIndex2, endIndex]) + // } + } + if (e.data.type === 'camera') { + camera.rotation.set(e.data.camera.rotation.x, e.data.camera.rotation.y, e.data.camera.rotation.z, 'ZYX') + // camera.position.set(e.data.camera.position.x, e.data.camera.position.y, e.data.camera.position.z) + if (camera.position.x === 0 && camera.position.y === 0 && camera.position.z === 0) { + // initial camera position + camera.position.set(e.data.camera.position.x, e.data.camera.position.y, e.data.camera.position.z) + } else { + new tweenJs.Tween(camera.position).to({ x: e.data.camera.position.x, y: e.data.camera.position.y, z: e.data.camera.position.z }, 50).start() + } + } + if (e.data.type === 'animationTick') { + if (e.data.frames <= 0) { + autoTickUpdate = undefined + animationTick = 0 + return + } + if (e.data.tick === -1) { + autoTickUpdate = e.data.frames + } else { + autoTickUpdate = undefined + animationTick = e.data.tick % 20 // todo update automatically in worker + } + } + if (e.data.type === 'fullReset') { + fullReset() + } + if (e.data.type === 'exportData') { + const exported = exportData(); + postMessage({ type: 'exportData', data: exported }, undefined, [exported.sides.buffer]) + } + if (e.data.type === 'loadFixture') { + // allSides = e.data.json.map(([x, y, z, face, textureIndex]) => { + // return [x, y, z, { face, textureIndex }] as [number, number, number, BlockFaceType] + // }) + const dataSize = e.data.json.length / 5 + for (let i = 0; i < e.data.json.length; i += 5) { + allSides.push([e.data.json[i], e.data.json[i + 1], e.data.json[i + 2], { face: e.data.json[i + 3], textureIndex: e.data.json[i + 4] }]) + } + updateCubesWhenAvailable(0) + } +} + +globalThis.testDuplicates = () => { + const duplicates = allSides.filter((arr, index, self) => { + return index !== self.findIndex((t) => { + return t[0] === arr[0] && t[1] === arr[1] && t[2] === arr[2] && t[3].face === arr[3].face + }) + }) + console.log('duplicates', duplicates) +} + +const exportData = () => { + // Calculate the total length of the final array + const totalLength = allSides.length * 5; + + // Create a new Int16Array with the total length + const flatData = new Int16Array(totalLength); + + // Fill the flatData array + for (let i = 0; i < allSides.length; i++) { + const [x, y, z, side] = allSides[i]; + flatData.set([x, y, z, side.face, side.textureIndex], i * 5); + } + + return { sides: flatData }; +} + +setInterval(() => { + if (autoTickUpdate) { + animationTick = (animationTick + 1) % autoTickUpdate; + } +}, 1000 / 20) diff --git a/prismarine-viewer/globals.d.ts b/prismarine-viewer/globals.d.ts new file mode 100644 index 000000000..c2cb5532a --- /dev/null +++ b/prismarine-viewer/globals.d.ts @@ -0,0 +1,9 @@ +type StringKeys = Extract + +interface ObjectConstructor { + keys (obj: T): Array> + entries (obj: T): Array<[StringKeys, T[keyof T]]> + // todo review https://stackoverflow.com/questions/57390305/trying-to-get-fromentries-type-right + fromEntries> (obj: T): Record + assign, K extends Record> (target: T, source: K): asserts target is T & K +} diff --git a/prismarine-viewer/package.json b/prismarine-viewer/package.json index 529aa9ae4..6942bb876 100644 --- a/prismarine-viewer/package.json +++ b/prismarine-viewer/package.json @@ -19,6 +19,7 @@ }, "dependencies": { "@tweenjs/tween.js": "^20.0.3", + "live-server": "^1.2.2", "assert": "^2.0.0", "buffer": "^6.0.3", "canvas": "^2.11.2", diff --git a/prismarine-viewer/playground.html b/prismarine-viewer/playground.html index fd92009a4..c3902f40d 100644 --- a/prismarine-viewer/playground.html +++ b/prismarine-viewer/playground.html @@ -31,6 +31,7 @@ +