From 248d5a8c00cf3a4772ab313a3151ce560e94e979 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Tue, 2 Apr 2024 11:22:05 +0300 Subject: [PATCH 0001/1097] add new hills generator --- package.json | 2 +- pnpm-lock.yaml | 101 ++++++++++++++++++++----------------- scripts/esbuildPlugins.mjs | 2 +- src/optionsStorage.ts | 4 +- 4 files changed, 60 insertions(+), 49 deletions(-) diff --git a/package.json b/package.json index 881be9cc..3fcae0b4 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "esbuild": "^0.19.3", "esbuild-plugin-polyfill-node": "^0.3.0", "express": "^4.18.2", - "flying-squid": "npm:@zardoy/flying-squid@^0.0.15", + "flying-squid": "zardoy/space-squid#custom-generator", "fs-extra": "^11.1.1", "google-drive-browserfs": "github:zardoy/browserfs#google-drive", "iconify-icon": "^1.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 483f0277..7623c4ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -85,8 +85,8 @@ importers: specifier: ^4.18.2 version: 4.18.2 flying-squid: - specifier: npm:@zardoy/flying-squid@^0.0.15 - version: /@zardoy/flying-squid@0.0.15 + specifier: zardoy/space-squid#custom-generator + version: github.com/zardoy/space-squid/2c396a9405025f5aed3d1241beccfec2a8f3acbc fs-extra: specifier: ^11.1.1 version: 11.1.1 @@ -5692,46 +5692,6 @@ packages: tslib: 1.14.1 dev: true - /@zardoy/flying-squid@0.0.15: - resolution: {integrity: sha512-VooP9XuzNQVL3y0zlaU5wStRm1vfQIXAzVNHuvMoMgyIyOiD7A59QzVZT93GAoTyUBHTwqweXMPQftjywUy62A==} - engines: {node: '>=8'} - hasBin: true - dependencies: - change-case: 4.1.2 - colors: 1.4.0 - diamond-square: github.com/zardoy/diamond-square/915fce8e27fe8eb45464d89b9563956afa4f7687 - emit-then: 2.0.0 - event-promise: 0.0.1 - exit-hook: 2.2.1 - flatmap: 0.0.3 - long: 5.2.3 - minecraft-data: 3.62.0 - minecraft-protocol: github.com/zardoy/minecraft-protocol/2c14a686bfe7cbd9a5c87b629b402295ee86219f - mkdirp: 2.1.6 - moment: 2.30.1 - needle: 2.9.1 - node-gzip: 1.1.2 - node-rsa: 1.1.1 - prismarine-chunk: 1.35.0(minecraft-data@3.62.0) - prismarine-entity: 2.3.1 - prismarine-item: 1.14.0 - 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 - random-seed: 0.3.0 - range: 0.0.3 - readline: 1.3.0 - typed-emitter: 1.4.0 - uuid-1345: 1.0.2 - vec3: 0.1.8 - yaml: 2.4.1 - yargs: 17.7.2 - transitivePeerDependencies: - - encoding - - supports-color - dev: false - /@zardoy/react-util@0.2.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-glABtx54mh4XSaK6BNALWE3mlshPjcPwPsRj/GnOXEA7WJY/6n43iJoukbaYF3758mGZRU5Fq6gklyFjBg0yHQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -12483,7 +12443,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 @@ -13832,6 +13792,10 @@ packages: semver: 7.6.0 dev: true + /simplex-noise@4.0.1: + resolution: {integrity: sha512-zl/+bdSqW7HJOQ0oDbxrNYaF4F5ik0i7M6YOYmEoIJNtg16NpvWaTTM1Y7oV/7T0jFljawLgYPS81Uu2rsfo1A==} + dev: false + /sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} dev: true @@ -15929,7 +15893,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 +16001,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'} @@ -16058,3 +16022,48 @@ packages: - supports-color - utf-8-validate dev: false + + github.com/zardoy/space-squid/2c396a9405025f5aed3d1241beccfec2a8f3acbc: + resolution: {tarball: https://codeload.github.com/zardoy/space-squid/tar.gz/2c396a9405025f5aed3d1241beccfec2a8f3acbc} + name: '@zardoy/flying-squid' + version: 0.0.0-dev + engines: {node: '>=8'} + hasBin: true + prepare: true + requiresBuild: true + dependencies: + change-case: 4.1.2 + colors: 1.4.0 + diamond-square: github.com/zardoy/diamond-square/915fce8e27fe8eb45464d89b9563956afa4f7687 + emit-then: 2.0.0 + event-promise: 0.0.1 + exit-hook: 2.2.1 + flatmap: 0.0.3 + long: 5.2.3 + minecraft-data: 3.62.0 + minecraft-protocol: github.com/zardoy/minecraft-protocol/2c14a686bfe7cbd9a5c87b629b402295ee86219f + mkdirp: 2.1.6 + moment: 2.30.1 + needle: 2.9.1 + node-gzip: 1.1.2 + node-rsa: 1.1.1 + prismarine-chunk: 1.35.0(minecraft-data@3.62.0) + prismarine-entity: 2.3.1 + prismarine-item: 1.14.0 + 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/6ae6f009d38460de284f8c226c665f04cbad9465 + random-seed: 0.3.0 + range: 0.0.3 + readline: 1.3.0 + simplex-noise: 4.0.1 + typed-emitter: 1.4.0 + uuid-1345: 1.0.2 + vec3: 0.1.8 + yaml: 2.4.1 + yargs: 17.7.2 + transitivePeerDependencies: + - encoding + - supports-color + dev: false diff --git a/scripts/esbuildPlugins.mjs b/scripts/esbuildPlugins.mjs index 95d88b8e..259db7e1 100644 --- a/scripts/esbuildPlugins.mjs +++ b/scripts/esbuildPlugins.mjs @@ -220,7 +220,7 @@ const plugins = [ const { resolveDir } = pluginData //@ts-ignore const [, userPath, skipFiles] = /^esbuild-import-glob\(path:(.+),skipFiles:(.+)\)+$/g.exec(path) - const files = (await fs.promises.readdir(join(resolveDir, userPath))).filter(f => !skipFiles.includes(f)) + const files = (await fs.promises.readdir(join(resolveDir, userPath))).filter(f => !skipFiles.includes(f)).filter(x => x.endsWith('.js')) return { contents: `module.exports = { ${files.map(f => `'${f}': require('./${join(userPath, f)}')`).join(',')} }`, resolveDir, diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index 8490053c..dc3a94ac 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -61,7 +61,9 @@ const defaultOptions = { excludeCommunicationDebugEvents: [], preventDevReloadWhilePlaying: false, numWorkers: 4, - localServerOptions: {} as any, + localServerOptions: { + gameMode: 1, + } as any, preferLoadReadonly: false, disableLoadPrompts: false, guestUsername: 'guest', From f2803b9b3ac399dc84802e6041732e59bd52fe84 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 6 Apr 2024 15:22:50 +0300 Subject: [PATCH 0002/1097] remove alias set --- .github/workflows/preview.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 2a5f5665..02598446 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -42,10 +42,6 @@ jobs: with: run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} id: deploy - - name: Set deployment alias - # only if on branch next - if: github.ref == 'refs/heads/next' - run: vercel alias set ${{ steps.deploy.outputs.stdout }} ${{ secrets.TEST_PREVIEW_DOMAIN }} --token=${{ secrets.VERCEL_TOKEN }} - uses: mshick/add-pr-comment@v2 with: message: | From b89aab72d0a92d8129024f5d3c8168b59befa633 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Tue, 9 Apr 2024 03:28:55 +0300 Subject: [PATCH 0003/1097] ci: text aliases --- .github/workflows/next-deploy.yml | 8 +++++++- scripts/githubActions.mjs | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 scripts/githubActions.mjs diff --git a/.github/workflows/next-deploy.yml b/.github/workflows/next-deploy.yml index 93c46aeb..d7d4d322 100644 --- a/.github/workflows/next-deploy.yml +++ b/.github/workflows/next-deploy.yml @@ -2,6 +2,7 @@ name: Vercel Deploy Next env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + ALIASES: ${{ vars.ALIASES }} on: push: branches: @@ -30,8 +31,13 @@ jobs: with: run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} id: deploy + - name: Get deployment alias + run: node scripts/githubActions.mjs getAlias + - run: echo $OUTPUT + env: + OUTPUT: ${{ steps.repos.outputs.alias }} - name: Set deployment alias - run: vercel alias set ${{ steps.deploy.outputs.stdout }} ${{ secrets.TEST_PREVIEW_DOMAIN }} --token=${{ secrets.VERCEL_TOKEN }} + run: vercel alias set ${{ steps.deploy.outputs.stdout }} ${{ secrets.TEST_PREVIEW_DOMAIN }} --token=${{ secrets.VERCEL_TOKEN }} --scope=zaro # - uses: mshick/add-pr-comment@v2 # with: # message: | diff --git a/scripts/githubActions.mjs b/scripts/githubActions.mjs new file mode 100644 index 00000000..f392da55 --- /dev/null +++ b/scripts/githubActions.mjs @@ -0,0 +1,23 @@ +const fns = { + async getAlias () { + const aliasesRaw = process.env.ALIASES + if (!aliasesRaw) throw new Error('No aliases found') + const aliases = aliasesRaw.split('\n').map((x) => x.search('=')) + const githubActionsPull = process.env.GITHUB_REF.match(/refs\/pull\/(\d+)\/merge/) + if (!githubActionsPull) throw new Error(`Not a pull request, got ${process.env.GITHUB_REF}`) + const prNumber = githubActionsPull[1] + const alias = aliases.find((x) => x[0] === prNumber) + if (alias) { + console.log('Found alias', alias[1]) + // set github output + console.log(`::set-output name=alias::${alias[1]}`) + } + } +} + +const fn = fns[process.argv[2]] +if (fn) { + fn() +} else { + console.error('Function not found') +} From ac3448c74502e6e23c357c1614bc81dab3beb354 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Tue, 9 Apr 2024 03:47:03 +0300 Subject: [PATCH 0004/1097] ci: set custom mcraft aliases for PRs! (#99) --- .github/workflows/next-deploy.yml | 5 ----- .github/workflows/preview.yml | 7 +++++++ scripts/githubActions.mjs | 15 ++++++++++++--- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/.github/workflows/next-deploy.yml b/.github/workflows/next-deploy.yml index d7d4d322..7ee33ac0 100644 --- a/.github/workflows/next-deploy.yml +++ b/.github/workflows/next-deploy.yml @@ -31,11 +31,6 @@ jobs: with: run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} id: deploy - - name: Get deployment alias - run: node scripts/githubActions.mjs getAlias - - run: echo $OUTPUT - env: - OUTPUT: ${{ steps.repos.outputs.alias }} - name: Set deployment alias run: vercel alias set ${{ steps.deploy.outputs.stdout }} ${{ secrets.TEST_PREVIEW_DOMAIN }} --token=${{ secrets.VERCEL_TOKEN }} --scope=zaro # - uses: mshick/add-pr-comment@v2 diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 02598446..44c55480 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -2,6 +2,7 @@ name: Vercel Deploy Preview env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + ALIASES: ${{ vars.ALIASES }} on: issue_comment: types: [created] @@ -48,3 +49,9 @@ jobs: Deployed to Vercel Preview: ${{ steps.deploy.outputs.stdout }} [Playground](${{ steps.deploy.outputs.stdout }}/playground.html) [Storybook](${{ steps.deploy.outputs.stdout }}/storybook/) + - name: Get deployment alias + run: node scripts/githubActions.mjs getAlias + id: alias + - name: Set deployment alias + if: ${{ steps.alias.outputs.alias != '' }} + run: vercel alias set ${{ steps.deploy.outputs.stdout }} ${{ steps.alias.outputs.alias }} --token=${{ secrets.VERCEL_TOKEN }} --scope=zaro diff --git a/scripts/githubActions.mjs b/scripts/githubActions.mjs index f392da55..ac218f56 100644 --- a/scripts/githubActions.mjs +++ b/scripts/githubActions.mjs @@ -1,20 +1,29 @@ +//@ts-check +import fs from 'fs' +import os from 'os' + const fns = { async getAlias () { const aliasesRaw = process.env.ALIASES if (!aliasesRaw) throw new Error('No aliases found') - const aliases = aliasesRaw.split('\n').map((x) => x.search('=')) + const aliases = aliasesRaw.split('\n').map((x) => x.split('=')) const githubActionsPull = process.env.GITHUB_REF.match(/refs\/pull\/(\d+)\/merge/) if (!githubActionsPull) throw new Error(`Not a pull request, got ${process.env.GITHUB_REF}`) const prNumber = githubActionsPull[1] const alias = aliases.find((x) => x[0] === prNumber) if (alias) { - console.log('Found alias', alias[1]) // set github output - console.log(`::set-output name=alias::${alias[1]}`) + setOutput('alias', alias[1]) } } } +function setOutput(key, value) { + // Temporary hack until core actions library catches up with github new recommendations + const output = process.env['GITHUB_OUTPUT'] + fs.appendFileSync(output, `${key}=${value}${os.EOL}`) +} + const fn = fns[process.argv[2]] if (fn) { fn() From 0b15ac9ba099c5e1183003efdbb5576e06d531bb Mon Sep 17 00:00:00 2001 From: Vitaly Date: Tue, 9 Apr 2024 15:59:35 +0300 Subject: [PATCH 0005/1097] ci: improve aliases set --- .github/workflows/preview.yml | 6 +++++- scripts/githubActions.mjs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 44c55480..cdefd2e2 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -49,9 +49,13 @@ jobs: Deployed to Vercel Preview: ${{ steps.deploy.outputs.stdout }} [Playground](${{ steps.deploy.outputs.stdout }}/playground.html) [Storybook](${{ steps.deploy.outputs.stdout }}/storybook/) + - run: git checkout next scripts/githubActions.mjs - name: Get deployment alias run: node scripts/githubActions.mjs getAlias id: alias + env: + ALIASES: ${{ env.ALIASES }} + PULL_URL: ${{ github.event.comment.issue.pull_request.url }} - name: Set deployment alias - if: ${{ steps.alias.outputs.alias != '' }} + if: ${{ steps.alias.outputs.alias != '' && steps.alias.outputs.alias != 'mcraft.fun' && steps.alias.outputs.alias != 's.mcraft.fun' }} run: vercel alias set ${{ steps.deploy.outputs.stdout }} ${{ steps.alias.outputs.alias }} --token=${{ secrets.VERCEL_TOKEN }} --scope=zaro diff --git a/scripts/githubActions.mjs b/scripts/githubActions.mjs index ac218f56..ba7b8566 100644 --- a/scripts/githubActions.mjs +++ b/scripts/githubActions.mjs @@ -7,7 +7,7 @@ const fns = { const aliasesRaw = process.env.ALIASES if (!aliasesRaw) throw new Error('No aliases found') const aliases = aliasesRaw.split('\n').map((x) => x.split('=')) - const githubActionsPull = process.env.GITHUB_REF.match(/refs\/pull\/(\d+)\/merge/) + const githubActionsPull = process.env.PULL_URL?.split('/').at(-1) if (!githubActionsPull) throw new Error(`Not a pull request, got ${process.env.GITHUB_REF}`) const prNumber = githubActionsPull[1] const alias = aliases.find((x) => x[0] === prNumber) From 2a396d118792ca7000f734928dcd9b19ca052f24 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 9 Apr 2024 16:40:32 +0300 Subject: [PATCH 0006/1097] ci: disable next checkout as its not available in some repoes --- .github/workflows/preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index cdefd2e2..52f8bc29 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -49,7 +49,7 @@ jobs: Deployed to Vercel Preview: ${{ steps.deploy.outputs.stdout }} [Playground](${{ steps.deploy.outputs.stdout }}/playground.html) [Storybook](${{ steps.deploy.outputs.stdout }}/storybook/) - - run: git checkout next scripts/githubActions.mjs + # - run: git checkout next scripts/githubActions.mjs - name: Get deployment alias run: node scripts/githubActions.mjs getAlias id: alias From bf655b075b686285c1163d9d511f457c101d58a8 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 11 Apr 2024 05:14:16 +0300 Subject: [PATCH 0007/1097] ci: try sticky messages --- .github/workflows/preview.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 52f8bc29..f0cdc190 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -45,6 +45,7 @@ jobs: id: deploy - uses: mshick/add-pr-comment@v2 with: + refresh-message-position: true message: | Deployed to Vercel Preview: ${{ steps.deploy.outputs.stdout }} [Playground](${{ steps.deploy.outputs.stdout }}/playground.html) From be87a57192cae816b695ab6d2f8611ca2e0b022c Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 11 Apr 2024 05:18:14 +0300 Subject: [PATCH 0008/1097] fix indicator not disappearing sometimes --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index 3a8fbd5c..99f433e6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -919,6 +919,7 @@ downloadAndOpenFile().then((downloadAction) => { const initialLoader = document.querySelector('.initial-loader') as HTMLElement | null if (initialLoader) { initialLoader.style.opacity = '0' + initialLoader.style.pointerEvents = 'none' } window.pageLoaded = true From df0bf14f14ddc3f99dc0a8f37c9c1d6547be867c Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 11 Apr 2024 05:19:32 +0300 Subject: [PATCH 0009/1097] ci: post deploy message on each deploy --- .github/workflows/preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index f0cdc190..6ce2b927 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -45,7 +45,7 @@ jobs: id: deploy - uses: mshick/add-pr-comment@v2 with: - refresh-message-position: true + allow-repeats: true message: | Deployed to Vercel Preview: ${{ steps.deploy.outputs.stdout }} [Playground](${{ steps.deploy.outputs.stdout }}/playground.html) From 4d74730742b9a6dc08f2433faa1ec98f2e7cfa71 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Thu, 11 Apr 2024 05:36:54 +0300 Subject: [PATCH 0010/1097] ci: fix pull url in the preview script --- .github/workflows/preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 6ce2b927..03990d04 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -56,7 +56,7 @@ jobs: id: alias env: ALIASES: ${{ env.ALIASES }} - PULL_URL: ${{ github.event.comment.issue.pull_request.url }} + PULL_URL: ${{ github.event.issue.pull_request.url }} - name: Set deployment alias if: ${{ steps.alias.outputs.alias != '' && steps.alias.outputs.alias != 'mcraft.fun' && steps.alias.outputs.alias != 's.mcraft.fun' }} run: vercel alias set ${{ steps.deploy.outputs.stdout }} ${{ steps.alias.outputs.alias }} --token=${{ secrets.VERCEL_TOKEN }} --scope=zaro From da44ad40fc322bf4f85610c31f7fbae729488b0a Mon Sep 17 00:00:00 2001 From: Vitaly Date: Sun, 14 Apr 2024 23:22:23 +0300 Subject: [PATCH 0011/1097] feat: allow to setup temporary options & commands overrides in QS that wont be saved --- src/index.ts | 10 +++++++++- src/optionsStorage.ts | 13 +++++++++++-- src/react/OptionsItems.tsx | 11 ++++++++--- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/index.ts b/src/index.ts index 99f433e6..bbbb060d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -315,7 +315,7 @@ const cleanConnectIp = (host: string | undefined, defaultPort: string | undefine } async function connect (connectOptions: { - server?: string; singleplayer?: any; username: string; password?: any; proxy?: any; botVersion?: any; serverOverrides?; serverOverridesFlat?; peerId?: string + server?: string; singleplayer?: any; username: string; password?: any; proxy?: any; botVersion?: any; serverOverrides?; serverOverridesFlat?; peerId?: string; ignoreQs?: boolean }) { if (miscUiState.gameLoaded) return miscUiState.hasErrors = false @@ -826,6 +826,14 @@ async function connect (connectOptions: { document.dispatchEvent(new Event('cypress-world-ready')) }) }) + + if (!connectOptions.ignoreQs) { + const qs = new URLSearchParams(window.location.search) + for (let command of qs.getAll('command')) { + if (!command.startsWith('/')) command = `/${command}` + bot.chat(command) + } + } } listenGlobalEvents() diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index 8490053c..9e13bf47 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -3,6 +3,7 @@ import { proxy, subscribe } from 'valtio/vanilla' // weird webpack configuration bug: it cant import valtio/utils in this file import { subscribeKey } from 'valtio/utils' +import { omitObj } from '@zardoy/utils' const defaultOptions = { renderDistance: 2, @@ -80,6 +81,12 @@ const defaultOptions = { wysiwygSignEditor: 'auto' as 'auto' | 'always' | 'never', } +const qsOptionsRaw = new URLSearchParams(location.search).getAll('setting') +export const qsOptions = Object.fromEntries(qsOptionsRaw.map(o => { + const [key, value] = o.split(':') + return [key, JSON.parse(value)] +})) + const migrateOptions = (options: Partial>) => { if (options.highPerformanceGpu) { options.gpuPreference = 'high-performance' @@ -96,7 +103,8 @@ export type AppOptions = typeof defaultOptions export const options: AppOptions = proxy({ ...defaultOptions, - ...migrateOptions(JSON.parse(localStorage.options || '{}')) + ...migrateOptions(JSON.parse(localStorage.options || '{}')), + ...qsOptions }) window.options = window.settings = options @@ -112,7 +120,8 @@ Object.defineProperty(window, 'debugChangedOptions', { }) subscribe(options, () => { - localStorage.options = JSON.stringify(options) + const saveOptions = omitObj(options, ...Object.keys(qsOptions) as [any]) + localStorage.options = JSON.stringify(saveOptions) }) type WatchValue = >(proxy: T, callback: (p: T) => void) => void diff --git a/src/react/OptionsItems.tsx b/src/react/OptionsItems.tsx index 5c0941e6..74e82051 100644 --- a/src/react/OptionsItems.tsx +++ b/src/react/OptionsItems.tsx @@ -2,7 +2,7 @@ import { useSnapshot } from 'valtio' import { noCase } from 'change-case' import { titleCase } from 'title-case' import { useMemo } from 'react' -import { options } from '../optionsStorage' +import { options, qsOptions } from '../optionsStorage' import Button from './Button' import Slider from './Slider' import Screen from './Screen' @@ -30,6 +30,11 @@ export type OptionMeta = GeneralItem & ({ render: () => React.ReactNode, }) +// todo not reactive +const isDisabled = (id) => { + return qsOptions.includes(id) +} + export const OptionButton = ({ item }: { item: Extract }) => { const optionValue = useSnapshot(options)[item.id!] @@ -74,7 +79,7 @@ export const OptionButton = ({ item }: { item: Extract { + return { options[item.id!] = value }} unit={item.unit} valueDisplay={valueDisplay} updateOnDragEnd={item.delayApply} /> } From 889e652455c3f5b576d78910abb7298c1133bac9 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 15 Apr 2024 02:04:33 +0300 Subject: [PATCH 0012/1097] fix: Make hideable vercel live feedback --- src/index.ts | 4 +++- src/react/OptionsItems.tsx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index bbbb060d..7fd99b14 100644 --- a/src/index.ts +++ b/src/index.ts @@ -871,7 +871,9 @@ document.body.addEventListener('touchend', (e) => { activeTouch = undefined }) document.body.addEventListener('touchstart', (e) => { - if (!isGameActive(true)) return + const ignoreElem = (e.target as HTMLElement).matches('vercel-live-feedback') + if (!isGameActive(true) || ignoreElem) return + // we always prevent default behavior to disable magnifier on ios, but by doing so we also disable click events e.preventDefault() let firstClickable // todo remove composedPath and this workaround when lit-element is fully dropped const path = e.composedPath() as Array<{ click?: () => void }> diff --git a/src/react/OptionsItems.tsx b/src/react/OptionsItems.tsx index 74e82051..9351d66b 100644 --- a/src/react/OptionsItems.tsx +++ b/src/react/OptionsItems.tsx @@ -32,7 +32,7 @@ export type OptionMeta = GeneralItem & ({ // todo not reactive const isDisabled = (id) => { - return qsOptions.includes(id) + return Object.keys(qsOptions).includes(id) } export const OptionButton = ({ item }: { item: Extract }) => { From aafdb6469435ce3869fd4a21b2a6436ebc69abd2 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 15 Apr 2024 05:44:25 +0300 Subject: [PATCH 0013/1097] outdated commit hints in ci!! (#101) --- .github/workflows/ci.yml | 9 +++- package.json | 3 ++ prismarine-viewer/package.json | 2 +- .../viewer/prepare/generateTextures.ts | 6 +-- .../viewer/prepare/postinstall.ts | 12 +++++ scripts/outdatedGitPackages.mjs | 52 +++++++++++++++++++ scripts/updateGitPackages.mjs | 26 ---------- 7 files changed, 77 insertions(+), 33 deletions(-) create mode 100644 prismarine-viewer/viewer/prepare/postinstall.ts create mode 100644 scripts/outdatedGitPackages.mjs delete mode 100644 scripts/updateGitPackages.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe7c8ba6..3bc45b5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,10 @@ jobs: uses: actions/checkout@master - name: Install pnpm run: npm i -g pnpm - # todo this needs investigating fixing + - uses: actions/setup-node@v4 + with: + node-version: 18 + # cache: "pnpm" - run: pnpm install - run: pnpm lint - run: pnpm check-build @@ -24,3 +27,7 @@ jobs: with: name: cypress-images path: cypress/integration/__image_snapshots__/ + - run: node scripts/outdatedGitPackages.mjs + # if: github.ref == 'refs/heads/next' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/package.json b/package.json index 881be9cc..d6ea6655 100644 --- a/package.json +++ b/package.json @@ -144,6 +144,9 @@ "prismarine-provider-anvil": "github:zardoy/prismarine-provider-anvil#everything", "minecraft-protocol": "github:zardoy/minecraft-protocol#everything", "react": "^18.2.0" + }, + "updateConfig": { + "ignoreDependencies": [] } } } diff --git a/prismarine-viewer/package.json b/prismarine-viewer/package.json index 529aa9ae..7d7b6b81 100644 --- a/prismarine-viewer/package.json +++ b/prismarine-viewer/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "postinstall": "pnpm generate-textures && node buildWorker.mjs", - "generate-textures": "tsx viewer/prepare/generateTextures.ts" + "generate-textures": "tsx viewer/prepare/postinstall.ts" }, "author": "PrismarineJS", "license": "MIT", diff --git a/prismarine-viewer/viewer/prepare/generateTextures.ts b/prismarine-viewer/viewer/prepare/generateTextures.ts index b9a5e3e5..2a196ccb 100644 --- a/prismarine-viewer/viewer/prepare/generateTextures.ts +++ b/prismarine-viewer/viewer/prepare/generateTextures.ts @@ -1,6 +1,6 @@ import path from 'path' import { makeBlockTextureAtlas } from './atlas' -import { McAssets, prepareBlocksStates } from './modelsBuilder' +import { prepareBlocksStates } from './modelsBuilder' import mcAssets from 'minecraft-assets' import fs from 'fs-extra' import { prepareMoreGeneratedBlocks } from './moreGeneratedBlocks' @@ -9,10 +9,6 @@ import { generateItemsAtlases } from './genItemsAtlas' const publicPath = path.resolve(__dirname, '../../public') const texturesPath = path.join(publicPath, 'textures') -if (fs.existsSync(texturesPath) && !process.argv.includes('-f')) { - console.log('textures folder already exists, skipping...') - process.exit(0) -} fs.mkdirSync(texturesPath, { recursive: true }) const blockStatesPath = path.join(publicPath, 'blocksStates') diff --git a/prismarine-viewer/viewer/prepare/postinstall.ts b/prismarine-viewer/viewer/prepare/postinstall.ts new file mode 100644 index 00000000..bf70d26c --- /dev/null +++ b/prismarine-viewer/viewer/prepare/postinstall.ts @@ -0,0 +1,12 @@ +import path from 'path' +import fs from 'fs' + +const publicPath = path.resolve(__dirname, '../../public') +const texturesPath = path.join(publicPath, 'textures') + +if (fs.existsSync(texturesPath) && !process.argv.includes('-f')) { + console.log('textures folder already exists, skipping...') + process.exit(0) +} else { + import('./generateTextures') +} diff --git a/scripts/outdatedGitPackages.mjs b/scripts/outdatedGitPackages.mjs new file mode 100644 index 00000000..c6a3b2d5 --- /dev/null +++ b/scripts/outdatedGitPackages.mjs @@ -0,0 +1,52 @@ +// pnpm bug workaround +import fs from 'fs' +import { parse } from 'yaml' +import _ from 'lodash' + +const lockfile = parse(fs.readFileSync('./pnpm-lock.yaml', 'utf8')) +const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8')) +const depsKeys = ['dependencies', 'devDependencies'] + +const githubToken = process.env.GITHUB_TOKEN +const ignoreDeps = packageJson.pnpm?.updateConfig?.ignoreDependencies ?? [] + +const outdatedDeps = [] + +const allDepsObj = {} + +for (const [key, val] of Object.entries(lockfile.importers)) { + // Object.assign(allDepsObj, val) + _.merge(allDepsObj, val) +} + +for (const [depsKey, deps] of Object.entries(allDepsObj)) { + for (const [depName, { specifier, version }] of Object.entries(deps)) { + if (ignoreDeps.includes(depName)) continue + if (!specifier.startsWith('github:')) continue + // console.log('checking github:', depName, version, specifier) + + let possiblyBranch = specifier.match(/#(.*)$/)?.[1] ?? '' + if (possiblyBranch) possiblyBranch = `/${possiblyBranch}` + const sha = version.split('/').slice(3).join('/').replace(/\(.+/, '') + const repo = version.split('/').slice(1, 3).join('/') + + const lastCommitJson = await fetch(`https://api.github.com/repos/${repo}/commits${possiblyBranch}?per_page=1`, { + headers: { + Authorization: githubToken ? `token ${githubToken}` : undefined, + }, + }).then(res => res.json()) + + const lastCommitActual = lastCommitJson ?? lastCommitJson[0] + const lastCommitActualSha = Array.isArray(lastCommitActual) ? lastCommitActual[0]?.sha : lastCommitActual?.sha + if (lastCommitActualSha === undefined) debugger + if (sha !== lastCommitActualSha) { + // console.log(`Outdated ${depName} github.com/${repo} : ${sha} -> ${lastCommitActualSha} (${lastCommitActual.commit.message})`) + outdatedDeps.push({ depName, repo, sha, lastCommitActualSha }) + } + } + +} + +if (outdatedDeps.length) { + throw new Error(`Outdated dependencies found: \n${outdatedDeps.map(({ depName, repo, sha, lastCommitActualSha }) => `${depName} github.com/${repo} : ${sha} -> ${lastCommitActualSha}`).join('\n')}`) +} diff --git a/scripts/updateGitPackages.mjs b/scripts/updateGitPackages.mjs deleted file mode 100644 index 14524587..00000000 --- a/scripts/updateGitPackages.mjs +++ /dev/null @@ -1,26 +0,0 @@ -// pnpm bug workaround -import fs from 'fs' -import { parse } from 'yaml' - -const lockfile = parse(fs.readFileSync('./pnpm-lock.yaml', 'utf8')) - -const depsKeys = ['dependencies', 'devDependencies'] - -for (const importer of Object.values(lockfile.importers)) { - for (const depsKey of depsKeys) { - for (const [depName, { specifier, version }] of Object.entries(importer[depsKey])) { - if (!specifier.startsWith('github:')) continue - let branch = specifier.match(/#(.*)$/)?.[1] ?? '' - if (branch) branch = `/${branch}` - const sha = version.split('/').slice(3).join('/').replace(/\(.+/, '') - const repo = version.split('/').slice(1, 3).join('/') - const lastCommitJson = await fetch(`https://api.github.com/repos/${repo}/commits${branch}?per_page=1`).then(res => res.json()) - const lastCommitActual = lastCommitJson ?? lastCommitJson[0] - const lastCommitActualSha = lastCommitActual?.sha - if (lastCommitActualSha === undefined) debugger - if (sha !== lastCommitActualSha) { - console.log(`Outdated ${depName} github.com/${repo} : ${sha} -> ${lastCommitActualSha} (${lastCommitActual.commit.message})`) - } - } - } -} From 954169d1b9d1f96e36cce33914a442a10236b8b0 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 15 Apr 2024 05:45:14 +0300 Subject: [PATCH 0014/1097] enable outdated deps check only on next --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3bc45b5e..cbd12318 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,6 @@ jobs: name: cypress-images path: cypress/integration/__image_snapshots__/ - run: node scripts/outdatedGitPackages.mjs - # if: github.ref == 'refs/heads/next' + if: github.ref == 'refs/heads/next' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 10662bcbc06221aabc4b86aa33e7dcd28d40c002 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Tue, 16 Apr 2024 05:24:47 +0300 Subject: [PATCH 0015/1097] feat: Add auto jump (disabled by default for PC & Gamepad users) (#100) --- package.json | 2 + pnpm-lock.yaml | 546 ++++++++++++++++++++++++++++----------- src/entities.ts | 31 +++ src/optionsGuiScheme.tsx | 7 + src/optionsStorage.ts | 1 + 5 files changed, 442 insertions(+), 145 deletions(-) diff --git a/package.json b/package.json index d6ea6655..b91bb11e 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@dimaka/interface": "0.0.3-alpha.0", "@floating-ui/react": "^0.26.1", "@mui/base": "5.0.0-beta.34", + "@nxg-org/mineflayer-auto-jump": "^0.7.5", "@nxg-org/mineflayer-tracker": "^1.2.1", "@react-oauth/google": "^0.12.1", "@types/gapi": "^0.0.47", @@ -136,6 +137,7 @@ }, "pnpm": { "overrides": { + "@nxg-org/mineflayer-physics-util": "1.5.8", "three": "0.154.0", "diamond-square": "github:zardoy/diamond-square", "prismarine-block": "github:zardoy/prismarine-block#next-era", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 483f0277..4c43c6ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: + '@nxg-org/mineflayer-physics-util': 1.5.8 three: 0.154.0 diamond-square: github:zardoy/diamond-square prismarine-block: github:zardoy/prismarine-block#next-era @@ -27,6 +28,9 @@ importers: '@mui/base': specifier: 5.0.0-beta.34 version: 5.0.0-beta.34(@types/react@18.2.20)(react-dom@18.2.0)(react@18.2.0) + '@nxg-org/mineflayer-auto-jump': + specifier: ^0.7.5 + version: 0.7.5 '@nxg-org/mineflayer-tracker': specifier: ^1.2.1 version: 1.2.1 @@ -186,7 +190,7 @@ importers: optionalDependencies: systeminformation: specifier: ^5.21.22 - version: 5.21.24 + version: 5.22.7 devDependencies: '@storybook/addon-essentials': specifier: ^7.4.6 @@ -202,13 +206,13 @@ importers: version: 7.4.6(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) '@storybook/react-vite': specifier: ^7.4.6 - version: 7.4.6(react-dom@18.2.0)(react@18.2.0)(rollup@2.79.1)(typescript@5.2.2)(vite@4.5.2) + version: 7.4.6(react-dom@18.2.0)(react@18.2.0)(rollup@2.79.1)(typescript@5.2.2)(vite@4.5.3) '@storybook/web-components': specifier: ^7.4.6 version: 7.4.6(lit@2.8.0)(react-dom@18.2.0)(react@18.2.0) '@storybook/web-components-vite': specifier: ^7.4.6 - version: 7.4.6(lit@2.8.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.5.2) + version: 7.4.6(lit@2.8.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.5.3) '@types/lodash-es': specifier: ^4.17.9 version: 4.17.9 @@ -256,7 +260,7 @@ importers: version: 8.50.0 eslint-config-zardoy: specifier: ^0.2.17 - version: 0.2.17(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.33.2)(eslint@8.50.0)(typescript@5.2.2) + version: 0.2.17(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.34.1)(eslint@8.50.0)(typescript@5.2.2) events: specifier: ^3.3.0 version: 3.3.0 @@ -436,15 +440,15 @@ packages: default-browser-id: 3.0.0 dev: true - /@azure/msal-common@14.7.0: - resolution: {integrity: sha512-WexujW5jKWib7xtIxR7fEVyd5xcA3FNwenELy2HO4YC/ivTFdsEcDhtpKQuRUHqXRwxoqBblyZzTAhBm4v6fHA==} + /@azure/msal-common@14.9.0: + resolution: {integrity: sha512-yzBPRlWPnTBeixxLNI3BBIgF5/bHpbhoRVuuDBnYjCyWRavaPUsKAHUDYLqpGkBLDciA6TCc6GOxN4/S3WiSxg==} engines: {node: '>=0.8.0'} - /@azure/msal-node@2.6.3: - resolution: {integrity: sha512-ojjJqUwb297T5Tcln4PbJANFEqRXfbQXcyOrtdr1HQYIo+dSuCT/o0nG6bFVihf6fcNykDwJLCQPVXzTkx/oGg==} + /@azure/msal-node@2.7.0: + resolution: {integrity: sha512-wXD8LkUvHICeSWZydqg6o8Yvv+grlBEcmLGu+QEI4FcwFendbTEZrlSygnAXXSOCVaGAirWLchca35qrgpO6Jw==} engines: {node: '>=16'} dependencies: - '@azure/msal-common': 14.7.0 + '@azure/msal-common': 14.9.0 jsonwebtoken: 9.0.2 uuid: 8.3.2 @@ -3138,7 +3142,7 @@ packages: regenerator-runtime: 0.13.11 dev: false - /@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.2.2)(vite@4.5.2): + /@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.2.2)(vite@4.5.3): resolution: {integrity: sha512-ou4ZJSXMMWHqGS4g8uNRbC5TiTWxAgQZiVucoUrOCWuPrTbkpJbmVyIi9jU72SBry7gQtuMEDp4YR8EEXAg7VQ==} peerDependencies: typescript: '>= 4.3.x' @@ -3152,7 +3156,7 @@ packages: magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.2.2) typescript: 5.2.2 - vite: 4.5.2 + vite: 4.5.3 dev: true /@jridgewell/gen-mapping@0.3.3: @@ -3337,6 +3341,19 @@ packages: dev: false optional: true + /@nxg-org/mineflayer-auto-jump@0.7.5: + resolution: {integrity: sha512-wvPLPW06nxz9/WimNdReF41I6mSQcxAcJFFBmN9geaSdnPkr8GVxq6daJSDwXXktNsh8/NBusJhMkJGh6eNnZg==} + dependencies: + '@nxg-org/mineflayer-physics-util': 1.5.8 + strict-event-emitter-types: 2.0.0 + dev: false + + /@nxg-org/mineflayer-physics-util@1.5.8: + resolution: {integrity: sha512-KmCkAqpUo8BbuRdIBs6+V2hWHehz++PRz3lRwIsb47CuG0u4sgLYh37RY3ifAznC6uWvmPK+q3B4ZXwJzPy1MQ==} + dependencies: + '@nxg-org/mineflayer-util-plugin': 1.8.3 + dev: false + /@nxg-org/mineflayer-tracker@1.2.1: resolution: {integrity: sha512-SI1ffF8zvg3/ZNE021Ja2W0FZPN+WbQDZf8yFqOcXtPRXAtM9W6HvoACdzXep8BZid7WYgYLIgjKpB+9RqvCNQ==} dependencies: @@ -4370,7 +4387,7 @@ packages: - supports-color dev: true - /@storybook/builder-vite@7.4.6(typescript@5.2.2)(vite@4.5.2): + /@storybook/builder-vite@7.4.6(typescript@5.2.2)(vite@4.5.3): resolution: {integrity: sha512-xV9STYK+TkqWWTf2ydm6jx+7P70fjD2UPd1XTUw08uKszIjhuuxk+bG/OF5R1E25mPunAKXm6kBFh351AKejBg==} peerDependencies: '@preact/preset-vite': '*' @@ -4405,7 +4422,7 @@ packages: remark-slug: 6.1.0 rollup: 3.29.4 typescript: 5.2.2 - vite: 4.5.2 + vite: 4.5.3 transitivePeerDependencies: - encoding - supports-color @@ -4746,7 +4763,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/react-vite@7.4.6(react-dom@18.2.0)(react@18.2.0)(rollup@2.79.1)(typescript@5.2.2)(vite@4.5.2): + /@storybook/react-vite@7.4.6(react-dom@18.2.0)(react@18.2.0)(rollup@2.79.1)(typescript@5.2.2)(vite@4.5.3): resolution: {integrity: sha512-jkjnrf3FxzR5wcmebXRPflrsM4WIDjWyW/NVFJwxi5PeIOk7fE7/QAPrm4NFRUu2Q7DeuH3oLKsw8bigvUI9RA==} engines: {node: '>=16'} peerDependencies: @@ -4754,17 +4771,17 @@ packages: react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.2.2)(vite@4.5.2) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.2.2)(vite@4.5.3) '@rollup/pluginutils': 5.0.5(rollup@2.79.1) - '@storybook/builder-vite': 7.4.6(typescript@5.2.2)(vite@4.5.2) + '@storybook/builder-vite': 7.4.6(typescript@5.2.2)(vite@4.5.3) '@storybook/react': 7.4.6(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) - '@vitejs/plugin-react': 3.1.0(vite@4.5.2) + '@vitejs/plugin-react': 3.1.0(vite@4.5.3) ast-types: 0.14.2 magic-string: 0.30.4 react: 18.2.0 react-docgen: 6.0.0-alpha.3 react-dom: 18.2.0(react@18.2.0) - vite: 4.5.2 + vite: 4.5.3 transitivePeerDependencies: - '@preact/preset-vite' - encoding @@ -4866,14 +4883,14 @@ packages: file-system-cache: 2.3.0 dev: true - /@storybook/web-components-vite@7.4.6(lit@2.8.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.5.2): + /@storybook/web-components-vite@7.4.6(lit@2.8.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(vite@4.5.3): resolution: {integrity: sha512-L/y6MTLbqfHaM0faK9Yl8n5PIyW4daZrtk7NfaOT6UjgNFjOx3o4CctYew6oj90cNk5HdZQX2OZny043GxDLZw==} engines: {node: ^14.18 || >=16} peerDependencies: react: ^18.2.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/builder-vite': 7.4.6(typescript@5.2.2)(vite@4.5.2) + '@storybook/builder-vite': 7.4.6(typescript@5.2.2)(vite@4.5.3) '@storybook/core-server': 7.4.6 '@storybook/node-logger': 7.4.6 '@storybook/web-components': 7.4.6(lit@2.8.0)(react-dom@18.2.0)(react@18.2.0) @@ -5184,6 +5201,13 @@ packages: /@types/node@20.11.19: resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==} + requiresBuild: true + dependencies: + undici-types: 5.26.5 + optional: true + + /@types/node@20.12.7: + resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} dependencies: undici-types: 5.26.5 @@ -5248,10 +5272,10 @@ packages: '@types/scheduler': 0.16.3 csstype: 3.1.2 - /@types/readable-stream@4.0.10: - resolution: {integrity: sha512-AbUKBjcC8SHmImNi4yK2bbjogQlkFSg7shZCcicxPQapniOlajG8GCc39lvXzCWX4lLRRs7DM3VAeSlqmEVZUA==} + /@types/readable-stream@4.0.11: + resolution: {integrity: sha512-R3eUMUTTKoIoaz7UpYLxvZCrOmCRPRbAmoDDHKcimTEySltaJhF8hLzj4+EzyDifiX5eK6oDQGSfmNnXjxZzYQ==} dependencies: - '@types/node': 20.11.19 + '@types/node': 20.12.7 safe-buffer: 5.1.2 /@types/resolve@1.17.1: @@ -5534,7 +5558,7 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@vitejs/plugin-react@3.1.0(vite@4.5.2): + /@vitejs/plugin-react@3.1.0(vite@4.5.3): resolution: {integrity: sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -5545,7 +5569,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.22.11) magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 4.5.2 + vite: 4.5.3 transitivePeerDependencies: - supports-color dev: true @@ -5718,7 +5742,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 @@ -6014,11 +6038,35 @@ packages: is-string: 1.0.7 dev: true + /array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + dev: true + /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} dev: true + /array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + dev: true + /array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} @@ -6039,12 +6087,21 @@ packages: es-shim-unscopables: 1.0.0 dev: true + /array.prototype.toreversed@1.1.2: + resolution: {integrity: sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + dev: true + /array.prototype.tosorted@1.1.3: resolution: {integrity: sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-errors: 1.3.0 es-shim-unscopables: 1.0.2 dev: true @@ -6068,11 +6125,11 @@ packages: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-errors: 1.3.0 get-intrinsic: 1.2.4 is-array-buffer: 3.0.4 - is-shared-array-buffer: 1.0.2 + is-shared-array-buffer: 1.0.3 dev: true /arraybuffer.slice@0.0.7: @@ -6157,12 +6214,6 @@ packages: /async@3.2.5: resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} - /asynciterator.prototype@1.0.0: - resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} - dependencies: - has-symbols: 1.0.3 - dev: true - /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -6174,9 +6225,11 @@ packages: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} - /available-typed-arrays@1.0.6: - resolution: {integrity: sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==} + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 dev: true /aws-sign2@0.7.0: @@ -6188,7 +6241,7 @@ packages: /axios@0.21.4(debug@4.3.4): resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} dependencies: - follow-redirects: 1.15.5(debug@4.3.4) + follow-redirects: 1.15.6(debug@4.3.4) transitivePeerDependencies: - debug @@ -7305,6 +7358,33 @@ packages: dependencies: assert-plus: 1.0.0 + /data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + + /data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true + /dayjs@1.11.9: resolution: {integrity: sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==} @@ -7945,17 +8025,21 @@ packages: unbox-primitive: 1.0.2 which-typed-array: 1.1.11 - /es-abstract@1.22.4: - resolution: {integrity: sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==} + /es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 - available-typed-arrays: 1.0.6 + available-typed-arrays: 1.0.7 call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 es-define-property: 1.0.0 es-errors: 1.3.0 - es-set-tostringtag: 2.0.2 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 es-to-primitive: 1.2.1 function.prototype.name: 1.1.6 get-intrinsic: 1.2.4 @@ -7963,15 +8047,16 @@ packages: globalthis: 1.0.3 gopd: 1.0.1 has-property-descriptors: 1.0.2 - has-proto: 1.0.1 + has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.1 + hasown: 2.0.2 internal-slot: 1.0.7 is-array-buffer: 3.0.4 is-callable: 1.2.7 - is-negative-zero: 2.0.2 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 + is-shared-array-buffer: 1.0.3 is-string: 1.0.7 is-typed-array: 1.1.13 is-weakref: 1.0.2 @@ -7979,17 +8064,17 @@ packages: object-keys: 1.1.1 object.assign: 4.1.5 regexp.prototype.flags: 1.5.2 - safe-array-concat: 1.1.0 + safe-array-concat: 1.1.2 safe-regex-test: 1.0.3 - string.prototype.trim: 1.2.8 - string.prototype.trimend: 1.0.7 - string.prototype.trimstart: 1.0.7 - typed-array-buffer: 1.0.1 - typed-array-byte-length: 1.0.0 - typed-array-byte-offset: 1.0.0 - typed-array-length: 1.0.4 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 unbox-primitive: 1.0.2 - which-typed-array: 1.1.14 + which-typed-array: 1.1.15 dev: true /es-define-property@1.0.0: @@ -8002,31 +8087,37 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - /es-iterator-helpers@1.0.17: - resolution: {integrity: sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ==} + /es-iterator-helpers@1.0.18: + resolution: {integrity: sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==} engines: {node: '>= 0.4'} dependencies: - asynciterator.prototype: 1.0.0 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-errors: 1.3.0 - es-set-tostringtag: 2.0.2 + es-set-tostringtag: 2.0.3 function-bind: 1.1.2 get-intrinsic: 1.2.4 globalthis: 1.0.3 has-property-descriptors: 1.0.2 - has-proto: 1.0.1 + has-proto: 1.0.3 has-symbols: 1.0.3 internal-slot: 1.0.7 iterator.prototype: 1.1.2 - safe-array-concat: 1.1.0 + safe-array-concat: 1.1.2 dev: true /es-module-lexer@0.9.3: resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} dev: true + /es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: true + /es-set-tostringtag@2.0.1: resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} engines: {node: '>= 0.4'} @@ -8035,13 +8126,13 @@ packages: has: 1.0.3 has-tostringtag: 1.0.0 - /es-set-tostringtag@2.0.2: - resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + /es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 - hasown: 2.0.1 + hasown: 2.0.2 dev: true /es-shim-unscopables@1.0.0: @@ -8053,7 +8144,7 @@ packages: /es-shim-unscopables@1.0.2: resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: - hasown: 2.0.1 + hasown: 2.0.2 dev: true /es-to-primitive@1.2.1: @@ -8228,7 +8319,7 @@ packages: eslint: 8.50.0 dev: true - /eslint-config-xo-react@0.27.0(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.33.2)(eslint@8.50.0): + /eslint-config-xo-react@0.27.0(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.34.1)(eslint@8.50.0): resolution: {integrity: sha512-wiV215xQIn71XZyyVfaOXHaFpR1B14IJttwOjMi/eqUK1s+ojJdHr7eHqTLaGUfh6FKgWha1QNwePlIXx7mBUg==} engines: {node: '>=12'} peerDependencies: @@ -8237,7 +8328,7 @@ packages: eslint-plugin-react-hooks: '>=4.3.0' dependencies: eslint: 8.50.0 - eslint-plugin-react: 7.33.2(eslint@8.50.0) + eslint-plugin-react: 7.34.1(eslint@8.50.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.50.0) dev: true @@ -8266,7 +8357,7 @@ packages: eslint: 8.50.0 dev: true - /eslint-config-zardoy@0.2.17(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.33.2)(eslint@8.50.0)(typescript@5.2.2): + /eslint-config-zardoy@0.2.17(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.34.1)(eslint@8.50.0)(typescript@5.2.2): resolution: {integrity: sha512-d31WsjyVSQqHbzTpBSmH96+nw5gwY2yhDbZatU89gr+U8ou1FRUkJSApYJUgmcINt8AQocj1RDDAVYmVSILZgQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: @@ -8286,7 +8377,7 @@ packages: eslint: 8.50.0 eslint-config-prettier: 8.10.0(eslint@8.50.0) eslint-config-xo: 0.43.1(eslint@8.50.0) - eslint-config-xo-react: 0.27.0(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.33.2)(eslint@8.50.0) + eslint-config-xo-react: 0.27.0(eslint-plugin-react-hooks@4.6.0)(eslint-plugin-react@7.34.1)(eslint@8.50.0) eslint-config-xo-typescript: 1.0.1(@typescript-eslint/eslint-plugin@6.1.0)(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.2.2) eslint-plugin-eslint-comments: 3.2.0(eslint@8.50.0) eslint-plugin-import: 2.27.5(@typescript-eslint/parser@6.7.3)(eslint@8.50.0) @@ -8420,29 +8511,31 @@ packages: eslint: 8.50.0 dev: true - /eslint-plugin-react@7.33.2(eslint@8.50.0): - resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} + /eslint-plugin-react@7.34.1(eslint@8.50.0): + resolution: {integrity: sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - array-includes: 3.1.7 + array-includes: 3.1.8 + array.prototype.findlast: 1.2.5 array.prototype.flatmap: 1.3.2 + array.prototype.toreversed: 1.1.2 array.prototype.tosorted: 1.1.3 doctrine: 2.1.0 - es-iterator-helpers: 1.0.17 + es-iterator-helpers: 1.0.18 eslint: 8.50.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 - object.entries: 1.1.7 - object.fromentries: 2.0.7 - object.hasown: 1.1.3 - object.values: 1.1.7 + object.entries: 1.1.8 + object.fromentries: 2.0.8 + object.hasown: 1.1.4 + object.values: 1.2.0 prop-types: 15.8.1 resolve: 2.0.0-next.5 semver: 6.3.1 - string.prototype.matchall: 4.0.10 + string.prototype.matchall: 4.0.11 dev: true /eslint-plugin-sonarjs@0.19.0(eslint@8.50.0): @@ -8973,8 +9066,8 @@ packages: debug: 4.3.4(supports-color@8.1.1) dev: true - /follow-redirects@1.15.5(debug@4.3.4): - resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} + /follow-redirects@1.15.6(debug@4.3.4): + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -9465,6 +9558,11 @@ packages: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + dev: true + /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} @@ -9514,6 +9612,13 @@ packages: dependencies: function-bind: 1.1.2 + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true @@ -9811,8 +9916,8 @@ packages: engines: {node: '>= 0.4'} dependencies: es-errors: 1.3.0 - hasown: 2.0.1 - side-channel: 1.0.5 + hasown: 2.0.2 + side-channel: 1.0.6 dev: true /invariant@2.2.4: @@ -9913,7 +10018,14 @@ packages: /is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: - hasown: 2.0.1 + hasown: 2.0.2 + dev: true + + /is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + dependencies: + is-typed-array: 1.1.13 dev: true /is-date-object@1.0.5: @@ -9987,8 +10099,9 @@ packages: dev: false optional: true - /is-map@2.0.2: - resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} + /is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} dev: true /is-module@1.0.0: @@ -10006,6 +10119,11 @@ packages: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + dev: true + /is-number-object@1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} @@ -10065,8 +10183,9 @@ packages: engines: {node: '>=0.10.0'} dev: false - /is-set@2.0.2: - resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + /is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} dev: true /is-shared-array-buffer@1.0.2: @@ -10074,6 +10193,13 @@ packages: dependencies: call-bind: 1.0.2 + /is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + dev: true + /is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -10100,7 +10226,7 @@ packages: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} dependencies: - which-typed-array: 1.1.14 + which-typed-array: 1.1.15 dev: true /is-typedarray@1.0.0: @@ -10110,8 +10236,9 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} - /is-weakmap@2.0.1: - resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} + /is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} dev: true /is-weakref@1.0.2: @@ -10119,8 +10246,9 @@ packages: dependencies: call-bind: 1.0.2 - /is-weakset@2.0.2: - resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + /is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 @@ -10201,8 +10329,8 @@ packages: define-properties: 1.2.1 get-intrinsic: 1.2.4 has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.5 - set-function-name: 2.0.1 + reflect.getprototypeof: 1.0.6 + set-function-name: 2.0.2 dev: true /jackspeak@2.3.0: @@ -10290,8 +10418,8 @@ packages: regenerator-runtime: 0.13.11 dev: false - /jose@4.15.4: - resolution: {integrity: sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==} + /jose@4.15.5: + resolution: {integrity: sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==} /jpeg-js@0.3.7: resolution: {integrity: sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==} @@ -10466,10 +10594,10 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} dependencies: - array-includes: 3.1.7 + array-includes: 3.1.8 array.prototype.flat: 1.3.2 object.assign: 4.1.5 - object.values: 1.1.7 + object.values: 1.2.0 dev: true /jszip@3.10.1: @@ -11815,29 +11943,32 @@ packages: object-keys: 1.1.1 dev: true - /object.entries@1.1.7: - resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + /object.entries@1.1.8: + resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-object-atoms: 1.0.0 dev: true - /object.fromentries@2.0.7: - resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + /object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 dev: true - /object.hasown@1.1.3: - resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + /object.hasown@1.1.4: + resolution: {integrity: sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==} + engines: {node: '>= 0.4'} dependencies: define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 dev: true /object.values@1.1.7: @@ -11849,6 +11980,15 @@ packages: es-abstract: 1.22.2 dev: true + /object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: true + /omggif@1.0.10: resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==} dev: false @@ -12296,6 +12436,11 @@ packages: - supports-color dev: true + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: true + /postcss@8.4.31: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} @@ -12304,13 +12449,13 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 - /postcss@8.4.35: - resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} + /postcss@8.4.38: + resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.7 picocolors: 1.0.0 - source-map-js: 1.0.2 + source-map-js: 1.2.0 dev: true /potpack@1.0.2: @@ -12376,13 +12521,13 @@ packages: engines: {node: '>= 0.8'} dev: true - /prismarine-auth@2.4.1: - resolution: {integrity: sha512-DwDI3Ucxf/eThJJo5QVzlywFrJulL1fK1z6F8bybvddim8YgudRksQc3w4cE2m0hPPHfE1BRd5lh1NpedrixMQ==} + /prismarine-auth@2.4.2: + resolution: {integrity: sha512-Cq4woGobnFYYfMBDh1WITW+Vs98toN91qAFBvBitwV7IwJaiSAh2Nl+WPUEGeg5eLBoSPpSyCVT8P2oi7Cav8g==} dependencies: - '@azure/msal-node': 2.6.3 + '@azure/msal-node': 2.7.0 '@xboxreplay/xboxlive-auth': 3.3.3(debug@4.3.4) debug: 4.3.4(supports-color@8.1.1) - jose: 4.15.4 + jose: 4.15.5 node-fetch: 2.7.0 smart-buffer: 4.2.0 uuid-1345: 1.0.2 @@ -12483,7 +12628,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 @@ -13243,13 +13388,13 @@ packages: strip-indent: 4.0.0 dev: true - /reflect.getprototypeof@1.0.5: - resolution: {integrity: sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==} + /reflect.getprototypeof@1.0.6: + resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.4 + es-abstract: 1.23.3 es-errors: 1.3.0 get-intrinsic: 1.2.4 globalthis: 1.0.3 @@ -13297,7 +13442,7 @@ packages: call-bind: 1.0.7 define-properties: 1.2.1 es-errors: 1.3.0 - set-function-name: 2.0.1 + set-function-name: 2.0.2 dev: true /regexpp@3.2.0: @@ -13546,8 +13691,8 @@ packages: has-symbols: 1.0.3 isarray: 2.0.5 - /safe-array-concat@1.1.0: - resolution: {integrity: sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==} + /safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} dependencies: call-bind: 1.0.7 @@ -13704,6 +13849,16 @@ packages: functions-have-names: 1.2.3 has-property-descriptors: 1.0.0 + /set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + dev: true + /set-harmonic-interval@1.0.1: resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==} engines: {node: '>=6.9'} @@ -13787,6 +13942,16 @@ packages: get-intrinsic: 1.2.4 object-inspect: 1.13.1 + /side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.1 + dev: true + /siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} dev: true @@ -14017,6 +14182,11 @@ packages: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} + /source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + dev: true + /source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: @@ -14175,6 +14345,10 @@ packages: resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==} dev: true + /strict-event-emitter-types@2.0.0: + resolution: {integrity: sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==} + dev: false + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -14204,6 +14378,25 @@ packages: regexp.prototype.flags: 1.5.1 set-function-name: 2.0.1 side-channel: 1.0.4 + dev: false + + /string.prototype.matchall@4.0.11: + resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.7 + regexp.prototype.flags: 1.5.2 + set-function-name: 2.0.2 + side-channel: 1.0.6 + dev: true /string.prototype.padend@3.1.4: resolution: {integrity: sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw==} @@ -14222,6 +14415,16 @@ packages: define-properties: 1.2.1 es-abstract: 1.22.2 + /string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + dev: true + /string.prototype.trimend@1.0.7: resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} dependencies: @@ -14229,6 +14432,14 @@ packages: define-properties: 1.2.1 es-abstract: 1.22.2 + /string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: true + /string.prototype.trimstart@1.0.7: resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} dependencies: @@ -14236,6 +14447,15 @@ packages: define-properties: 1.2.1 es-abstract: 1.22.2 + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: true + /string_decoder@0.10.31: resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} requiresBuild: true @@ -14349,8 +14569,8 @@ packages: resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==} dev: true - /systeminformation@5.21.24: - resolution: {integrity: sha512-xQada8ByGGFoRXJaUptGgddn3i7IjtSdqNdCKzB8xkzsM7pHnfLYBWxkPdGzhZ0Z/l+W1yo+aZQZ74d2isj8kw==} + /systeminformation@5.22.7: + resolution: {integrity: sha512-AWxlP05KeHbpGdgvZkcudJpsmChc2Y5Eo/GvxG/iUA/Aws5LZKHAMSeAo+V+nD+nxWZaxrwpWcnx4SH3oxNL3A==} engines: {node: '>=8.0.0'} os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] hasBin: true @@ -14735,8 +14955,8 @@ packages: get-intrinsic: 1.2.1 is-typed-array: 1.1.12 - /typed-array-buffer@1.0.1: - resolution: {integrity: sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ==} + /typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 @@ -14753,6 +14973,17 @@ packages: has-proto: 1.0.1 is-typed-array: 1.1.12 + /typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + dev: true + /typed-array-byte-offset@1.0.0: resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} engines: {node: '>= 0.4'} @@ -14763,6 +14994,18 @@ packages: has-proto: 1.0.1 is-typed-array: 1.1.12 + /typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + dev: true + /typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} dependencies: @@ -14770,6 +15013,18 @@ packages: for-each: 0.3.3 is-typed-array: 1.1.12 + /typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + dev: true + /typed-emitter@1.4.0: resolution: {integrity: sha512-weBmoo3HhpKGgLBOYwe8EB31CzDFuaK7CCL+axXhUYhn4jo6DSkHnbefboCF5i4DQ2aMFe0C/FdTWcPdObgHyg==} @@ -15250,8 +15505,8 @@ packages: optionalDependencies: fsevents: 2.3.3 - /vite@4.5.2: - resolution: {integrity: sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==} + /vite@4.5.3: + resolution: {integrity: sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: @@ -15279,7 +15534,7 @@ packages: optional: true dependencies: esbuild: 0.18.20 - postcss: 8.4.35 + postcss: 8.4.38 rollup: 3.29.4 optionalDependencies: fsevents: 2.3.3 @@ -15451,17 +15706,18 @@ packages: is-weakref: 1.0.2 isarray: 2.0.5 which-boxed-primitive: 1.0.2 - which-collection: 1.0.1 - which-typed-array: 1.1.14 + which-collection: 1.0.2 + which-typed-array: 1.1.15 dev: true - /which-collection@1.0.1: - resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + /which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} dependencies: - is-map: 2.0.2 - is-set: 2.0.2 - is-weakmap: 2.0.1 - is-weakset: 2.0.2 + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.3 dev: true /which-typed-array@1.1.11: @@ -15474,11 +15730,11 @@ packages: gopd: 1.0.1 has-tostringtag: 1.0.0 - /which-typed-array@1.1.14: - resolution: {integrity: sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==} + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} dependencies: - available-typed-arrays: 1.0.6 + available-typed-arrays: 1.0.7 call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 @@ -15929,7 +16185,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 @@ -15989,7 +16245,7 @@ packages: version: 1.45.0 engines: {node: '>=14'} dependencies: - '@types/readable-stream': 4.0.10 + '@types/readable-stream': 4.0.11 aes-js: 3.1.2 buffer-equal: 1.0.1 debug: 4.3.4(supports-color@8.1.1) @@ -16000,7 +16256,7 @@ packages: minecraft-folder-path: 1.2.0 node-fetch: 2.7.0 node-rsa: 0.4.2 - prismarine-auth: 2.4.1 + prismarine-auth: 2.4.2 prismarine-nbt: 2.5.0 prismarine-realms: 1.3.2 protodef: 1.15.0 @@ -16037,8 +16293,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/src/entities.ts b/src/entities.ts index 0889c9ed..58c445f1 100644 --- a/src/entities.ts +++ b/src/entities.ts @@ -1,9 +1,39 @@ import { Entity } from 'prismarine-entity' import tracker from '@nxg-org/mineflayer-tracker' +import { loader as autoJumpPlugin } from '@nxg-org/mineflayer-auto-jump' +import { subscribeKey } from 'valtio/utils' import { options, watchValue } from './optionsStorage' +import { miscUiState } from './globalState' + + +const updateAutoJump = () => { + if (!bot?.autoJumper) return + const autoJump = options.autoJump === 'auto' ? miscUiState.currentTouch && !miscUiState.usingGamepadInput : options.autoJump === 'always' + bot.autoJumper.setOpts({ + jumpIntoWater: false, + jumpOnAllEdges: false, + // strictBlockCollision: true, + }) + if (autoJump) { + bot.autoJumper.enable() + } else { + bot.autoJumper.disable() + } +} +subscribeKey(options, 'autoJump', () => { + updateAutoJump() +}) +subscribeKey(miscUiState, 'usingGamepadInput', () => { + updateAutoJump() +}) +subscribeKey(miscUiState, 'currentTouch', () => { + updateAutoJump() +}) customEvents.on('gameLoaded', () => { bot.loadPlugin(tracker) + bot.loadPlugin(autoJumpPlugin) + updateAutoJump() // todo cleanup (move to viewer, also shouldnt be used at all) const playerPerAnimation = {} as Record @@ -13,6 +43,7 @@ customEvents.on('gameLoaded', () => { window.debugEntityMetadata[e.username] = e // todo entity spawn timing issue, check perf if (viewer.entities.entities[e.id]?.playerObject) { + // todo throttle! bot.tracker.trackEntity(e) const { playerObject } = viewer.entities.entities[e.id] playerObject.backEquipment = e.equipment.some((item) => item?.name === 'elytra') ? 'elytra' : 'cape' diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 13e6388b..b54f3498 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -208,6 +208,13 @@ export const guiOptionsScheme: { touchControlsType: { values: [['classic', 'Classic'], ['joystick-buttons', 'New']], }, + autoJump: { + values: [ + 'always', + 'auto', + 'never' + ], + }, }, { custom () { diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index 9e13bf47..25c8b3c7 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -71,6 +71,7 @@ const defaultOptions = { showCursorBlockInSpectator: false, renderEntities: true, chatSelect: false, + autoJump: 'auto' as 'auto' | 'always' | 'never', // advanced bot options autoRespawn: false, From 219f525409cea9e3e92229f2e6e522a9c2d5fae9 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 16 Apr 2024 06:37:22 +0300 Subject: [PATCH 0016/1097] support for custom input keys / gamepad buttons (no ui yet) --- package.json | 2 +- pnpm-lock.yaml | 9 +++++---- src/controls.ts | 11 ++++++++--- src/index.ts | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index b91bb11e..d6969dc2 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "constants-browserify": "^1.0.0", - "contro-max": "^0.1.1", + "contro-max": "^0.1.2", "crypto-browserify": "^3.12.0", "cypress": "^10.11.0", "cypress-esbuild-preprocessor": "^1.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c43c6ba..b9857220 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -244,8 +244,8 @@ importers: specifier: ^1.0.0 version: 1.0.0 contro-max: - specifier: ^0.1.1 - version: 0.1.1(typescript@5.2.2) + specifier: ^0.1.2 + version: 0.1.2(typescript@5.2.2) crypto-browserify: specifier: ^3.12.0 version: 3.12.0 @@ -7091,8 +7091,9 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - /contro-max@0.1.1(typescript@5.2.2): - resolution: {integrity: sha512-H+bzJWxiuxu98Tz8iGs1occMkRlr9fOzfOKeflVU8bD5teAEiJu8zjVnNSbweLQIR+Vhdynygv18N69t97rVAw==} + /contro-max@0.1.2(typescript@5.2.2): + resolution: {integrity: sha512-mY9aRQ9on/iyzvyhb4OD/10WRRKulVd92F7cxMFVn3rq5EwI+gZitGpHN2mp9+IzwRgBJrOKr1C051b3YlEktQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: emittery: 0.10.2 lodash-es: 4.17.21 diff --git a/src/controls.ts b/src/controls.ts index 48c05179..90ca29bf 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -16,8 +16,8 @@ import { showOptionsModal } from './react/SelectOption' import widgets from './react/widgets' import { getItemFromBlock } from './botUtils' -// doesnt seem to work for now -const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}')) +// todo move this to shared file with component +export const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}')) subscribe(customKeymaps, () => { localStorage.keymap = JSON.parse(customKeymaps) }) @@ -322,11 +322,16 @@ document.addEventListener('keydown', (e) => { if (!isGameActive(false)) return if (hardcodedPressedKeys.has('F3')) { const keybind = f3Keybinds.find((v) => v.key === e.code) - if (keybind) keybind.action() + if (keybind) { + keybind.action() + e.stopPropagation() + } return } hardcodedPressedKeys.add(e.code) +}, { + capture: true, }) document.addEventListener('keyup', (e) => { hardcodedPressedKeys.delete(e.code) diff --git a/src/index.ts b/src/index.ts index 7fd99b14..edbd8a92 100644 --- a/src/index.ts +++ b/src/index.ts @@ -871,7 +871,7 @@ document.body.addEventListener('touchend', (e) => { activeTouch = undefined }) document.body.addEventListener('touchstart', (e) => { - const ignoreElem = (e.target as HTMLElement).matches('vercel-live-feedback') + const ignoreElem = (e.target as HTMLElement).matches('vercel-live-feedback') || (e.target as HTMLElement).closest('.hotbar') if (!isGameActive(true) || ignoreElem) return // we always prevent default behavior to disable magnifier on ios, but by doing so we also disable click events e.preventDefault() From f747ff1c2b9dd8e11826a384874721642b56e166 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 16 Apr 2024 06:43:24 +0300 Subject: [PATCH 0017/1097] feat: auto parkour mode! (implies auto-jump) --- src/entities.ts | 9 ++++++--- src/optionsGuiScheme.tsx | 3 +++ src/optionsStorage.ts | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/entities.ts b/src/entities.ts index 58c445f1..59a43772 100644 --- a/src/entities.ts +++ b/src/entities.ts @@ -8,10 +8,10 @@ import { miscUiState } from './globalState' const updateAutoJump = () => { if (!bot?.autoJumper) return - const autoJump = options.autoJump === 'auto' ? miscUiState.currentTouch && !miscUiState.usingGamepadInput : options.autoJump === 'always' + const autoJump = options.parkourMode || (options.autoJump === 'auto' ? miscUiState.currentTouch && !miscUiState.usingGamepadInput : options.autoJump === 'always') bot.autoJumper.setOpts({ - jumpIntoWater: false, - jumpOnAllEdges: false, + jumpIntoWater: options.parkourMode, + jumpOnAllEdges: options.parkourMode, // strictBlockCollision: true, }) if (autoJump) { @@ -23,6 +23,9 @@ const updateAutoJump = () => { subscribeKey(options, 'autoJump', () => { updateAutoJump() }) +subscribeKey(options, 'parkourMode', () => { + updateAutoJump() +}) subscribeKey(miscUiState, 'usingGamepadInput', () => { updateAutoJump() }) diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index b54f3498..71ea9cd3 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -221,6 +221,9 @@ export const guiOptionsScheme: { const { touchControlsType } = useSnapshot(options) return + + + })} + + })} + + +} + +const AwaitingInputOverlay = ({ isGamepad }) => { + return
+ {isGamepad ? 'Press the button on the gamepad' : 'Press the key'}. + Press ESC to cancel. +
+} diff --git a/src/react/MessageFormatted.css b/src/react/MessageFormatted.css new file mode 100644 index 00000000..7e5be00a --- /dev/null +++ b/src/react/MessageFormatted.css @@ -0,0 +1,5 @@ +/* base global styles */ + +.formatted-message { + text-shadow: 1px 1px 0px #3f3f3f;; +} diff --git a/src/react/MessageFormatted.tsx b/src/react/MessageFormatted.tsx index cc1a089c..95ab064c 100644 --- a/src/react/MessageFormatted.tsx +++ b/src/react/MessageFormatted.tsx @@ -2,9 +2,10 @@ import { ComponentProps } from 'react' import { render } from '@xmcl/text-component' import { noCase } from 'change-case' import mojangson from 'mojangson' +import { openURL } from 'prismarine-viewer/viewer/lib/simpleUtils' import { MessageFormatPart } from '../botUtils' -import { openURL } from '../menus/components/common' import { chatInputValueGlobal } from './ChatContainer' +import './MessageFormatted.css' const hoverItemToText = (hoverEvent: MessageFormatPart['hoverEvent']) => { try { @@ -27,7 +28,7 @@ const hoverItemToText = (hoverEvent: MessageFormatPart['hoverEvent']) => { } } catch (err) { // todo report critical error - console.error('Failed to parse message hover', err) + reportError?.('Failed to parse message hover' + err.message) return undefined } } @@ -84,7 +85,7 @@ export const MessagePart = ({ part, ...props }: { part: MessageFormatPart } & Co export default ({ parts }: { parts: readonly MessageFormatPart[] }) => { return ( - + {parts.map((part, i) => )} ) diff --git a/src/react/MobileTopButtons.module.css b/src/react/MobileTopButtons.module.css new file mode 100644 index 00000000..1b142d3f --- /dev/null +++ b/src/react/MobileTopButtons.module.css @@ -0,0 +1,37 @@ +.mobile-top-btns { + display: none; + flex-direction: row; + position: fixed; + top: 0; + left: 50%; + transform: translate(-50%); + gap: 0 5px; + z-index: -1; +} + +.pause-btn, +.chat-btn { + --scale: 1.3; + border: none; + outline: 0.5px solid white; + width: calc(14px * var(--scale)); + height: calc(14px * var(--scale)); + background-image: url('extra-textures/gui.png'); + background-size: calc(256px * var(--scale)); + background-position-x: calc(var(--scale) * -202px); + background-position-y: calc(var(--scale) * -66px); +} + +.chat-btn { + background-position-y: calc(var(--scale) * -84px); +} +.debug-btn { + background: #9c8c86; + font-size: 8px; + /* todo make other buttons centered */ + /* margin-right: 5px; */ + color: white; + font-family: minecraft, mojangles, monospace; + padding: 4px 6px; + outline: 0.5px solid white; +} diff --git a/src/react/MobileTopButtons.tsx b/src/react/MobileTopButtons.tsx new file mode 100644 index 00000000..c4acb028 --- /dev/null +++ b/src/react/MobileTopButtons.tsx @@ -0,0 +1,57 @@ +import { useEffect, useRef } from 'react' +import { f3Keybinds } from '../controls' +import { watchValue } from '../optionsStorage' +import { showModal, miscUiState, activeModalStack, hideCurrentModal } from '../globalState' +import { showOptionsModal } from './SelectOption' +import useLongPress from './useLongPress' +import styles from './MobileTopButtons.module.css' + + +export default () => { + const elRef = useRef(null) + + const showMobileControls = (bl) => { + if (elRef.current) elRef.current.style.display = bl ? 'flex' : 'none' + } + + useEffect(() => { + watchValue(miscUiState, o => { + showMobileControls(o.currentTouch) + }) + }, []) + + const onLongPress = async () => { + const select = await showOptionsModal('', f3Keybinds.filter(f3Keybind => f3Keybind.mobileTitle).map(f3Keybind => f3Keybind.mobileTitle)) + if (!select) return + const f3Keybind = f3Keybinds.find(f3Keybind => f3Keybind.mobileTitle === select) + if (f3Keybind) f3Keybind.action() + } + + const defaultOptions = { + shouldPreventDefault: true, + delay: 500, + } + const longPressEvent = useLongPress(onLongPress, () => {}, defaultOptions) + + // ios note: just don't use +
+ + +
+ + {singleplayer ? ( +
+ + {(navigator.share as typeof navigator.share | undefined) ? ( +
+ ) : null} + + + +} diff --git a/src/react/PlayerListOverlay.css b/src/react/PlayerListOverlay.css new file mode 100644 index 00000000..b36801c0 --- /dev/null +++ b/src/react/PlayerListOverlay.css @@ -0,0 +1,80 @@ + +.playerlist-container { + position: absolute; + background-color: rgba(0, 0, 0, 0.3); + top: 9px; + left: 50%; + transform: translate(-50%); + width: fit-content; + padding: 1px; + display: flex; + flex-direction: column; + gap: 1px 0; + place-items: center; + z-index: 30; +} + +.playerlist-header, .playerlist-footer { + font-size: 0.5rem +} + +.playerlist-title { + color: white; + text-shadow: 1px 1px 0px #3f3f3f; + font-size: 10px; + margin: 0; + padding: 0; +} + +.playerlist-entry { + overflow: hidden; + color: white; + font-size: 10px; + margin: 0px; + line-height: calc(100% - 1px); + text-shadow: 1px 1px 0px #3f3f3f; + font-family: mojangles, minecraft, monospace; + background: rgba(255, 255, 255, 0.1); + width: 100%; +} + +.active-player { + color: rgb(42, 204, 237); + text-shadow: 1px 1px 0px rgb(4, 44, 67); +} + +.playerlist-ping { + text-align: right; + float: right; + padding-left: 10px; +} + +.playerlist-ping-value { + color: rgb(114, 255, 114); + text-shadow: 1px 1px 0px rgb(28, 105, 28); + float: left; + margin: 0; + margin-right: 1px; +} + +.playerlist-ping-label { + text-shadow: 1px 1px 0px #3f3f3f; + color: white; + float: right; + margin: 0px; +} + +.player-lists { + display: flex; + flex-direction: row; + place-items: center; + place-content: center; + gap: 0 4px; +} + +.player-list { + display: flex; + flex-direction: column; + gap: 1px 0; + min-width: 80px; +} diff --git a/src/react/PlayerListOverlay.stories.tsx b/src/react/PlayerListOverlay.stories.tsx new file mode 100644 index 00000000..cb2d972f --- /dev/null +++ b/src/react/PlayerListOverlay.stories.tsx @@ -0,0 +1,20 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import PlayerListOverlay from './PlayerListOverlay' + +const meta: Meta = { + component: PlayerListOverlay +} + +export default meta +type Story = StoryObj; + +export const Primary: Story = { + args: { + playersLists: [], + clientId: '', + tablistHeader: 'Header', + tablistFooter: 'Footer', + serverIP: '95.163.228.101', + } +} diff --git a/src/react/PlayerListOverlay.tsx b/src/react/PlayerListOverlay.tsx new file mode 100644 index 00000000..ee43ae2c --- /dev/null +++ b/src/react/PlayerListOverlay.tsx @@ -0,0 +1,41 @@ +import MessageFormattedString from './MessageFormattedString' +import './PlayerListOverlay.css' + + +type PlayersLists = Array> + +type PlayerListOverlayProps = { + playersLists: PlayersLists, + clientId: string, + tablistHeader: string | Record | null, + tablistFooter: string | Record | null, + serverIP: string +} + +export default ({ playersLists, clientId, tablistHeader, tablistFooter, serverIP }: PlayerListOverlayProps) => { + + return
+ Server IP: {serverIP} +
+ +
+
+ {playersLists.map((list, index) => ( +
+ {list.map(player => ( +
+ +
+

{player.ping}

+

ms

+
+
+ ))} +
+ ))} +
+
+ +
+
+} diff --git a/src/react/PlayerListOverlayProvider.tsx b/src/react/PlayerListOverlayProvider.tsx new file mode 100644 index 00000000..42e8c735 --- /dev/null +++ b/src/react/PlayerListOverlayProvider.tsx @@ -0,0 +1,91 @@ +import { useSnapshot } from 'valtio' +import { useState, useEffect, useMemo } from 'react' +import { isGameActive, miscUiState } from '../globalState' +import MessageFormattedString from './MessageFormattedString' +import PlayerListOverlay from './PlayerListOverlay' +import './PlayerListOverlay.css' + + +const MAX_ROWS_PER_COL = 10 + +type Players = typeof bot.players + +export default () => { + const { serverIp } = useSnapshot(miscUiState) + const [clientId, setClientId] = useState('') + const [players, setPlayers] = useState({}) + const [isOpen, setIsOpen] = useState(false) + + const handleKeyDown = (e) => { + if (!isGameActive(true)) return + if (e.key === 'Tab') { + setIsOpen(prev => true) + e.preventDefault() + } + } + + const handleKeyUp = (e) => { + if (e.key === 'Tab') { + setIsOpen(prev => false) + e.preventDefault() + } + } + + useMemo(() => { + function requestUpdate () { + // Placeholder for requestUpdate logic + setPlayers(bot.players) + } + + bot.on('playerUpdated', () => requestUpdate()) + bot.on('playerJoined', () => requestUpdate()) + bot.on('playerLeft', () => requestUpdate()) + }, []) + + useEffect(() => { + setPlayers(bot.players) + if (bot.player) { + setClientId(bot.player.uuid) + } else { + bot._client.on('player_info', () => { + setClientId(bot.player?.uuid) + }) + } + + document.addEventListener('keydown', handleKeyDown) + document.addEventListener('keyup', handleKeyUp) + + return () => { + document.removeEventListener('keydown', handleKeyDown) + document.removeEventListener('keyup', handleKeyUp) + } + }, [serverIp]) + + + const playersArray = Object.values(players).sort((a, b) => { + if (a.username > b.username) return 1 + if (a.username < b.username) return -1 + return 0 + }) + const lists = [] as Array + + let tempList = [] as typeof playersArray + for (let i = 0; i < playersArray.length; i++) { + tempList.push(playersArray[i]) + + if ((i + 1) % MAX_ROWS_PER_COL === 0 || i + 1 === playersArray.length) { + lists.push([...tempList]) + tempList = [] + } + } + + if (!isOpen) return null + + return +} diff --git a/src/react/SharedHudVars.tsx b/src/react/SharedHudVars.tsx new file mode 100644 index 00000000..acdcc237 --- /dev/null +++ b/src/react/SharedHudVars.tsx @@ -0,0 +1,27 @@ +import { CSSProperties, useEffect } from 'react' +import icons from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/icons.png' + +export default ({ children }) => { + useEffect(() => { + if (document.getElementById('hud-vars-style')) return + // 1. Don't inline long data URLs for better DX in elements tab + // 2. Easier application to globally override icons with custom image (eg from resourcepacks) + const css = /* css */` + :root { + --gui-icons: url(${icons}), url(${icons}); + } + ` + const style = document.createElement('style') + style.id = 'hud-vars-style' + style.textContent = css + document.head.appendChild(style) + }, []) + + const customVars = { + '--safe-area-inset-bottom': 'calc(env(safe-area-inset-bottom) / 2)' + } as CSSProperties + + return
{children}
+} diff --git a/src/react/Singleplayer.tsx b/src/react/Singleplayer.tsx index c00ffc8c..a4d8c559 100644 --- a/src/react/Singleplayer.tsx +++ b/src/react/Singleplayer.tsx @@ -51,8 +51,8 @@ const World = ({ name, isFocused, title, lastPlayed, size, detail = '', onFocus, world preview
{title}
-
{timeRelativeFormatted} {detail.slice(-30)}
-
{sizeFormatted}
+
{timeRelativeFormatted} {detail.slice(-30)}
+
{sizeFormatted}
} diff --git a/src/react/XPBar.module.css b/src/react/XPBar.module.css new file mode 100644 index 00000000..e9598f99 --- /dev/null +++ b/src/react/XPBar.module.css @@ -0,0 +1,33 @@ +.xp-bar-bg { + z-index: -1; + position: fixed; + left: 50%; + bottom: calc(var(--safe-area-inset-bottom) + 25px); + transform: translate(-50%); + width: 182px; + height: 5px; + background-image: url('minecraft-assets/minecraft-assets/data/1.16.4/gui/icons.png'); + background-size: 256px; + background-position-y: -64px; +} + +.xp-bar { + width: 182px; + height: 5px; + background-image: url('minecraft-assets/minecraft-assets/data/1.17.1/gui/icons.png'); + background-size: 256px; + background-position-y: -69px; +} + + +.xp-label { + position: fixed; + top: -8px; + left: 50%; + transform: translate(-50%); + font-size: 10px; + font-family: minecraft, mojangles, monospace; + color: rgb(30, 250, 30); + text-shadow: 0px -1px #000, 0px 1px #000, 1px 0px #000, -1px 0px #000; + z-index: 10; +} diff --git a/src/react/XPBar.stories.tsx b/src/react/XPBar.stories.tsx new file mode 100644 index 00000000..a7890b1a --- /dev/null +++ b/src/react/XPBar.stories.tsx @@ -0,0 +1,28 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import XPBar from './XPBar' + +const meta: Meta = { + component: XPBar +} + +export default meta +type Story = StoryObj; + +export const Primary: Story = { + args: { + progress: 1, + level: 5 + }, + // add slider for progress + argTypes: { + progress: { + control: { + type: 'range', + min: 0, + max: 1, + step: 0.1 + } + } + } +} diff --git a/src/react/XPBar.tsx b/src/react/XPBar.tsx new file mode 100644 index 00000000..1b3a7a85 --- /dev/null +++ b/src/react/XPBar.tsx @@ -0,0 +1,16 @@ +import SharedHudVars from './SharedHudVars' +import styles from './XPBar.module.css' + +export default ({ progress, level, gamemode }: { progress: number; level: number, gamemode: string }) => ( + +
+
+ 0 ? 'block' : 'none' }}>{level} +
+
+) + diff --git a/src/react/XPBarProvider.tsx b/src/react/XPBarProvider.tsx new file mode 100644 index 00000000..4ee1a392 --- /dev/null +++ b/src/react/XPBarProvider.tsx @@ -0,0 +1,26 @@ +import { useState, useMemo } from 'react' +import { GameMode } from 'mineflayer' +import XPBar from './XPBar' + + +export default () => { + const [progress, setProgress] = useState(0) + const [level, setLevel] = useState(0) + const [gamemode, setGamemode] = useState(bot.game.gameMode) + + useMemo(() => { + const onXpUpdate = () => { + setProgress(bot.experience.progress) + setLevel(bot.experience.level) + } + onXpUpdate() + + bot.on('experience', onXpUpdate) + + bot.on('game', () => { + setGamemode(prev => bot.game.gameMode) + }) + }, []) + + return +} diff --git a/src/react/armorValues.ts b/src/react/armorValues.ts new file mode 100644 index 00000000..cf17edbc --- /dev/null +++ b/src/react/armorValues.ts @@ -0,0 +1,52 @@ +interface Armor { + 'helmet': number; + 'chestplate': number | null; + 'leggings': number | null; + 'boots': number | null; +} + +export const armor: { [material: string]: Armor } = { + 'turtle': { + 'helmet': 2, + 'chestplate': null, + 'leggings': null, + 'boots': null + }, + 'leather': { + 'helmet': 1, + 'chestplate': 3, + 'leggings': 2, + 'boots': 1 + }, + 'golden': { + 'helmet': 2, + 'chestplate': 5, + 'leggings': 3, + 'boots': 1 + }, + 'chainmail': { + 'helmet': 2, + 'chestplate': 5, + 'leggings': 4, + 'boots': 1 + }, + 'iron': { + 'helmet': 2, + 'chestplate': 6, + 'leggings': 5, + 'boots': 2 + }, + 'diamond': { + 'helmet': 3, + 'chestplate': 8, + 'leggings': 6, + 'boots': 3 + }, + 'netherite': { + 'helmet': 3, + 'chestplate': 8, + 'leggings': 6, + 'boots': 3 + } +} + diff --git a/src/react/simpleUtils.ts b/src/react/simpleUtils.ts new file mode 100644 index 00000000..d9519d20 --- /dev/null +++ b/src/react/simpleUtils.ts @@ -0,0 +1,5 @@ +import prettyBytes from 'pretty-bytes' + +export const getFixedFilesize = (bytes: number) => { + return prettyBytes(bytes, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) +} diff --git a/src/react/singleplayer.module.css b/src/react/singleplayer.module.css index 3258ba29..1e092b39 100644 --- a/src/react/singleplayer.module.css +++ b/src/react/singleplayer.module.css @@ -34,6 +34,10 @@ flex-direction: column; font-size: 11px; } +.world_info_description_line { + color: #999; + white-space: nowrap; +} .world_image { height: 100%; aspect-ratio: 1; diff --git a/src/react/useLongPress.ts b/src/react/useLongPress.ts new file mode 100644 index 00000000..3807221d --- /dev/null +++ b/src/react/useLongPress.ts @@ -0,0 +1,64 @@ +import { useCallback, useRef, useState } from 'react' + +interface LongPressOptions { + shouldPreventDefault?: boolean; + delay?: number; +} + +const useLongPress = ( + onLongPress: () => void, + onClick: () => void, + { shouldPreventDefault = true, delay = 300 }: LongPressOptions = {} +) => { + const [longPressTriggered, setLongPressTriggered] = useState(false) + const timeout = useRef() + const target = useRef(null) + + const start = useCallback( + (event: React.MouseEvent | React.TouchEvent) => { + if (shouldPreventDefault && event.target) { + event.target.addEventListener('touchend', preventDefault, { + passive: false + }) + target.current = event.target + } + timeout.current = window.setTimeout(() => { + onLongPress() + setLongPressTriggered(true) + }, delay) + }, + [onLongPress, delay, shouldPreventDefault] + ) + + const clear = useCallback( + (event: React.MouseEvent | React.TouchEvent, shouldTriggerClick = true) => { + if (timeout.current) clearTimeout(timeout.current) + if (shouldTriggerClick && !longPressTriggered) onClick() + setLongPressTriggered(false) + if (shouldPreventDefault && target.current) { + target.current.removeEventListener('touchend', preventDefault) + } + }, + [shouldPreventDefault, onClick, longPressTriggered] + ) + + return { + onMouseDown: (e: React.MouseEvent) => start(e), + onTouchStart: (e: React.TouchEvent) => start(e), + onMouseUp: (e: React.MouseEvent) => clear(e), + onMouseLeave: (e: React.MouseEvent) => clear(e, false), + onTouchEnd: (e: React.TouchEvent) => clear(e) + } +} + +const preventDefault = (event: Event) => { + if (!('touches' in event)) return + + const touchEvent = event as TouchEvent + if (touchEvent.touches.length < 2 && event.preventDefault) { + event.preventDefault() + } +} + +export default useLongPress + diff --git a/src/reactUi.tsx b/src/reactUi.tsx index d56cb805..4c5f1516 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -3,6 +3,7 @@ import { renderToDom, ErrorBoundary } from '@zardoy/react-util' import { useSnapshot } from 'valtio' import { QRCodeSVG } from 'qrcode.react' import { createPortal } from 'react-dom' +import { useEffect, useMemo, useState } from 'react' import { miscUiState } from './globalState' import DeathScreenProvider from './react/DeathScreenProvider' import OptionsRenderApp from './react/OptionsRenderApp' @@ -17,6 +18,12 @@ import TitleProvider from './react/TitleProvider' import ScoreboardProvider from './react/ScoreboardProvider' import SignEditorProvider from './react/SignEditorProvider' import IndicatorEffectsProvider from './react/IndicatorEffectsProvider' +import PlayerListOverlayProvider from './react/PlayerListOverlayProvider' +import HudBarsProvider from './react/HudBarsProvider' +import XPBarProvider from './react/XPBarProvider' +import DebugOverlay from './react/DebugOverlay' +import MobileTopButtons from './react/MobileTopButtons' +import PauseScreen from './react/PauseScreen' import SoundMuffler from './react/SoundMuffler' import TouchControls from './react/TouchControls' import widgets from './react/widgets' @@ -24,6 +31,8 @@ import { useIsWidgetActive } from './react/utils' import GlobalSearchInput from './GlobalSearchInput' import TouchAreasControlsProvider from './react/TouchAreasControlsProvider' import NotificationProvider, { showNotification } from './react/NotificationProvider' +import HotbarRenderApp from './react/HotbarRenderApp' +import Crosshair from './react/Crosshair' const RobustPortal = ({ children, to }) => { return createPortal({children}, to) @@ -54,6 +63,25 @@ const DisplayQr = () => { } +// mounted earlier than ingame ui TODO +const GameHud = ({ children }) => { + const { loadedDataVersion } = useSnapshot(miscUiState) + const [gameLoaded, setGameLoaded] = useState(false) + + useEffect(() => { + customEvents.on('mineflayerBotCreated', () => { + bot.once('inject_allowed', () => { + setGameLoaded(true) + }) + }) + }, []) + useEffect(() => { + if (!loadedDataVersion) setGameLoaded(false) + }, [loadedDataVersion]) + + return gameLoaded ? children : null +} + const InGameUi = () => { const { gameLoaded } = useSnapshot(miscUiState) if (!gameLoaded) return @@ -62,12 +90,21 @@ const InGameUi = () => { {/* apply scaling */} + + + + + + + + + @@ -105,6 +142,8 @@ const App = () => { + {/* + */} } @@ -121,3 +160,17 @@ renderToDom(, { strictMode: false, selector: '#react-root', }) + +disableReactProfiling() +function disableReactProfiling () { + //@ts-expect-error + window.performance.markOrig = window.performance.mark + //@ts-expect-error + window.performance.mark = (name, options) => { + // ignore react internal marks + if (!name.startsWith('⚛') && !localStorage.enableReactProfiling) { + //@ts-expect-error + window.performance.markOrig(name, options) + } + } +} diff --git a/src/scaleInterface.ts b/src/scaleInterface.ts new file mode 100644 index 00000000..9eac457d --- /dev/null +++ b/src/scaleInterface.ts @@ -0,0 +1,31 @@ +import { proxy } from 'valtio' +import { subscribeKey } from 'valtio/utils' +import { options } from './optionsStorage' + +export const currentScaling = proxy({ + scale: 1, +}) + +const setScale = () => { + const scaleValues = [ + { width: 971, height: 670, scale: 2 }, + { width: null, height: 430, scale: 1.5 }, + { width: 590, height: null, scale: 1 } + ] + + const { innerWidth, innerHeight } = window + + let result = options.guiScale + for (const { width, height, scale } of scaleValues) { + if ((width && innerWidth <= width) || (height && innerHeight <= height)) { + result = scale + } + } + + currentScaling.scale = result + document.documentElement.style.setProperty('--guiScale', String(result)) +} + +setScale() +subscribeKey(options, 'guiScale', setScale) +window.addEventListener('resize', setScale) diff --git a/src/texturePack.ts b/src/texturePack.ts index 8c251b49..566e10da 100644 --- a/src/texturePack.ts +++ b/src/texturePack.ts @@ -6,7 +6,7 @@ import { subscribeKey } from 'valtio/utils' import { proxy, ref } from 'valtio' import { getVersion } from 'prismarine-viewer/viewer/lib/version' import blocksFileNames from '../generated/blocks.json' -import type { BlockStates } from './playerWindows' +import type { BlockStates } from './inventoryWindows' import { copyFilesAsync, copyFilesAsyncWithProgress, mkdirRecursive, removeFileRecursiveAsync } from './browserfs' import { setLoadingScreenStatus } from './utils' import { showNotification } from './react/NotificationProvider' diff --git a/src/watchOptions.ts b/src/watchOptions.ts index 4380c6f3..1493e7d1 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -14,7 +14,7 @@ watchValue(options, o => { document.documentElement.style.setProperty('--chatScale', `${o.chatScale / 100}`) document.documentElement.style.setProperty('--chatWidth', `${o.chatWidth}px`) document.documentElement.style.setProperty('--chatHeight', `${o.chatHeight}px`) - document.documentElement.style.setProperty('--guiScale', `${o.guiScale}`) + // gui scale is set in scaleInterface.ts }) /** happens once */ From 7a28dfc4888d4d546d6dbfdc7944494de1da8c4a Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 20 Apr 2024 22:10:10 +0300 Subject: [PATCH 0046/1097] fix water fog --- src/water.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/water.ts b/src/water.ts index 8bdb2698..9f8ec557 100644 --- a/src/water.ts +++ b/src/water.ts @@ -9,8 +9,8 @@ customEvents.on('gameLoaded', () => { watchUnloadForCleanup(cleanup) const updateInWater = () => { - const waterBr = bot.entity.effects.find(effect => loadedData.effects[effect.id].name === 'water_breathing') - if (inWater && waterBr) { + const waterBr = Object.keys(bot.entity.effects).find((effect: any) => loadedData.effects[effect.id].name === 'water_breathing') + if (inWater) { viewer.scene.fog = new THREE.Fog(0x00_00_ff, 0.1, waterBr ? 100 : 20) // Set the fog color to blue if the bot is in water. } else { cleanup() From 241e5d3d1aa528b0a45b8b961b0c16b8d6fb2714 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Wed, 24 Apr 2024 17:10:44 +0300 Subject: [PATCH 0047/1097] do not override pnpm ver --- .github/workflows/preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 2f866235..9da50d0a 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -28,7 +28,7 @@ jobs: node-version: 18 cache: "pnpm" - name: Install Global Dependencies - run: npm install --global vercel pnpm + run: npm install --global vercel - name: Pull Vercel Environment Information run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} - name: Build Project Artifacts From 619aa5b06376e4fcf6335205cd350dd977ae367b Mon Sep 17 00:00:00 2001 From: Vitaly Date: Wed, 24 Apr 2024 17:16:16 +0300 Subject: [PATCH 0048/1097] optimize light update in single chunks --- prismarine-viewer/viewer/lib/viewer.ts | 8 ++++---- prismarine-viewer/viewer/lib/worldDataEmitter.ts | 6 +++--- prismarine-viewer/viewer/lib/worldrendererCommon.ts | 12 +++++++----- src/watchOptions.ts | 3 ++- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts index 1b11ac63..9cb7eb3d 100644 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ b/prismarine-viewer/viewer/lib/viewer.ts @@ -77,8 +77,8 @@ export class Viewer { // this.primitives.clear() } - addColumn (x, z, chunk) { - this.world.addColumn(x, z, chunk) + addColumn (x, z, chunk, isLightUpdate = false) { + this.world.addColumn(x, z, chunk, isLightUpdate) } removeColumn (x: string, z: string) { @@ -148,9 +148,9 @@ export class Viewer { // this.updatePrimitive(p) }) - emitter.on('loadChunk', ({ x, z, chunk, worldConfig }) => { + emitter.on('loadChunk', ({ x, z, chunk, worldConfig, isLightUpdate }) => { this.world.worldConfig = worldConfig - this.addColumn(x, z, chunk) + this.addColumn(x, z, chunk, isLightUpdate) }) // todo remove and use other architecture instead so data flow is clear emitter.on('blockEntities', (blockEntities) => { diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index fa916c51..6743e337 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -75,7 +75,7 @@ export class WorldDataEmitter extends EventEmitter { bot._client.on('update_light', ({ chunkX, chunkZ }) => { const chunkPos = new Vec3(chunkX * 16, 0, chunkZ * 16) - this.loadChunk(chunkPos) + this.loadChunk(chunkPos, true) }) this.emitter.on('listening', () => { @@ -128,7 +128,7 @@ export class WorldDataEmitter extends EventEmitter { } } - async loadChunk (pos: ChunkPos) { + async loadChunk (pos: ChunkPos, isLightUpdate = false) { const [botX, botZ] = chunkPos(this.lastPos) const dx = Math.abs(botX - Math.floor(pos.x / 16)) const dz = Math.abs(botZ - Math.floor(pos.z / 16)) @@ -143,7 +143,7 @@ export class WorldDataEmitter extends EventEmitter { worldHeight: column['worldHeight'] ?? 256, } //@ts-ignore - this.emitter.emit('loadChunk', { x: pos.x, z: pos.z, chunk, blockEntities: column.blockEntities, worldConfig }) + this.emitter.emit('loadChunk', { x: pos.x, z: pos.z, chunk, blockEntities: column.blockEntities, worldConfig, isLightUpdate }) this.loadedChunks[`${pos.x},${pos.z}`] = true } } else { diff --git a/prismarine-viewer/viewer/lib/worldrendererCommon.ts b/prismarine-viewer/viewer/lib/worldrendererCommon.ts index ae2a91d3..43983977 100644 --- a/prismarine-viewer/viewer/lib/worldrendererCommon.ts +++ b/prismarine-viewer/viewer/lib/worldrendererCommon.ts @@ -211,7 +211,7 @@ export abstract class WorldRendererCommon } - addColumn (x, z, chunk) { + addColumn (x: number, z: number, chunk: any, isLightUpdate: boolean) { if (this.workers.length === 0) throw new Error('workers not initialized yet') this.initialChunksLoad = false this.loadedChunks[`${x},${z}`] = true @@ -222,10 +222,12 @@ export abstract class WorldRendererCommon for (let y = this.worldConfig.minY; y < this.worldConfig.worldHeight; y += 16) { const loc = new Vec3(x, y, z) this.setSectionDirty(loc) - this.setSectionDirty(loc.offset(-16, 0, 0)) - this.setSectionDirty(loc.offset(16, 0, 0)) - this.setSectionDirty(loc.offset(0, 0, -16)) - this.setSectionDirty(loc.offset(0, 0, 16)) + if (!isLightUpdate || this.mesherConfig.smoothLighting) { + this.setSectionDirty(loc.offset(-16, 0, 0)) + this.setSectionDirty(loc.offset(16, 0, 0)) + this.setSectionDirty(loc.offset(0, 0, -16)) + this.setSectionDirty(loc.offset(0, 0, 16)) + } } } diff --git a/src/watchOptions.ts b/src/watchOptions.ts index 1493e7d1..009463be 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -44,7 +44,8 @@ export const watchOptionsAfterViewerInit = () => { viewer.entities.setVisible(o.renderEntities) }) - viewer.world.mesherConfig.smoothLighting = options.smoothLighting + // viewer.world.mesherConfig.smoothLighting = options.smoothLighting + viewer.world.mesherConfig.smoothLighting = false // todo not supported for now subscribeKey(options, 'smoothLighting', () => { viewer.world.mesherConfig.smoothLighting = options.smoothLighting; (viewer.world as WorldRendererThree).rerenderAllChunks() From d7f5e98fe35164fc9351f3bb814b1a260ffd784e Mon Sep 17 00:00:00 2001 From: Vitaly Date: Fri, 26 Apr 2024 09:44:04 +0300 Subject: [PATCH 0049/1097] update typescript to 5.5 --- package.json | 2 +- pnpm-lock.yaml | 138 +++++++++--------- .../viewer/lib/worldDataEmitter.ts | 4 +- src/inventoryWindows.ts | 4 +- src/react/MessageFormatted.tsx | 2 +- src/react/SoundMuffler.tsx | 6 +- 6 files changed, 78 insertions(+), 78 deletions(-) diff --git a/package.json b/package.json index e9981866..dee909a8 100644 --- a/package.json +++ b/package.json @@ -133,7 +133,7 @@ "stream-browserify": "^3.0.0", "three": "0.154.0", "timers-browserify": "^2.0.12", - "typescript": "^5.2.2", + "typescript": "5.5.0-beta", "use-typed-event-listener": "^4.0.2", "vitest": "^0.34.6", "yaml": "^2.3.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5eb5111a..fc504d17 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -207,16 +207,16 @@ importers: version: 7.4.6(@types/react-dom@18.2.7)(@types/react@18.2.20)(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/react': specifier: ^7.4.6 - version: 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.2.2) + version: 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.0-beta) '@storybook/react-vite': specifier: ^7.4.6 - version: 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@2.79.1)(typescript@5.2.2)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) + version: 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@2.79.1)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) '@storybook/web-components': specifier: ^7.4.6 version: 7.4.6(encoding@0.1.13)(lit@2.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@storybook/web-components-vite': specifier: ^7.4.6 - version: 7.4.6(encoding@0.1.13)(lit@2.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.2.2)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) + version: 7.4.6(encoding@0.1.13)(lit@2.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) '@types/lodash-es': specifier: ^4.17.9 version: 4.17.9 @@ -249,7 +249,7 @@ importers: version: 1.0.0 contro-max: specifier: ^0.1.2 - version: 0.1.2(typescript@5.2.2) + version: 0.1.2(typescript@5.5.0-beta) crypto-browserify: specifier: ^3.12.0 version: 3.12.0 @@ -264,7 +264,7 @@ importers: version: 8.50.0 eslint-config-zardoy: specifier: ^0.2.17 - version: 0.2.17(eslint-plugin-react-hooks@4.6.0(eslint@8.50.0))(eslint-plugin-react@7.34.1(eslint@8.50.0))(eslint@8.50.0)(typescript@5.2.2) + version: 0.2.17(eslint-plugin-react-hooks@4.6.0(eslint@8.50.0))(eslint-plugin-react@7.34.1(eslint@8.50.0))(eslint@8.50.0)(typescript@5.5.0-beta) events: specifier: ^3.3.0 version: 3.3.0 @@ -323,11 +323,11 @@ importers: specifier: ^2.0.12 version: 2.0.12 typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: 5.5.0-beta + version: 5.5.0-beta use-typed-event-listener: specifier: ^4.0.2 - version: 4.0.2(react@18.2.0)(typescript@5.2.2) + version: 4.0.2(react@18.2.0)(typescript@5.5.0-beta) vitest: specifier: ^0.34.6 version: 0.34.6(terser@5.19.2) @@ -7996,8 +7996,8 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript@5.2.2: - resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + typescript@5.5.0-beta: + resolution: {integrity: sha512-FRg3e/aQg3olEG3ff8YjHOERsO4IM0m4qGrsE4UMvILaq4TdDZ6gQX4+2Rq9SjTpfSe/ebwiHcsjm/7FfWWQ6Q==} engines: {node: '>=14.17'} hasBin: true @@ -10214,15 +10214,15 @@ snapshots: core-js: 3.32.1 regenerator-runtime: 0.13.11 - '@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.2.2)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': dependencies: glob: 7.2.3 glob-promise: 4.2.2(glob@7.2.3) magic-string: 0.27.0 - react-docgen-typescript: 2.2.2(typescript@5.2.2) + react-docgen-typescript: 2.2.2(typescript@5.5.0-beta) vite: 4.5.3(@types/node@20.8.0)(terser@5.19.2) optionalDependencies: - typescript: 5.2.2 + typescript: 5.5.0-beta '@jridgewell/gen-mapping@0.3.3': dependencies: @@ -10957,7 +10957,7 @@ snapshots: - encoding - supports-color - '@storybook/builder-vite@7.4.6(encoding@0.1.13)(typescript@5.2.2)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': + '@storybook/builder-vite@7.4.6(encoding@0.1.13)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': dependencies: '@storybook/channels': 7.4.6 '@storybook/client-logger': 7.4.6 @@ -10980,7 +10980,7 @@ snapshots: rollup: 3.29.4 vite: 4.5.3(@types/node@20.8.0)(terser@5.19.2) optionalDependencies: - typescript: 5.2.2 + typescript: 5.5.0-beta transitivePeerDependencies: - encoding - supports-color @@ -11264,12 +11264,12 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@storybook/react-vite@7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@2.79.1)(typescript@5.2.2)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': + '@storybook/react-vite@7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@2.79.1)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.2.2)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) '@rollup/pluginutils': 5.0.5(rollup@2.79.1) - '@storybook/builder-vite': 7.4.6(encoding@0.1.13)(typescript@5.2.2)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) - '@storybook/react': 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.2.2) + '@storybook/builder-vite': 7.4.6(encoding@0.1.13)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) + '@storybook/react': 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.0-beta) '@vitejs/plugin-react': 3.1.0(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) ast-types: 0.14.2 magic-string: 0.30.4 @@ -11285,7 +11285,7 @@ snapshots: - typescript - vite-plugin-glimmerx - '@storybook/react@7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.2.2)': + '@storybook/react@7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.0-beta)': dependencies: '@storybook/client-logger': 7.4.6 '@storybook/core-client': 7.4.6 @@ -11311,7 +11311,7 @@ snapshots: type-fest: 2.19.0 util-deprecate: 1.0.2 optionalDependencies: - typescript: 5.2.2 + typescript: 5.5.0-beta transitivePeerDependencies: - encoding - supports-color @@ -11354,9 +11354,9 @@ snapshots: '@types/express': 4.17.18 file-system-cache: 2.3.0 - '@storybook/web-components-vite@7.4.6(encoding@0.1.13)(lit@2.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.2.2)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': + '@storybook/web-components-vite@7.4.6(encoding@0.1.13)(lit@2.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': dependencies: - '@storybook/builder-vite': 7.4.6(encoding@0.1.13)(typescript@5.2.2)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) + '@storybook/builder-vite': 7.4.6(encoding@0.1.13)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) '@storybook/core-server': 7.4.6(encoding@0.1.13) '@storybook/node-logger': 7.4.6 '@storybook/web-components': 7.4.6(encoding@0.1.13)(lit@2.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -11674,13 +11674,13 @@ snapshots: '@types/node': 20.11.19 optional: true - '@typescript-eslint/eslint-plugin@6.1.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2))(eslint@8.50.0)(typescript@5.2.2)': + '@typescript-eslint/eslint-plugin@6.1.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta))(eslint@8.50.0)(typescript@5.5.0-beta)': dependencies: '@eslint-community/regexpp': 4.8.0 - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.5.0-beta) '@typescript-eslint/scope-manager': 6.1.0 - '@typescript-eslint/type-utils': 6.1.0(eslint@8.50.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.1.0(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/type-utils': 6.1.0(eslint@8.50.0)(typescript@5.5.0-beta) + '@typescript-eslint/utils': 6.1.0(eslint@8.50.0)(typescript@5.5.0-beta) '@typescript-eslint/visitor-keys': 6.1.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.50.0 @@ -11689,22 +11689,22 @@ snapshots: natural-compare: 1.4.0 natural-compare-lite: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.2.2) + ts-api-utils: 1.0.3(typescript@5.5.0-beta) optionalDependencies: - typescript: 5.2.2 + typescript: 5.5.0-beta transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2)': + '@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta)': dependencies: '@typescript-eslint/scope-manager': 6.7.3 '@typescript-eslint/types': 6.7.3 - '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.7.3(typescript@5.5.0-beta) '@typescript-eslint/visitor-keys': 6.7.3 debug: 4.3.4(supports-color@8.1.1) eslint: 8.50.0 optionalDependencies: - typescript: 5.2.2 + typescript: 5.5.0-beta transitivePeerDependencies: - supports-color @@ -11718,15 +11718,15 @@ snapshots: '@typescript-eslint/types': 6.7.3 '@typescript-eslint/visitor-keys': 6.7.3 - '@typescript-eslint/type-utils@6.1.0(eslint@8.50.0)(typescript@5.2.2)': + '@typescript-eslint/type-utils@6.1.0(eslint@8.50.0)(typescript@5.5.0-beta)': dependencies: - '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.2.2) - '@typescript-eslint/utils': 6.1.0(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.5.0-beta) + '@typescript-eslint/utils': 6.1.0(eslint@8.50.0)(typescript@5.5.0-beta) debug: 4.3.4(supports-color@8.1.1) eslint: 8.50.0 - ts-api-utils: 1.0.3(typescript@5.2.2) + ts-api-utils: 1.0.3(typescript@5.5.0-beta) optionalDependencies: - typescript: 5.2.2 + typescript: 5.5.0-beta transitivePeerDependencies: - supports-color @@ -11734,7 +11734,7 @@ snapshots: '@typescript-eslint/types@6.7.3': {} - '@typescript-eslint/typescript-estree@6.1.0(typescript@5.2.2)': + '@typescript-eslint/typescript-estree@6.1.0(typescript@5.5.0-beta)': dependencies: '@typescript-eslint/types': 6.1.0 '@typescript-eslint/visitor-keys': 6.1.0 @@ -11742,13 +11742,13 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.0 - ts-api-utils: 1.0.3(typescript@5.2.2) + ts-api-utils: 1.0.3(typescript@5.5.0-beta) optionalDependencies: - typescript: 5.2.2 + typescript: 5.5.0-beta transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@6.7.3(typescript@5.2.2)': + '@typescript-eslint/typescript-estree@6.7.3(typescript@5.5.0-beta)': dependencies: '@typescript-eslint/types': 6.7.3 '@typescript-eslint/visitor-keys': 6.7.3 @@ -11756,20 +11756,20 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.0 - ts-api-utils: 1.0.3(typescript@5.2.2) + ts-api-utils: 1.0.3(typescript@5.5.0-beta) optionalDependencies: - typescript: 5.2.2 + typescript: 5.5.0-beta transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@6.1.0(eslint@8.50.0)(typescript@5.2.2)': + '@typescript-eslint/utils@6.1.0(eslint@8.50.0)(typescript@5.5.0-beta)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.3 '@typescript-eslint/scope-manager': 6.1.0 '@typescript-eslint/types': 6.1.0 - '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.5.0-beta) eslint: 8.50.0 semver: 7.6.0 transitivePeerDependencies: @@ -12802,13 +12802,13 @@ snapshots: content-type@1.0.5: {} - contro-max@0.1.2(typescript@5.2.2): + contro-max@0.1.2(typescript@5.5.0-beta): dependencies: emittery: 0.10.2 lodash-es: 4.17.21 optionalDependencies: react: 18.2.0 - use-typed-event-listener: 4.0.2(react@18.2.0)(typescript@5.2.2) + use-typed-event-listener: 4.0.2(react@18.2.0)(typescript@5.5.0-beta) transitivePeerDependencies: - typescript @@ -13664,34 +13664,34 @@ snapshots: eslint-plugin-react: 7.34.1(eslint@8.50.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.50.0) - eslint-config-xo-typescript@1.0.1(@typescript-eslint/eslint-plugin@6.1.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2))(eslint@8.50.0)(typescript@5.2.2))(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2))(eslint@8.50.0)(typescript@5.2.2): + eslint-config-xo-typescript@1.0.1(@typescript-eslint/eslint-plugin@6.1.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta))(eslint@8.50.0)(typescript@5.5.0-beta))(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta))(eslint@8.50.0)(typescript@5.5.0-beta): dependencies: - '@typescript-eslint/eslint-plugin': 6.1.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2))(eslint@8.50.0)(typescript@5.2.2) - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/eslint-plugin': 6.1.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta))(eslint@8.50.0)(typescript@5.5.0-beta) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.5.0-beta) eslint: 8.50.0 - typescript: 5.2.2 + typescript: 5.5.0-beta eslint-config-xo@0.43.1(eslint@8.50.0): dependencies: confusing-browser-globals: 1.0.11 eslint: 8.50.0 - eslint-config-zardoy@0.2.17(eslint-plugin-react-hooks@4.6.0(eslint@8.50.0))(eslint-plugin-react@7.34.1(eslint@8.50.0))(eslint@8.50.0)(typescript@5.2.2): + eslint-config-zardoy@0.2.17(eslint-plugin-react-hooks@4.6.0(eslint@8.50.0))(eslint-plugin-react@7.34.1(eslint@8.50.0))(eslint@8.50.0)(typescript@5.5.0-beta): dependencies: '@rushstack/eslint-patch': 1.4.0 - '@typescript-eslint/eslint-plugin': 6.1.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2))(eslint@8.50.0)(typescript@5.2.2) - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/eslint-plugin': 6.1.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta))(eslint@8.50.0)(typescript@5.5.0-beta) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.5.0-beta) eslint: 8.50.0 eslint-config-prettier: 8.10.0(eslint@8.50.0) eslint-config-xo: 0.43.1(eslint@8.50.0) eslint-config-xo-react: 0.27.0(eslint-plugin-react-hooks@4.6.0(eslint@8.50.0))(eslint-plugin-react@7.34.1(eslint@8.50.0))(eslint@8.50.0) - eslint-config-xo-typescript: 1.0.1(@typescript-eslint/eslint-plugin@6.1.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2))(eslint@8.50.0)(typescript@5.2.2))(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2))(eslint@8.50.0)(typescript@5.2.2) + eslint-config-xo-typescript: 1.0.1(@typescript-eslint/eslint-plugin@6.1.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta))(eslint@8.50.0)(typescript@5.5.0-beta))(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta))(eslint@8.50.0)(typescript@5.5.0-beta) eslint-plugin-eslint-comments: 3.2.0(eslint@8.50.0) - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2))(eslint@8.50.0) + eslint-plugin-import: 2.27.5(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta))(eslint@8.50.0) eslint-plugin-node: 11.1.0(eslint@8.50.0) eslint-plugin-sonarjs: 0.19.0(eslint@8.50.0) eslint-plugin-unicorn: 48.0.0(eslint@8.50.0) - typescript: 5.2.2 + typescript: 5.5.0-beta transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -13707,11 +13707,11 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.5.0-beta) eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: @@ -13729,7 +13729,7 @@ snapshots: eslint: 8.50.0 ignore: 5.2.4 - eslint-plugin-import@2.27.5(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2))(eslint@8.50.0): + eslint-plugin-import@2.27.5(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta))(eslint@8.50.0): dependencies: array-includes: 3.1.7 array.prototype.flat: 1.3.2 @@ -13738,7 +13738,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.2.2))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.3(eslint@8.50.0)(typescript@5.5.0-beta))(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) has: 1.0.3 is-core-module: 2.13.0 is-glob: 4.0.3 @@ -13748,7 +13748,7 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.14.2 optionalDependencies: - '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.7.3(eslint@8.50.0)(typescript@5.5.0-beta) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -16791,9 +16791,9 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-docgen-typescript@2.2.2(typescript@5.2.2): + react-docgen-typescript@2.2.2(typescript@5.5.0-beta): dependencies: - typescript: 5.2.2 + typescript: 5.5.0-beta react-docgen@6.0.0-alpha.3: dependencies: @@ -17968,9 +17968,9 @@ snapshots: dependencies: utf8-byte-length: 1.0.4 - ts-api-utils@1.0.3(typescript@5.2.2): + ts-api-utils@1.0.3(typescript@5.5.0-beta): dependencies: - typescript: 5.2.2 + typescript: 5.5.0-beta ts-dedent@2.2.0: {} @@ -18092,7 +18092,7 @@ snapshots: typedarray@0.0.6: {} - typescript@5.2.2: {} + typescript@5.5.0-beta: {} ua-parser-js@1.0.37: {} @@ -18267,13 +18267,13 @@ snapshots: dependencies: react: 18.2.0 - use-typed-event-listener@4.0.2(react@18.2.0)(typescript@5.2.2): + use-typed-event-listener@4.0.2(react@18.2.0)(typescript@5.5.0-beta): dependencies: '@babel/runtime': 7.22.11 react: 18.2.0 use-deep-compare: 1.1.0(react@18.2.0) optionalDependencies: - typescript: 5.2.2 + typescript: 5.5.0-beta utf8-byte-length@1.0.4: {} diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index 6743e337..f4ce9675 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -186,8 +186,8 @@ export class WorldDataEmitter extends EventEmitter { const positions = generateSpiralMatrix(this.viewDistance).map(([x, z]) => { const pos = new Vec3((botX + x) * 16, 0, (botZ + z) * 16) if (!this.loadedChunks[`${pos.x},${pos.z}`]) return pos - return undefined! - }).filter(Boolean) + return undefined + }).filter(a => !!a) this.lastPos.update(pos) await this._loadChunks(positions) } else { diff --git a/src/inventoryWindows.ts b/src/inventoryWindows.ts index 3345b6cd..d9fda1c7 100644 --- a/src/inventoryWindows.ts +++ b/src/inventoryWindows.ts @@ -389,9 +389,9 @@ const upJei = (search: string) => { search = search.toLowerCase() // todo fix pre flat const matchedSlots = loadedData.itemsArray.map(x => { - if (!x.displayName.toLowerCase().includes(search)) return null! + if (!x.displayName.toLowerCase().includes(search)) return null return new PrismarineItem(x.id, 1) - }).filter(Boolean) + }).filter(a => a !== null) lastWindow.pwindow.win.jeiSlotsPage = 0 lastWindow.pwindow.win.jeiSlots = mapSlots(matchedSlots) } diff --git a/src/react/MessageFormatted.tsx b/src/react/MessageFormatted.tsx index 95ab064c..e9a0641a 100644 --- a/src/react/MessageFormatted.tsx +++ b/src/react/MessageFormatted.tsx @@ -78,7 +78,7 @@ export const MessagePart = ({ part, ...props }: { part: MessageFormatPart } & Co underlined && messageFormatStylesMap.underlined, strikethrough && messageFormatStylesMap.strikethrough, obfuscated && messageFormatStylesMap.obfuscated - ].filter(Boolean) + ].filter(a => a !== false && a !== undefined).filter(Boolean) return {text} } diff --git a/src/react/SoundMuffler.tsx b/src/react/SoundMuffler.tsx index 4f162940..869abc1c 100644 --- a/src/react/SoundMuffler.tsx +++ b/src/react/SoundMuffler.tsx @@ -42,16 +42,16 @@ export default () => { Last World Played {Object.entries(lastPlayedSounds.lastServerPlayed).map(([key, value]) => { - if (!showMuted && mutedSounds.includes(key)) return null as never + if (!showMuted && mutedSounds.includes(key)) return null return [key, value.count] as const - }).filter(Boolean).sort((a, b) => b[1] - a[1]).slice(0, 20).map(([key, count]) => { + }).filter(a => !!a).sort((a, b) => b[1] - a[1]).slice(0, 20).map(([key, count]) => { return {count} })} Last Client Played {lastPlayedSounds.lastClientPlayed.map((key) => { - if (!showMuted && mutedSounds.includes(key)) return null as never + if (!showMuted && mutedSounds.includes(key)) return null return })} From cf83844281217f4ec52b8f62855844511bd7343e Mon Sep 17 00:00:00 2001 From: Vitaly Date: Fri, 26 Apr 2024 09:44:47 +0300 Subject: [PATCH 0050/1097] fix annoying f3 issue --- src/react/MobileTopButtons.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/react/MobileTopButtons.tsx b/src/react/MobileTopButtons.tsx index c4acb028..c686bb0b 100644 --- a/src/react/MobileTopButtons.tsx +++ b/src/react/MobileTopButtons.tsx @@ -40,6 +40,7 @@ export default () => { }}>S
{ document.dispatchEvent(new KeyboardEvent('keydown', { code: 'F3' })) + document.dispatchEvent(new KeyboardEvent('keyup', { code: 'F3' })) }} { ...longPressEvent }>F3
{ e.stopPropagation() From b9aa44907100a7c3a136da6c39d26cfb46a1ab45 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 27 Apr 2024 15:51:06 +0300 Subject: [PATCH 0051/1097] fix ios hotbar, fix item name display, fix item select, fix inv open --- src/botUtils.ts | 2 +- src/react/HotbarRenderApp.tsx | 29 +++++++++++++++-------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/botUtils.ts b/src/botUtils.ts index 5dacbf4f..a76f889b 100644 --- a/src/botUtils.ts +++ b/src/botUtils.ts @@ -114,6 +114,6 @@ const blockToItemRemaps = { } export const getItemFromBlock = (block: import('prismarine-block').Block) => { - const item = loadedData.items[blockToItemRemaps[block.name] ?? block.name] + const item = loadedData.itemsByName[blockToItemRemaps[block.name] ?? block.name] return item } diff --git a/src/react/HotbarRenderApp.tsx b/src/react/HotbarRenderApp.tsx index 2e7ee1d1..e747c4e3 100644 --- a/src/react/HotbarRenderApp.tsx +++ b/src/react/HotbarRenderApp.tsx @@ -19,7 +19,7 @@ const ItemName = ({ itemKey }: { itemKey: string }) => { const defaultStyle: React.CSSProperties = { position: 'fixed', - bottom: `calc(var(--safe-area-inset-bottom) + ${bot ? bot.game.gameMode === 'creative' ? '35px' : '50px' : '50px'})`, + bottom: `calc(env(safe-area-inset-bottom) + ${bot ? bot.game.gameMode === 'creative' ? '35px' : '50px' : '50px'})`, left: 0, right: 0, fontSize: 10, @@ -117,7 +117,7 @@ export default () => { canvasManager.canvas.onpointerdown = (e) => { if (!isGameActive(true)) return const pos = inv.canvasManager.getMousePos(inv.canvas, e) - if (pos.x > canvasManager.canvas.width - 30) { + if (canvasManager.canvas.width - pos.x < 35 * inv.canvasManager.scale) { openPlayerInventory() } } @@ -135,7 +135,10 @@ export default () => { const heldItemChanged = () => { inv.inventory.activeHotbarSlot = bot.quickBarSlot - if (!bot.inventory.slots?.[bot.quickBarSlot + 36]) return + if (!bot.inventory.slots?.[bot.quickBarSlot + 36]) { + setItemKey('') + return + } const item = bot.inventory.slots[bot.quickBarSlot + 36]! const itemNbt = item.nbt ? JSON.stringify(item.nbt) : '' setItemKey(`${item.displayName}_split_${item.type}_split_${item.metadata}_split_${itemNbt}`) @@ -199,17 +202,15 @@ export default () => { return - -
- +
} From 6615984966ee22670965bbbacb418f30818833fa Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 27 Apr 2024 16:04:52 +0300 Subject: [PATCH 0052/1097] fix water rendering TODO still need to be correctly mapped to block named water instead --- prismarine-viewer/viewer/lib/mesher/world.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prismarine-viewer/viewer/lib/mesher/world.ts b/prismarine-viewer/viewer/lib/mesher/world.ts index 50616f82..63263809 100644 --- a/prismarine-viewer/viewer/lib/mesher/world.ts +++ b/prismarine-viewer/viewer/lib/mesher/world.ts @@ -114,6 +114,8 @@ export class World { } const block = this.blockCache[stateId] + if (block.name === 'flowing_water') block.name = 'water' + if (block.name === 'flowing_lava') block.name = 'lava' // block.position = loc // it overrides position of all currently loaded blocks block.biome = this.biomeCache[column.getBiome(locInChunk)] ?? this.biomeCache[1] ?? this.biomeCache[0] if (block.name === 'redstone_ore') block.transparent = false From a504d3f5aa9b830ea47db577f2cb593e328bd236 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 27 Apr 2024 16:11:38 +0300 Subject: [PATCH 0053/1097] disable some useless warnings --- src/loadSave.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/loadSave.ts b/src/loadSave.ts index 655fbea8..c332e670 100644 --- a/src/loadSave.ts +++ b/src/loadSave.ts @@ -85,8 +85,10 @@ export const loadSave = async (root = '/world') => { const qs = new URLSearchParams(window.location.search) version = qs.get('mapVersion') ?? levelDat.Version?.Name if (!version) { - const newVersion = disablePrompts ? '1.8.8' : prompt(`In 1.8 and before world save doesn't contain version info, please enter version you want to use to load the world.\nSupported versions ${supportedVersions.join(', ')}`, '1.8.8') - if (!newVersion) return + // const newVersion = disablePrompts ? '1.8.8' : prompt(`In 1.8 and before world save doesn't contain version info, please enter version you want to use to load the world.\nSupported versions ${supportedVersions.join(', ')}`, '1.8.8') + // if (!newVersion) return + // todo detect world load issues + const newVersion = '1.8.8' version = newVersion } const lastSupportedVersion = supportedVersions.at(-1)! @@ -110,7 +112,7 @@ export const loadSave = async (root = '/world') => { isFlat = levelDat.generatorName === 'flat' } if (!isFlat && levelDat.generatorName !== 'default' && levelDat.generatorName !== 'customized') { - warnings.push(`Generator ${levelDat.generatorName} may not be supported yet`) + // warnings.push(`Generator ${levelDat.generatorName} may not be supported yet, be careful of new chunks writes`) } const playerUuid = nameToMcOfflineUUID(options.localUsername) @@ -150,7 +152,7 @@ export const loadSave = async (root = '/world') => { if (!fsState.isReadonly && !fsState.inMemorySave && !disablePrompts) { // todo allow also to ctrl+s - alert('Note: the world is saved only on /save or disconnect! Ensure you have backup!') + alert('Note: the world is saved on interval, /save or disconnect! Ensure you have backup and be careful of new chunks writes!') } // improve compatibility with community saves From 9322e09a836a0d896ccaa0e5aa8ebd48e31f34f2 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 27 Apr 2024 22:55:25 +0300 Subject: [PATCH 0054/1097] fix: "modern" controls now correctly works with flying fix: right stick button on gamepad now toggles sneaking --- src/controls.ts | 13 +++++++++++-- src/react/HotbarRenderApp.tsx | 4 +++- src/react/TouchAreasControls.tsx | 29 ++++++++++++++++++++++------- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/controls.ts b/src/controls.ts index 734a2a6d..26405082 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -32,7 +32,8 @@ export const contro = new ControMax({ jump: ['Space', 'A'], inventory: ['KeyE', 'X'], drop: ['KeyQ', 'B'], - sneak: ['ShiftLeft', 'Right Stick'], + sneak: ['ShiftLeft'], + toggleSneakOrDown: [null, 'Right Stick'], sprint: ['ControlLeft', 'Left Stick'], nextHotbarSlot: [null, 'Left Bumper'], prevHotbarSlot: [null, 'Right Bumper'], @@ -152,7 +153,7 @@ const uiCommand = (command: Command) => { } } -export const setSneaking = (state: boolean) => { +const setSneaking = (state: boolean) => { gameAdditionalState.isSneaking = state bot.setControlState('sneak', state) } @@ -178,6 +179,14 @@ const onTriggerOrReleased = (command: Command, pressed: boolean) => { if (pressed) { setSprinting(pressed) } + break + case 'general.toggleSneakOrDown': + if (gameAdditionalState.isFlying) { + setSneaking(pressed) + } else if (pressed) { + setSneaking(!gameAdditionalState.isSneaking) + } + break case 'general.attackDestroy': document.dispatchEvent(new MouseEvent(pressed ? 'mousedown' : 'mouseup', { button: 0 })) diff --git a/src/react/HotbarRenderApp.tsx b/src/react/HotbarRenderApp.tsx index e747c4e3..5b32e3cc 100644 --- a/src/react/HotbarRenderApp.tsx +++ b/src/react/HotbarRenderApp.tsx @@ -108,13 +108,14 @@ export default () => { } setSize() watchUnloadForCleanup(subscribe(currentScaling, setSize)) + inv.canvas.style.pointerEvents = 'auto' container.current.appendChild(inv.canvas) const upHotbarItems = () => { if (!viewer.world.downloadedTextureImage && !viewer.world.customTexturesDataUrl) return upInventoryItems(true, inv) } - canvasManager.canvas.onpointerdown = (e) => { + canvasManager.canvas.onclick = (e) => { if (!isGameActive(true)) return const pos = inv.canvasManager.getMousePos(inv.canvas, e) if (canvasManager.canvas.width - pos.x < 35 * inv.canvasManager.scale) { @@ -209,6 +210,7 @@ export default () => { display: 'flex', justifyContent: 'center', zIndex: hasModals ? 1 : 8, + pointerEvents: 'none', bottom: 'env(safe-area-inset-bottom)' }} /> diff --git a/src/react/TouchAreasControls.tsx b/src/react/TouchAreasControls.tsx index e2a3fd87..f56db047 100644 --- a/src/react/TouchAreasControls.tsx +++ b/src/react/TouchAreasControls.tsx @@ -1,6 +1,6 @@ -import { CSSProperties, PointerEvent, PointerEventHandler, useEffect, useRef, useState } from 'react' +import { CSSProperties, PointerEvent, useEffect, useRef } from 'react' import { proxy, ref, useSnapshot } from 'valtio' -import { contro, setSneaking } from '../controls' +import { contro } from '../controls' import worldInteractions from '../worldInteractions' import PixelartIcon from './PixelartIcon' import Button from './Button' @@ -56,6 +56,7 @@ export default ({ touchActive, setupActive, buttonsPositions, closeButtonsSetup const joystickInner = useRef(null) const { pointer } = useSnapshot(joystickPointer) + // const { isFlying, isSneaking } = useSnapshot(gameAdditionalState) const newButtonPositions = { ...buttonsPositions } const buttonProps = (name: ButtonName) => { @@ -72,7 +73,10 @@ export default ({ touchActive, setupActive, buttonsPositions, closeButtonsSetup document.dispatchEvent(new MouseEvent('mouseup', { button: 2 })) }, sneak () { - setSneaking(!bot.getControlState('sneak')) + void contro.emit('trigger', { + command: 'general.toggleSneakOrDown', + schema: null as any, + }) active = bot.getControlState('sneak') }, break () { @@ -81,14 +85,22 @@ export default ({ touchActive, setupActive, buttonsPositions, closeButtonsSetup active = true }, jump () { - bot.setControlState('jump', true) - active = true + void contro.emit('trigger', { + command: 'general.jump', + schema: null as any, + }) + active = bot.controlState.jump } } const holdUp = { action () { }, sneak () { + void contro.emit('release', { + command: 'general.toggleSneakOrDown', + schema: null as any, + }) + active = bot.getControlState('sneak') }, break () { document.dispatchEvent(new MouseEvent('mouseup', { button: 0 })) @@ -96,8 +108,11 @@ export default ({ touchActive, setupActive, buttonsPositions, closeButtonsSetup active = false }, jump () { - bot.setControlState('jump', false) - active = false + void contro.emit('release', { + command: 'general.jump', + schema: null as any, + }) + active = bot.controlState.jump } } From e44c7cece26d36ff18ce0bbc15314d3a72c520cb Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 27 Apr 2024 23:17:06 +0300 Subject: [PATCH 0055/1097] workaround gpu textures overflow issue with many unknown entities TODO should be reworked completely --- prismarine-viewer/examples/playground.ts | 2 +- prismarine-viewer/viewer/lib/entities.js | 38 ++++++++++++++---------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/prismarine-viewer/examples/playground.ts b/prismarine-viewer/examples/playground.ts index bc9294ac..295cc47d 100644 --- a/prismarine-viewer/examples/playground.ts +++ b/prismarine-viewer/examples/playground.ts @@ -132,7 +132,7 @@ async function main () { document.body.appendChild(renderer.domElement) // Create viewer - const viewer = new Viewer(renderer, 1) + const viewer = new Viewer(renderer, { numWorkers: 1, showChunkBorders: false }) viewer.entities.setDebugMode('basic') viewer.setVersion(version) viewer.entities.onSkinUpdate = () => { diff --git a/prismarine-viewer/viewer/lib/entities.js b/prismarine-viewer/viewer/lib/entities.js index 350dc53e..290c3932 100644 --- a/prismarine-viewer/viewer/lib/entities.js +++ b/prismarine-viewer/viewer/lib/entities.js @@ -17,7 +17,7 @@ import externalTexturesJson from './entity/externalTextures.json' export const TWEEN_DURATION = 50 // todo should be 100 -function getUsernameTexture (username, { fontFamily = 'sans-serif' }) { +function getUsernameTexture(username, { fontFamily = 'sans-serif' }) { const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') if (!ctx) throw new Error('Could not get 2d context') @@ -58,7 +58,10 @@ const addNametag = (entity, options, mesh) => { } } -function getEntityMesh (entity, scene, options, overrides) { +// todo cleanup +const nametags = {} + +function getEntityMesh(entity, scene, options, overrides) { if (entity.name) { try { // https://github.com/PrismarineJS/prismarine-viewer/pull/410 @@ -78,10 +81,13 @@ function getEntityMesh (entity, scene, options, overrides) { geometry.translate(0, entity.height / 2, 0) const material = new THREE.MeshBasicMaterial({ color: 0xff_00_ff }) const cube = new THREE.Mesh(geometry, material) - addNametag({ - username: entity.name, - height: entity.height, - }, options, cube) + const nametagCount = (nametags[entity.name] = (nametags[entity.name] || 0) + 1) + if (nametagCount < 6) { + addNametag({ + username: entity.name, + height: entity.height, + }, options, cube) + } return cube } @@ -99,7 +105,7 @@ export class Entities extends EventEmitter { this.getItemUv = undefined } - clear () { + clear() { for (const mesh of Object.values(this.entities)) { this.scene.remove(mesh) dispose3(mesh) @@ -107,7 +113,7 @@ export class Entities extends EventEmitter { this.entities = {} } - setDebugMode (mode, /** @type {THREE.Object3D?} */entity = null) { + setDebugMode(mode, /** @type {THREE.Object3D?} */entity = null) { this.debugMode = mode for (const mesh of entity ? [entity] : Object.values(this.entities)) { const boxHelper = mesh.children.find(c => c.name === 'debug') @@ -119,14 +125,14 @@ export class Entities extends EventEmitter { } } - setVisible (visible, /** @type {THREE.Object3D?} */entity = null) { + setVisible(visible, /** @type {THREE.Object3D?} */entity = null) { this.visible = visible for (const mesh of entity ? [entity] : Object.values(this.entities)) { mesh.visible = visible } } - render () { + render() { const dt = this.clock.getDelta() for (const entityId of Object.keys(this.entities)) { const playerObject = this.getPlayerObject(entityId) @@ -136,7 +142,7 @@ export class Entities extends EventEmitter { } } - getPlayerObject (entityId) { + getPlayerObject(entityId) { /** @type {(PlayerObject & { animation?: PlayerAnimation }) | undefined} */ const playerObject = this.entities[entityId]?.playerObject return playerObject @@ -146,7 +152,7 @@ export class Entities extends EventEmitter { defaultSteveTexture // true means use default skin url - updatePlayerSkin (entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { + updatePlayerSkin(entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { let playerObject = this.getPlayerObject(entityId) if (!playerObject) return // const username = this.entities[entityId].username @@ -229,14 +235,14 @@ export class Entities extends EventEmitter { playerObject.cape.map = null } - function isCanvasBlank (canvas) { + function isCanvasBlank(canvas) { return !canvas.getContext('2d') .getImageData(0, 0, canvas.width, canvas.height).data .some(channel => channel !== 0) } } - playAnimation (entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { + playAnimation(entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { const playerObject = this.getPlayerObject(entityPlayerId) if (!playerObject) return @@ -256,14 +262,14 @@ export class Entities extends EventEmitter { } - displaySimpleText (jsonLike) { + displaySimpleText(jsonLike) { if (!jsonLike) return const parsed = mojangson.simplify(mojangson.parse(jsonLike)) const text = flat(parsed).map(x => x.text) return text.join('') } - update (/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { + update(/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { let isPlayerModel = entity.name === 'player' if (entity.name === 'zombie' || entity.name === 'zombie_villager' || entity.name === 'husk') { isPlayerModel = true From d83120fdce389f5c88b1c17dcbbb549747849523 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 22 Apr 2024 09:37:44 +0300 Subject: [PATCH 0056/1097] disable smooth lighting for now as it doesn't work correctly --- prismarine-viewer/viewer/lib/mesher/models.ts | 10 ++++------ prismarine-viewer/viewer/lib/mesher/world.ts | 4 +++- src/optionsGuiScheme.tsx | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/prismarine-viewer/viewer/lib/mesher/models.ts b/prismarine-viewer/viewer/lib/mesher/models.ts index fc86a671..833de180 100644 --- a/prismarine-viewer/viewer/lib/mesher/models.ts +++ b/prismarine-viewer/viewer/lib/mesher/models.ts @@ -387,15 +387,12 @@ function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr const corner = world.getBlock(cursor.offset(...cornerDir)) let cornerLightResult = 15 - if (world.config.smoothLighting) { + if (/* world.config.smoothLighting */false) { // todo fix const side1Light = world.getLight(cursor.plus(new Vec3(...side1Dir)), true) const side2Light = world.getLight(cursor.plus(new Vec3(...side2Dir)), true) const cornerLight = world.getLight(cursor.plus(new Vec3(...cornerDir)), true) // interpolate - cornerLightResult = Math.min( - Math.min(side1Light, side2Light), - cornerLight - ) + cornerLightResult = (side1Light + side2Light + cornerLight) / 3 } const side1Block = world.shouldMakeAo(side1) ? 1 : 0 @@ -405,7 +402,8 @@ function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr // TODO: correctly interpolate ao light based on pos (evaluate once for each corner of the block) const ao = (side1Block && side2Block) ? 0 : (3 - (side1Block + side2Block + cornerBlock)) - light = (ao + 1) / 4 * cornerLightResult / 15 + // todo light should go upper on lower blocks + light = (ao + 1) / 4 * (cornerLightResult / 15) aos.push(ao) } diff --git a/prismarine-viewer/viewer/lib/mesher/world.ts b/prismarine-viewer/viewer/lib/mesher/world.ts index 63263809..9a4f0ab3 100644 --- a/prismarine-viewer/viewer/lib/mesher/world.ts +++ b/prismarine-viewer/viewer/lib/mesher/world.ts @@ -130,7 +130,9 @@ export class World { // todo export in chunk instead const hasChunkSection = (column, pos) => { if (column._getSection) return column._getSection(pos) - if (column.skyLightSections) return column.skyLightSections[getLightSectionIndex(pos, column.minY)] + if (column.skyLightSections) { + return column.skyLightSections[getLightSectionIndex(pos, column.minY)] || column.blockLightSections[getLightSectionIndex(pos, column.minY)] + } if (column.sections) return column.sections[pos.y >> 4] } diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 84a09d45..96840af5 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -50,7 +50,7 @@ export const guiOptionsScheme: { dayCycleAndLighting: { text: 'Day Cycle', }, - smoothLighting: {}, + // smoothLighting: {}, newVersionsLighting: { text: 'Lighting in newer versions', }, From b278016460f2c659533fba05e0dfc5bac9898be9 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 22 Apr 2024 11:09:09 +0300 Subject: [PATCH 0057/1097] implement disableDuringGame --- src/optionsGuiScheme.tsx | 3 ++- src/react/OptionsItems.tsx | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 96840af5..2457c34f 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -56,7 +56,8 @@ export const guiOptionsScheme: { }, lowMemoryMode: { text: 'Low Memory Mode', - enableWarning: 'Enabling it will make chunks load ~4x slower' + enableWarning: 'Enabling it will make chunks load ~4x slower', + disabledDuringGame: true }, }, ], diff --git a/src/react/OptionsItems.tsx b/src/react/OptionsItems.tsx index 5dd31923..1ff589ca 100644 --- a/src/react/OptionsItems.tsx +++ b/src/react/OptionsItems.tsx @@ -3,6 +3,7 @@ import { noCase } from 'change-case' import { titleCase } from 'title-case' import { useMemo } from 'react' import { options, qsOptions } from '../optionsStorage' +import { miscUiState } from '../globalState' import Button from './Button' import Slider from './Slider' import Screen from './Screen' @@ -12,6 +13,7 @@ type GeneralItem = { id?: string text?: string, disabledReason?: string, + disabledDuringGame?: boolean tooltip?: string // description?: string enableWarning?: string @@ -34,8 +36,8 @@ export type OptionMeta = GeneralItem & ({ }) // todo not reactive -const isDisabled = (id) => { - return Object.keys(qsOptions).includes(id) +const isDisabled = (item: GeneralItem) => { + return Object.keys(qsOptions).includes(item.id!) } export const OptionButton = ({ item }: { item: Extract }) => { @@ -60,6 +62,10 @@ export const OptionButton = ({ item }: { item: Extract { + if (item.disabledReason) { + await showOptionsModal(`The option is unavailable. ${item.disabledReason}`, []) + return + } if (item.enableWarning && !options[item.id!]) { const result = await showOptionsModal(item.enableWarning, ['Enable']) if (!result) return @@ -86,7 +92,7 @@ export const OptionButton = ({ item }: { item: Extract { + return { options[item.id!] = value }} unit={item.unit} valueDisplay={valueDisplay} updateOnDragEnd={item.delayApply} /> } @@ -111,9 +117,13 @@ const OptionElement = ({ item }: { item: Extract { + const { gameLoaded } = useSnapshot(miscUiState) if (item.id) { item.text ??= titleCase(noCase(item.id)) } + if (item.disabledDuringGame && gameLoaded) { + item.disabledReason = 'Cannot be changed during game' + } let baseElement = null as React.ReactNode | null if (item.type === 'toggle') baseElement = From cfb9b17fd4aff13ebad063b0253b213584fd0b6e Mon Sep 17 00:00:00 2001 From: Vitaly Date: Sat, 4 May 2024 13:10:03 +0300 Subject: [PATCH 0058/1097] fix: don't attack on right click --- src/worldInteractions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index b2602cc5..544027a5 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -87,7 +87,7 @@ class WorldInteraction { const entity = getEntityCursor() - if (entity) { + if (entity && e.button === 2) { bot.attack(entity) } }) From 826c66b9ec51f89c41de7dbd643a43ea9af1bc11 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Sat, 4 May 2024 16:07:18 +0300 Subject: [PATCH 0059/1097] feat: brand new Servers List UI /w auto login feature! (#110) --- config.json | 18 +- cypress/e2e/index.spec.ts | 13 +- package.json | 2 +- pnpm-lock.yaml | 94 +++++- prismarine-viewer/viewer/lib/simpleUtils.ts | 4 + src/connect.ts | 15 + src/devReload.ts | 2 +- src/downloadAndOpenFile.ts | 5 +- src/globalState.ts | 15 +- src/globals.d.ts | 10 +- src/index.ts | 41 ++- src/menus/components/button.js | 136 -------- src/menus/components/common.js | 60 ---- src/menus/components/edit_box.js | 161 ---------- src/menus/play_screen.js | 250 --------------- src/optionsGuiScheme.tsx | 2 +- src/react/AddServer.tsx | 110 +++++++ src/react/Button.tsx | 4 +- src/react/ChatProvider.tsx | 18 +- src/react/Input.tsx | 4 +- src/react/MainMenu.tsx | 4 +- src/react/MainMenuRenderApp.tsx | 4 +- src/react/MessageFormatted.tsx | 2 +- src/react/PauseScreen.tsx | 2 +- src/react/ServersList.stories.tsx | 55 ++++ src/react/ServersList.tsx | 165 ++++++++++ src/react/ServersListProvider.tsx | 339 ++++++++++++++++++++ src/react/Singleplayer.tsx | 73 +++-- src/react/SingleplayerProvider.tsx | 2 +- src/react/input.module.css | 61 ++-- src/react/simpleHooks.ts | 6 + src/react/singleplayer.module.css | 14 + src/reactUi.tsx | 2 + src/watchOptions.ts | 2 +- 34 files changed, 976 insertions(+), 719 deletions(-) create mode 100644 src/connect.ts delete mode 100644 src/menus/components/button.js delete mode 100644 src/menus/components/common.js delete mode 100644 src/menus/components/edit_box.js delete mode 100644 src/menus/play_screen.js create mode 100644 src/react/AddServer.tsx create mode 100644 src/react/ServersList.stories.tsx create mode 100644 src/react/ServersList.tsx create mode 100644 src/react/ServersListProvider.tsx create mode 100644 src/react/simpleHooks.ts diff --git a/config.json b/config.json index b7fa1d7e..c1db50c3 100644 --- a/config.json +++ b/config.json @@ -2,6 +2,20 @@ "version": 1, "defaultHost": "", "defaultProxy": "proxy.mcraft.fun", - "defaultVersion": "1.18.2", - "mapsProvider": "https://maps.mcraft.fun/" + "mapsProvider": "https://maps.mcraft.fun/", + "promoteServers": [ + { + "ip": "kaboom.pw", + "description": "Chaos and destruction server. Free for everyone." + }, + { + "ip": "go.mineberry.org", + "version": "1.18.2", + "description": "One of the best servers here. Join now!" + }, + { + "ip": "play.minemalia.com", + "description": "Only login with existing accounts." + } + ] } diff --git a/cypress/e2e/index.spec.ts b/cypress/e2e/index.spec.ts index 8b168bf1..35399393 100644 --- a/cypress/e2e/index.spec.ts +++ b/cypress/e2e/index.spec.ts @@ -53,20 +53,19 @@ it('Loads & renders singleplayer', () => { }) it.only('Joins to server', () => { - // visit('/?version=1.16.1') + visit('/?ip=localhost&version=1.16.1') window.localStorage.version = '' - visit() // todo replace with data-test - cy.get('[data-test-id="connect-screen-button"]', { includeShadowDom: true }).click() - cy.get('input#serverip', { includeShadowDom: true }).clear().focus().type('localhost') - cy.get('input#botversion', { includeShadowDom: true }).clear().focus().type('1.16.1') // todo needs to fix autoversion - cy.get('[data-test-id="connect-to-server"]', { includeShadowDom: true }).click() + // cy.get('[data-test-id="servers-screen-button"]').click() + // cy.get('[data-test-id="server-ip"]').clear().focus().type('localhost') + // cy.get('[data-test-id="version"]').clear().focus().type('1.16.1') // todo needs to fix autoversion + cy.get('[data-test-id="connect-qs"]').click() testWorldLoad() }) it('Loads & renders zip world', () => { cleanVisit() - cy.get('[data-test-id="select-file-folder"]', { includeShadowDom: true }).click({ shiftKey: true }) + cy.get('[data-test-id="select-file-folder"]').click({ shiftKey: true }) cy.get('input[type="file"]').selectFile('cypress/superflat.zip', { force: true }) testWorldLoad() }) diff --git a/package.json b/package.json index dee909a8..4d99a6d5 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "dependencies": { "@dimaka/interface": "0.0.3-alpha.0", "@floating-ui/react": "^0.26.1", + "@mui/base": "5.0.0-beta.40", "@nxg-org/mineflayer-auto-jump": "^0.7.7", "@nxg-org/mineflayer-tracker": "^1.2.1", "@react-oauth/google": "^0.12.1", @@ -60,7 +61,6 @@ "google-drive-browserfs": "github:zardoy/browserfs#google-drive", "iconify-icon": "^1.0.8", "jszip": "^3.10.1", - "lit": "^2.8.0", "lodash-es": "^4.17.21", "minecraft-assets": "^1.12.2", "minecraft-data": "3.62.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fc504d17..1ef5b1d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: '@floating-ui/react': specifier: ^0.26.1 version: 0.26.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@mui/base': + specifier: 5.0.0-beta.40 + version: 5.0.0-beta.40(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@nxg-org/mineflayer-auto-jump': specifier: ^0.7.7 version: 0.7.7 @@ -104,9 +107,6 @@ importers: jszip: specifier: ^3.10.1 version: 3.10.1 - lit: - specifier: ^2.8.0 - version: 2.8.0 lodash-es: specifier: ^4.17.21 version: 4.17.21 @@ -1110,6 +1110,10 @@ packages: resolution: {integrity: sha512-ee7jVNlWN09+KftVOu9n7S8gQzD/Z6hN/I8VBRXW4P1+Xe7kJGXMwu8vds4aGIMHZnNbdpSWCfZZtinytpcAvA==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.24.5': + resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==} + engines: {node: '>=6.9.0'} + '@babel/template@7.22.5': resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} engines: {node: '>=6.9.0'} @@ -1661,6 +1665,12 @@ packages: react: ^18.2.0 react-dom: '>=16.8.0' + '@floating-ui/react-dom@2.0.9': + resolution: {integrity: sha512-q0umO0+LQK4+p6aGyvzASqKbKOJcAHJ7ycE9CuUvfx3s9zTHWmGJTPOIlM/hmSBfUfg/XfY5YhLBLR/LHwShQQ==} + peerDependencies: + react: ^18.2.0 + react-dom: '>=16.8.0' + '@floating-ui/react@0.26.1': resolution: {integrity: sha512-5gyJIJ2tZOPMgmZ/vEcVhdmQiy75b7LPO71sYIiDsxGcZ4hxLuygQWCuT0YXHqppt//Eese+L6t5KnX/gZ3tVA==} peerDependencies: @@ -1931,6 +1941,35 @@ packages: resolution: {integrity: sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==} engines: {node: '>= 10'} + '@mui/base@5.0.0-beta.40': + resolution: {integrity: sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 + react: ^18.2.0 + react-dom: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@mui/types@7.2.14': + resolution: {integrity: sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@mui/utils@5.15.14': + resolution: {integrity: sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 + react: ^18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@ndelangen/get-tarball@3.0.9': resolution: {integrity: sha512-9JKTEik4vq+yGosHYhZ1tiH/3WpUS0Nh0kej4Agndhox8pAdWhEx5knFVRcb/ya9knCRCs1rPxNrSXTDdfVqpA==} @@ -2774,6 +2813,9 @@ packages: '@types/pretty-hrtime@1.0.1': resolution: {integrity: sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==} + '@types/prop-types@15.7.12': + resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} + '@types/prop-types@15.7.5': resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} @@ -3664,6 +3706,10 @@ packages: resolution: {integrity: sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==} engines: {node: '>=6'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + color-convert@0.5.3: resolution: {integrity: sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling==} @@ -9458,6 +9504,10 @@ snapshots: dependencies: regenerator-runtime: 0.14.0 + '@babel/runtime@7.24.5': + dependencies: + regenerator-runtime: 0.14.0 + '@babel/template@7.22.5': dependencies: '@babel/code-frame': 7.22.13 @@ -9864,6 +9914,12 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + '@floating-ui/react-dom@2.0.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@floating-ui/dom': 1.5.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + '@floating-ui/react@0.26.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@floating-ui/react-dom': 2.0.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -10279,6 +10335,34 @@ snapshots: '@msgpack/msgpack@2.8.0': {} + '@mui/base@5.0.0-beta.40(@types/react@18.2.20)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.5 + '@floating-ui/react-dom': 2.0.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@mui/types': 7.2.14(@types/react@18.2.20) + '@mui/utils': 5.15.14(@types/react@18.2.20)(react@18.2.0) + '@popperjs/core': 2.11.8 + clsx: 2.1.1 + prop-types: 15.8.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.20 + + '@mui/types@7.2.14(@types/react@18.2.20)': + optionalDependencies: + '@types/react': 18.2.20 + + '@mui/utils@5.15.14(@types/react@18.2.20)(react@18.2.0)': + dependencies: + '@babel/runtime': 7.24.5 + '@types/prop-types': 15.7.12 + prop-types: 15.8.1 + react: 18.2.0 + react-is: 18.2.0 + optionalDependencies: + '@types/react': 18.2.20 + '@ndelangen/get-tarball@3.0.9': dependencies: gunzip-maybe: 1.4.2 @@ -11577,6 +11661,8 @@ snapshots: '@types/pretty-hrtime@1.0.1': {} + '@types/prop-types@15.7.12': {} + '@types/prop-types@15.7.5': {} '@types/qs@6.9.8': {} @@ -12705,6 +12791,8 @@ snapshots: clsx@1.1.1: {} + clsx@2.1.1: {} + color-convert@0.5.3: {} color-convert@1.9.3: diff --git a/prismarine-viewer/viewer/lib/simpleUtils.ts b/prismarine-viewer/viewer/lib/simpleUtils.ts index 5c602f1c..3f17e5ad 100644 --- a/prismarine-viewer/viewer/lib/simpleUtils.ts +++ b/prismarine-viewer/viewer/lib/simpleUtils.ts @@ -19,6 +19,10 @@ export function openURL (url, newTab = true) { } } +export const isMobile = () => { + return window.matchMedia('(pointer: coarse)').matches || navigator.userAgent.includes('Mobile') +} + export function chunkPos (pos: { x: number, z: number }) { const x = Math.floor(pos.x / 16) const z = Math.floor(pos.z / 16) diff --git a/src/connect.ts b/src/connect.ts new file mode 100644 index 00000000..5e4df859 --- /dev/null +++ b/src/connect.ts @@ -0,0 +1,15 @@ +export type ConnectOptions = { + server?: string; + singleplayer?: any; + username: string; + password?: any; + proxy?: any; + botVersion?: any; + serverOverrides?; + serverOverridesFlat?; + peerId?: string; + ignoreQs?: boolean; + onSuccessfulPlay?: () => void + autoLoginPassword?: string + serverIndex?: string +} diff --git a/src/devReload.ts b/src/devReload.ts index a89551d3..19e50263 100644 --- a/src/devReload.ts +++ b/src/devReload.ts @@ -1,5 +1,5 @@ +import { isMobile } from 'prismarine-viewer/viewer/lib/simpleUtils' import { WorldRendererThree } from 'prismarine-viewer/viewer/lib/worldrendererThree' -import { isMobile } from './menus/components/common' if (process.env.NODE_ENV === 'development') { if (sessionStorage.lastReload) { diff --git a/src/downloadAndOpenFile.ts b/src/downloadAndOpenFile.ts index b3d3a059..7ac154fc 100644 --- a/src/downloadAndOpenFile.ts +++ b/src/downloadAndOpenFile.ts @@ -20,9 +20,6 @@ const inner = async () => { if (resourcePackState.resourcePackInstalled) { if (!confirm(`You are going to install a new resource pack, which will REPLACE the current one: ${await getResourcePackName()} Continue?`)) return } - } else { - const menu = document.getElementById('play-screen') - menu.style = 'display: none;' } const name = mapUrl.slice(mapUrl.lastIndexOf('/') + 1).slice(-25) const downloadThing = texturepack ? 'texturepack' : 'world' @@ -78,7 +75,7 @@ export default async () => { try { return await inner() } catch (err) { - setLoadingScreenStatus(`Failed to download. Either refresh page or remove mapUrl param from URL. Reason: ${err.message}`) + setLoadingScreenStatus(`Failed to download. Either refresh page or remove map param from URL. Reason: ${err.message}`) return true } } diff --git a/src/globalState.ts b/src/globalState.ts index fa1c4cda..1b0526f9 100644 --- a/src/globalState.ts +++ b/src/globalState.ts @@ -56,10 +56,10 @@ const showModalInner = (modal: Modal) => { return true } -export const showModal = (elem: (HTMLElement & Record) | { reactType: string }) => { +export const showModal = (elem: /* (HTMLElement & Record) | */{ reactType: string }) => { const resolved = elem instanceof HTMLElement ? { elem: ref(elem) } : elem const curModal = activeModalStack.at(-1) - if (elem === curModal?.elem || (elem.reactType && elem.reactType === curModal?.reactType) || !showModalInner(resolved)) return + if (/* elem === curModal?.elem || */(elem.reactType && elem.reactType === curModal?.reactType) || !showModalInner(resolved)) return if (curModal) defaultModalActions.hide(curModal) activeModalStack.push(resolved) } @@ -118,11 +118,12 @@ export const showContextmenu = (items: ContextMenuItem[], { clientX, clientY }) // --- export type AppConfig = { - defaultHost?: string - defaultHostSave?: string + // defaultHost?: string + // defaultHostSave?: string defaultProxy?: string - defaultProxySave?: string - defaultVersion?: string + // defaultProxySave?: string + // defaultVersion?: string + promoteServers?: Array<{ip, description, version?}> mapsProvider?: string } @@ -130,12 +131,14 @@ export const miscUiState = proxy({ currentDisplayQr: null as string | null, currentTouch: null as boolean | null, serverIp: null as string | null, + username: '', hasErrors: false, singleplayer: false, flyingSquid: false, wanOpened: false, /** wether game hud is shown (in playing state) */ gameLoaded: false, + loadedServerIndex: '', /** currently trying to load or loaded mc version, after all data is loaded */ loadedDataVersion: null as string | null, appLoaded: false, diff --git a/src/globals.d.ts b/src/globals.d.ts index b0a8d6db..7d2a478c 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -27,7 +27,6 @@ declare const customEvents: import('typed-emitter').default<{ declare const beforeRenderFrame: Array<() => void> declare interface Document { - getElementById (id): any exitPointerLock?(): void } @@ -37,14 +36,7 @@ declare namespace JSX { } } -declare interface DocumentFragment { - getElementById (id): HTMLElement & Record - querySelector (id): HTMLElement & Record -} - -declare interface Window extends Record { - -} +declare interface Window extends Record {} type StringKeys = Extract diff --git a/src/index.ts b/src/index.ts index c4cff16a..0cd178d9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,9 +10,6 @@ import initCollisionShapes from './getCollisionShapes' import { itemsAtlases, onGameLoad } from './inventoryWindows' import { supportedVersions } from 'minecraft-protocol' -import './menus/components/button' -import './menus/components/edit_box' -import './menus/play_screen' import 'core-js/features/array/at' import 'core-js/features/promise/with-resolvers' @@ -90,6 +87,7 @@ import { saveToBrowserMemory } from './react/PauseScreen' import { ViewerWrapper } from 'prismarine-viewer/viewer/lib/viewerWrapper' import './devReload' import './water' +import { ConnectOptions } from './connect' window.debug = debug window.THREE = THREE @@ -240,13 +238,10 @@ const cleanConnectIp = (host: string | undefined, defaultPort: string | undefine } } -async function connect (connectOptions: { - server?: string; singleplayer?: any; username: string; password?: any; proxy?: any; botVersion?: any; serverOverrides?; serverOverridesFlat?; peerId?: string; ignoreQs?: boolean -}) { +async function connect (connectOptions: ConnectOptions) { if (miscUiState.gameLoaded) return miscUiState.hasErrors = false lastConnectOptions.value = connectOptions - document.getElementById('play-screen').style = 'display: none;' removePanorama() const { singleplayer } = connectOptions @@ -331,7 +326,7 @@ async function connect (connectOptions: { }) if (proxy) { - console.log(`using proxy ${proxy.host}${proxy.port && `:${proxy.port}`}`) + console.log(`using proxy ${proxy.host}:${proxy.port || location.port}`) net['setProxy']({ hostname: proxy.host, port: proxy.port }) } @@ -528,12 +523,6 @@ async function connect (connectOptions: { bot.once('login', () => { worldInteractions.initBot() - // server is ok, add it to the history - if (!connectOptions.server) return - const serverHistory: string[] = JSON.parse(localStorage.getItem('serverHistory') || '[]') - serverHistory.unshift(connectOptions.server) - localStorage.setItem('serverHistory', JSON.stringify([...new Set(serverHistory)])) - setLoadingScreenStatus('Loading world') }) @@ -548,10 +537,16 @@ async function connect (connectOptions: { window.pathfinder = pathfinder miscUiState.gameLoaded = true + miscUiState.loadedServerIndex = connectOptions.serverIndex ?? '' customEvents.emit('gameLoaded') if (p2pConnectTimeout) clearTimeout(p2pConnectTimeout) setLoadingScreenStatus('Placing blocks (starting viewer)') + localStorage.lastConnectOptions = JSON.stringify(connectOptions) + connectOptions.onSuccessfulPlay?.() + if (connectOptions.autoLoginPassword) { + bot.chat(`/login ${connectOptions.autoLoginPassword}`) + } console.log('bot spawned - starting viewer') @@ -726,6 +721,7 @@ async function connect (connectOptions: { console.log('Done!') + // todo onGameLoad(async () => { if (!viewer.world.downloadedBlockStatesData && !viewer.world.customBlockStatesData) { await new Promise(resolve => { @@ -733,6 +729,7 @@ async function connect (connectOptions: { }) } miscUiState.serverIp = server.host as string | null + miscUiState.username = username }) if (appStatusState.isError) return @@ -839,12 +836,26 @@ void window.fetch('config.json').then(async res => res.json()).then(c => c, (err miscUiState.appConfig = config }) +// qs open actions downloadAndOpenFile().then((downloadAction) => { if (downloadAction) return + const qs = new URLSearchParams(window.location.search) + if (qs.get('reconnect') && process.env.NODE_ENV === 'development') { + const ip = qs.get('ip') + const lastConnect = JSON.parse(localStorage.lastConnectOptions ?? {}) + void connect({ + ...lastConnect, // todo mixing is not good idea + ip: ip || undefined + }) + return + } + if (qs.get('ip') || qs.get('proxy')) { + // show server editor for connect or save + showModal({ reactType: 'editServer' }) + } void Promise.resolve().then(() => { // try to connect to peer - const qs = new URLSearchParams(window.location.search) const peerId = qs.get('connectPeer') const version = qs.get('peerVersion') if (peerId) { diff --git a/src/menus/components/button.js b/src/menus/components/button.js deleted file mode 100644 index 1f726821..00000000 --- a/src/menus/components/button.js +++ /dev/null @@ -1,136 +0,0 @@ -//@ts-check -import { LitElement, html, css, unsafeCSS } from 'lit' -import widgetsGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/widgets.png' -import { playSound, loadSound } from '../../basicSounds' - -class Button extends LitElement { - static get styles () { - return css` - .button { - --txrV: 66px; - position: relative; - width: 200px; - height: 20px; - font-family: minecraft, mojangles, monospace; - font-size: 10px; - color: white; - text-shadow: 1px 1px #222; - border: none; - z-index: 1; - outline: none; - display: inline-flex; - justify-content: center; - align-items: center; - } - - .button:hover, - .button:focus-visible { - --txrV: 86px; - } - - .button:disabled { - --txrV: 46px; - color: #A0A0A0; - text-shadow: 1px 1px #111; - } - - .button::after { - content: ''; - display: block; - position: absolute; - top: 0; - left: 0; - width: calc(50% + 1px); - height: 20px; - background: url('${unsafeCSS(widgetsGui)}'); - background-size: 256px; - background-position-y: calc(var(--txrV) * -1); - z-index: -1; - } - - .button::before { - content: ''; - display: block; - position: absolute; - top: 0; - left: 50%; - width: 50%; - height: 20px; - background: url('${unsafeCSS(widgetsGui)}'); - background-size: 256px; - background-position-x: calc(-200px + 100%); - background-position-y: calc(var(--txrV) * -1); - z-index: -1; - } - - .icon { - position: absolute; - top: 3px; - left: 3px; - font-size: 14px; - } - ` - } - - static get properties () { - return { - label: { - type: String, - attribute: 'pmui-label' - }, - width: { - type: String, - attribute: 'pmui-width' - }, - disabled: { - type: Boolean, - }, - onPress: { - type: Function, - attribute: 'pmui-click' - }, - icon: { - type: Function, - attribute: 'pmui-icon' - }, - testId: { - type: String, - attribute: 'pmui-test-id' - } - } - } - - constructor () { - super() - this.label = '' - this.icon = undefined - this.testId = undefined - this.disabled = false - this.width = '200px' - this.onPress = () => { } - } - - render () { - return html` - - ` - } - - onBtnClick (e) { - playSound('button_click.mp3') - this.dispatchEvent(new window.CustomEvent('pmui-click', { detail: e })) - } -} - -loadSound('button_click.mp3') -window.customElements.define('pmui-button', Button) diff --git a/src/menus/components/common.js b/src/menus/components/common.js deleted file mode 100644 index 83c74abd..00000000 --- a/src/menus/components/common.js +++ /dev/null @@ -1,60 +0,0 @@ -import { css } from 'lit' - -const commonCss = css` - .bg { - position: absolute; - top: 0; - left: 0; - background: rgba(0, 0, 0, 0.75); - width: 100%; - height: 100%; - } - - .title { - position: absolute; - top: 0; - left: 50%; - transform: translate(-50%); - font-size: 10px; - color: white; - text-align: center; - text-shadow: 1px 1px #222; - } - - .text { - color: white; - font-size: 10px; - text-shadow: 1px 1px #222; - } -` - -/** @returns {boolean} */ -function isMobile () { - return window.matchMedia('(pointer: coarse)').matches || navigator.userAgent.includes('Mobile') -} - -// todo there are better workarounds and proper way to detect notch -/** @returns {boolean} */ -function isProbablyIphone () { - if (!isMobile()) return false - const smallest = window.innerWidth < window.innerHeight ? window.innerWidth : window.innerHeight - return smallest < 600 -} - -/** - * @param {string} url - */ -function openURL (url, newTab = true) { - if (newTab) { - window.open(url, '_blank', 'noopener,noreferrer') - } else { - window.open(url, '_self') - } -} - -export { - isProbablyIphone, - commonCss, - isMobile, - openURL, -} diff --git a/src/menus/components/edit_box.js b/src/menus/components/edit_box.js deleted file mode 100644 index c7210d43..00000000 --- a/src/menus/components/edit_box.js +++ /dev/null @@ -1,161 +0,0 @@ -const { LitElement, html, css } = require('lit') -const { ifDefined } = require('lit/directives/if-defined.js') - -class EditBox extends LitElement { - static get styles () { - return css` - .edit-container { - position: relative; - width: 200px; - height: 20px; - background: black; - border: 1px solid grey; - } - .edit-container.invalid { - border: 1px solid #c70000; - } - - .edit-container.warning { - border: 1px solid rgb(159, 151, 0); - } - - .edit-container.invalid:hover, - .edit-container.invalid:focus-within { - border-color: red; - } - .edit-container.warning:hover, - .edit-container.warning:focus-within { - border-color: yellow; - } - - .edit-container:hover, - .edit-container:focus-within { - border-color: white; - } - - .edit-container label { - position: absolute; - z-index: 2; - pointer-events: none; - bottom: 21px; - left: 0; - font-size: 10px; - color: rgb(206, 206, 206); - text-shadow: 1px 1px black; - } - - .edit-box { - position: relative; - outline: none; - border: none; - background: none; - left: 1px; - width: calc(100% - 2px); - height: 100%; - font-family: minecraft, mojangles, monospace; - font-size: 10px; - color: white; - text-shadow: 1px 1px #222; - } - - input::-webkit-outer-spin-button, - input::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; - } - - /* Firefox */ - input[type=number] { - appearance: textfield; - -moz-appearance: textfield; - } - ` - } - - constructor () { - super() - this.width = '200px' - this.id = '' - this.value = '' - this.label = '' - this.required = false - } - - static get properties () { - return { - width: { - type: String, - attribute: 'pmui-width' - }, - id: { - type: String, - attribute: 'pmui-id' - }, - label: { - type: String, - attribute: 'pmui-label' - }, - value: { - type: String, - attribute: 'pmui-value' - }, - autocompleteValues: { - type: Array, - }, - type: { - type: String, - attribute: 'pmui-type' - }, - inputMode: { - type: String, - attribute: 'pmui-inputmode' - }, - required: { - type: Boolean, - attribute: 'pmui-required' - }, - placeholder: { - type: String, - attribute: 'pmui-placeholder' - }, - state: { - type: String, - attribute: true - } - } - } - - render () { - return html` -
- - ${this.autocompleteValues ? html` - - ${this.autocompleteValues.map(value => html` - - `)} - - ` : ''} - { this.value = this.inputMode === 'decimal' ? value.replaceAll(',', '.') : value }} - class="edit-box"> -
- ` - } -} - -window.customElements.define('pmui-editbox', EditBox) diff --git a/src/menus/play_screen.js b/src/menus/play_screen.js deleted file mode 100644 index e9517d9e..00000000 --- a/src/menus/play_screen.js +++ /dev/null @@ -1,250 +0,0 @@ -//@ts-check -const { LitElement, html, css } = require('lit') -const viewerSupportedVersions = require('prismarine-viewer/viewer/supportedVersions.json') -const { supportedVersions } = require('minecraft-protocol') -const { hideCurrentModal, miscUiState } = require('../globalState') -const { commonCss } = require('./components/common') - -const fullySupporedVersions = viewerSupportedVersions - -class PlayScreen extends LitElement { - static get styles () { - return css` - ${commonCss} - .title { - top: 12px; - } - - .edit-boxes { - position: fixed; - top: 59px; - left: 50%; - display: flex; - flex-direction: column; - gap: 14px 0; - transform: translate(-50%); - width: 310px; - } - - .wrapper { - width: 100%; - display: flex; - flex-direction: row; - gap: 0 4px; - } - - .button-wrapper { - display: flex; - flex-direction: row; - gap: 0 4px; - position: absolute; - bottom: 9px; - left: 50%; - transform: translate(-50%); - width: 310px; - } - - .extra-info-version { - font-size: 10px; - color: rgb(206, 206, 206); - text-shadow: 1px 1px black; - position: absolute; - left: calc(50% + 2px); - bottom: -34px; - } - - .extra-info-proxy { - font-size: 8px; - color: rgb(206, 206, 206); - text-shadow: 1px 1px black; - margin:0; - margin-top:-12px; - } - - a { - color: white; - } - ` - } - - static get properties () { - return { - server: { type: String }, - serverImplicit: { type: String }, - serverport: { type: Number }, - proxy: { type: String }, - proxyImplicit: { type: String }, - proxyport: { type: Number }, - username: { type: String }, - password: { type: String }, - version: { type: String } - } - } - - constructor () { - super() - this.version = '' - this.serverport = '' - this.proxyport = '' - this.server = '' - this.proxy = '' - this.username = '' - this.password = '' - this.serverImplicit = '' - this.proxyImplicit = '' - // todo set them sooner add indicator - void window.fetch('config.json').then(async res => res.json()).then(c => c, (error) => { - console.warn('Failed to load optional config.json', error) - return {} - }).then(async (/** @type {import('../globalState').AppConfig} */config) => { - miscUiState.appConfig = config - const params = new URLSearchParams(window.location.search) - - const getParam = (localStorageKey, qs = localStorageKey) => { - const qsValue = qs ? params.get(qs) : undefined - if (qsValue) { - this.style.display = 'block' - } - return qsValue || window.localStorage.getItem(localStorageKey) - } - - if (config.defaultHost === '' || config.defaultHostSave === '') { - let proxy = config.defaultProxy || config.defaultProxySave || params.get('proxy') - const cleanUrl = url => url.replaceAll(/(https?:\/\/|\/$)/g, '') - if (proxy && cleanUrl(proxy) !== cleanUrl(location.origin + location.pathname)) { - if (!proxy.startsWith('http')) proxy = 'https://' + proxy - const proxyConfig = await fetch(proxy + '/config.json').then(async res => res.json()).then(c => c, (error) => { - console.warn(`Failed to load config.json from proxy ${proxy}`, error) - return {} - }) - if (config.defaultHost === '' && proxyConfig.defaultHost) { - config.defaultHost = proxyConfig.defaultHost - } else { - config.defaultHost = '' - } - if (config.defaultHostSave === '' && proxyConfig.defaultHostSave) { - config.defaultHostSave = proxyConfig.defaultHostSave - } else { - config.defaultHostSave = '' - } - } - this.server = this.serverImplicit - } - - this.serverImplicit = config.defaultHost ?? '' - this.proxyImplicit = config.defaultProxy ?? '' - this.server = getParam('server', 'ip') ?? config.defaultHostSave ?? '' - this.proxy = getParam('proxy') ?? config.defaultProxySave ?? '' - this.version = getParam('version') || (window.localStorage.getItem('version') ?? config.defaultVersion ?? '') - this.username = getParam('username') || 'pviewer' + (Math.floor(Math.random() * 1000)) - this.password = getParam('password') || '' - if (process.env.NODE_ENV === 'development' && params.get('reconnect') && this.server && this.username) { - this.onConnectPress() - } - }) - } - - render () { - return html` -
- -

Join a Server

- -
-
- { this.server = e.target.value }} - > - { this.serverport = e.target.value }} - > -
-
- { this.proxy = e.target.value }} - > - { this.proxyport = e.target.value }} - > -
-
-

Enter proxy url you want to use. Learn more.

-
-
- { this.username = e.target.value }} - > - { this.version = e.target.value = e.target.value.replaceAll(',', '.') }} - > -
-

Leave blank and it will be chosen automatically

-
- -
- - hideCurrentModal()}> -
- ` - } - - onConnectPress () { - const server = this.server ? `${this.server}${this.serverport && `:${this.serverport}`}` : this.serverImplicit - const proxy = this.proxy ? `${this.proxy}${this.proxyport && `:${this.proxyport}`}` : this.proxyImplicit - - window.localStorage.setItem('username', this.username) - window.localStorage.setItem('password', this.password) - window.localStorage.setItem('server', server) - window.localStorage.setItem('proxy', proxy) - window.localStorage.setItem('version', this.version) - - window.dispatchEvent(new window.CustomEvent('connect', { - detail: { - server, - proxy, - username: this.username, - password: this.password, - botVersion: this.version - } - })) - } -} - -window.customElements.define('pmui-playscreen', PlayScreen) diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 2457c34f..1c92a39c 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -1,7 +1,7 @@ import { useState } from 'react' import { useSnapshot } from 'valtio' +import { openURL } from 'prismarine-viewer/viewer/lib/simpleUtils' import { miscUiState, openOptionsMenu, showModal } from './globalState' -import { openURL } from './menus/components/common' import { AppOptions, options } from './optionsStorage' import Button from './react/Button' import { OptionMeta, OptionSlider } from './react/OptionsItems' diff --git a/src/react/AddServer.tsx b/src/react/AddServer.tsx new file mode 100644 index 00000000..bae39ac9 --- /dev/null +++ b/src/react/AddServer.tsx @@ -0,0 +1,110 @@ +import React from 'react' +import Screen from './Screen' +import Input from './Input' +import Button from './Button' +import { useIsSmallWidth } from './simpleHooks' + +export interface NewServerInfo { + ip: string + name?: string + versionOverride?: string + proxyOverride?: string + usernameOverride?: string + passwordOverride?: string +} + +interface Props { + onBack: () => void + onConfirm: (info: NewServerInfo) => void + title?: string + initialData?: NewServerInfo + parseQs?: boolean + onQsConnect?: (server: NewServerInfo) => void + defaults?: Pick +} + +export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQs, onQsConnect, defaults }: Props) => { + const qsParams = parseQs ? new URLSearchParams(window.location.search) : undefined + + const [serverName, setServerName] = React.useState(initialData?.name ?? qsParams?.get('name') ?? '') + + const ipWithoutPort = initialData?.ip.split(':')[0] + const port = initialData?.ip.split(':')[1] + + const [serverIp, setServerIp] = React.useState(ipWithoutPort ?? qsParams?.get('ip') ?? '') + const [serverPort, setServerPort] = React.useState(port ?? '') + const [versionOverride, setVersionOverride] = React.useState(initialData?.versionOverride ?? qsParams?.get('version') ?? '') + const [proxyOverride, setProxyOverride] = React.useState(initialData?.proxyOverride ?? qsParams?.get('proxy') ?? '') + const [usernameOverride, setUsernameOverride] = React.useState(initialData?.usernameOverride ?? qsParams?.get('username') ?? '') + const [passwordOverride, setPasswordOverride] = React.useState(initialData?.passwordOverride ?? qsParams?.get('password') ?? '') + const smallWidth = useIsSmallWidth() + + return +
{ + e.preventDefault() + let ip = serverIp.includes(':') ? serverIp : `${serverIp}:${serverPort}` + ip = ip.replace(/:$/, '') + onConfirm({ + name: serverName, + ip, + versionOverride, + proxyOverride, + usernameOverride, + passwordOverride + }) + }} + > +
+
+ setServerName(value)} placeholder='Defaults to IP' /> +
+ setServerIp(value)} /> + setServerPort(value)} placeholder='25565' /> +
Overrides:
+ setVersionOverride(value)} placeholder='Optional, but recommended to specify' /> + setProxyOverride(value)} placeholder={defaults?.proxyOverride} /> + setUsernameOverride(value)} placeholder={defaults?.usernameOverride} /> + setPasswordOverride(value)} /* placeholder='For advanced usage only' */ /> + + + {qsParams?.get('ip') &&
+ +
} +
+
+
+} + +const InputWithLabel = ({ label, span, ...props }: React.ComponentProps & { label, span?}) => { + return
+ + +
+} diff --git a/src/react/Button.tsx b/src/react/Button.tsx index 4d346b14..db7e575a 100644 --- a/src/react/Button.tsx +++ b/src/react/Button.tsx @@ -15,7 +15,7 @@ interface Props extends React.ComponentProps<'button'> { void loadSound('button_click.mp3') -export default (({ label, icon, children, inScreen, rootRef, ...args }) => { +export default (({ label, icon, children, inScreen, rootRef, type = 'button', ...args }) => { const onClick = (e) => { void playSound('button_click.mp3') args.onClick?.(e) @@ -29,7 +29,7 @@ export default (({ label, icon, children, inScreen, rootRef, ...args }) => { args.style.width = 20 } - return +
+ } + searchRowChildrenOverride={ +
+
+ Proxy: +
+ + {autocomplete.groupedOptions &&
    + {autocomplete.groupedOptions.map((proxy, index) => { + const { itemRef, ...optionProps } = autocomplete.getOptionProps({ option: proxy, index }) + return + })} +
} +
+ + setUsername(value)} /> +
+
+ } + serversLayout + onWorldAction={(action, serverName) => { + if (action === 'load') { + joinServer(serverName, {}) + } + props.onWorldAction?.(action, serverName) + }} + /> +} + +type Status = 'unknown' | 'error' | 'success' + +const ProxyRender = ({ status, ip, inputRef, value, setValue, ...props }: { + status: Status + ip: string +} & Record) => { + const iconPerStatus = { + unknown: 'cellular-signal-0', + error: 'cellular-signal-off', + success: 'cellular-signal-3', + } + + return
+ setValue?.(value)} + onChange={props.onChange} + /> +
+ +
+ {ip} +
+
+
+} diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx new file mode 100644 index 00000000..ecd74916 --- /dev/null +++ b/src/react/ServersListProvider.tsx @@ -0,0 +1,339 @@ +import { useEffect, useMemo, useState } from 'react' +import { proxy } from 'valtio' +import { qsOptions } from '../optionsStorage' +import { ConnectOptions } from '../connect' +import { hideCurrentModal, miscUiState, showModal } from '../globalState' +import ServersList from './ServersList' +import AddServer from './AddServer' +import { useDidUpdateEffect, useIsModalActive } from './utils' + +interface StoreServerItem { + ip: string, + name?: string + version?: string + lastJoined?: number + description?: string + proxyOverride?: string + usernameOverride?: string + passwordOverride?: string + optionsOverride?: Record + autoLogin?: Record +} + +type ServerResponse = { + version: { + name_raw: string + } + // display tooltip + players?: { + online: number + max: number + list: Array<{ + name_raw: string + name_clean: string + }> + } + icon: string + motd: { + raw: string + } + // todo circle error icon + mods?: Array<{ name, version }> + // todo display via hammer icon + software?: string + plugins?: Array<{ name, version }> +} + +type AdditionalDisplayData = { + formattedText: string + textNameRight: string + icon?: string +} + +const getInitialServersList = () => { + if (localStorage['serversList']) return JSON.parse(localStorage['serversList']) as StoreServerItem[] + + const servers = [] as StoreServerItem[] + + const legacyServersList = localStorage['serverHistory'] ? JSON.parse(localStorage['serverHistory']) as string[] : null + if (legacyServersList) { + for (const server of legacyServersList) { + if (!server || localStorage['server'] === server) continue + servers.push({ ip: server, lastJoined: Date.now() }) + } + } + + if (localStorage['server']) { + const legacyLastJoinedServer: StoreServerItem = { + ip: localStorage['server'], + passwordOverride: localStorage['password'], + version: localStorage['version'], + lastJoined: Date.now() + } + servers.push(legacyLastJoinedServer) + } + + if (servers.length === 0) { // server list is empty, let's suggest some + for (const server of miscUiState.appConfig?.promoteServers ?? []) { + servers.push({ + ip: server.ip, + description: server.description, + version: server.version, + }) + } + } + + return servers +} + +const setNewServersList = (serversList: StoreServerItem[]) => { + localStorage['serversList'] = JSON.stringify(serversList) + + // cleanup legacy + localStorage.removeItem('serverHistory') + localStorage.removeItem('server') + localStorage.removeItem('password') + localStorage.removeItem('version') +} + +const getInitialProxies = () => { + const proxies = [] as string[] + if (miscUiState.appConfig?.defaultProxy) { + proxies.push(miscUiState.appConfig.defaultProxy) + } + if (localStorage['proxy']) { + proxies.push(localStorage['proxy']) + localStorage.removeItem('proxy') + } + return proxies +} + +export const updateLoadedServerData = (callback: (data: StoreServerItem) => StoreServerItem) => { + // function assumes component is not mounted to avoid sync issues after save + const { loadedServerIndex } = miscUiState + if (!loadedServerIndex) return + const servers = getInitialServersList() + const server = servers[loadedServerIndex] + servers[loadedServerIndex] = callback(server) + setNewServersList(servers) +} + +const Inner = () => { + const [proxies, setProxies] = useState(localStorage['proxies'] ? JSON.parse(localStorage['proxies']) : getInitialProxies()) + const [selectedProxy, setSelectedProxy] = useState(localStorage.getItem('selectedProxy') ?? proxies?.[0] ?? '') + const [serverEditScreen, setServerEditScreen] = useState(null) // true for add + const [defaultUsername, setDefaultUsername] = useState(localStorage['username'] ?? (`mcrafter${Math.floor(Math.random() * 1000)}`)) + + useEffect(() => { + localStorage.setItem('username', defaultUsername) + }, [defaultUsername]) + + useEffect(() => { + // TODO! do not unmount on connecting screen + // if (proxies.length) { + // localStorage.setItem('proxies', JSON.stringify(proxies)) + // } + // if (selectedProxy) { + // localStorage.setItem('selectedProxy', selectedProxy) + // } + }, [proxies]) + + const [serversList, setServersList] = useState(() => getInitialServersList()) + const [additionalData, setAdditionalData] = useState>({}) + + useDidUpdateEffect(() => { + // save data only on user changes + setNewServersList(serversList) + }, [serversList]) + + // by lastJoined + const serversListSorted = useMemo(() => { + return serversList.map((server, index) => ({ ...server, index })).sort((a, b) => (b.lastJoined ?? 0) - (a.lastJoined ?? 0)) + }, [serversList]) + + useEffect(() => { + const update = async () => { + for (const server of serversListSorted) { + const isInLocalNetwork = server.ip.startsWith('192.168.') || server.ip.startsWith('10.') || server.ip.startsWith('172.') || server.ip.startsWith('127.') || server.ip.startsWith('localhost') + if (isInLocalNetwork) continue + // eslint-disable-next-line no-await-in-loop + await fetch(`https://api.mcstatus.io/v2/status/java/${server.ip}`).then(async r => r.json()).then((data: ServerResponse) => { + const versionClean = data.version.name_raw.replace(/^[^\d.]+/, '') + setAdditionalData(old => { + return ({ + ...old, + [server.ip]: { + formattedText: data.motd.raw, + textNameRight: `${versionClean} ${data.players?.online ?? '??'}/${data.players?.max ?? '??'}`, + icon: data.icon, + } + }) + }) + }) + } + } + void update() + }, [serversListSorted]) + + const isEditScreenModal = useIsModalActive('editServer') + + useEffect(() => { + if (!isEditScreenModal) { + setServerEditScreen(null) + } + }, [isEditScreenModal]) + + useEffect(() => { + if (serverEditScreen && !isEditScreenModal) { + showModal({ reactType: 'editServer' }) + } + }, [serverEditScreen]) + + if (isEditScreenModal) { + return { + hideCurrentModal() + }} + onConfirm={(info) => { + if (!serverEditScreen) return + if (serverEditScreen === true) { + const server: StoreServerItem = { ...info, lastJoined: Date.now() } // so it appears first + setServersList(old => [...old, server]) + } else { + const index = serversList.indexOf(serverEditScreen) + serversList[index] = info + setServersList([...serversList]) + } + setServerEditScreen(null) + }} + initialData={!serverEditScreen || serverEditScreen === true ? undefined : serverEditScreen} + onQsConnect={(info) => { + const connectOptions: ConnectOptions = { + username: info.usernameOverride || defaultUsername, + server: info.ip, + proxy: info.proxyOverride || selectedProxy, + botVersion: info.versionOverride, + password: info.passwordOverride, + ignoreQs: true, + } + dispatchEvent(new CustomEvent('connect', { detail: connectOptions })) + }} + /> + } + + return { + let ip = indexOrIp + let server: StoreServerItem | undefined + if (overrides.shouldSave === undefined) { + // hack: inner component doesn't know of overrides for existing servers + server = serversListSorted.find(s => s.index.toString() === indexOrIp)! + ip = server.ip + overrides = server + } + + const lastJoinedUsername = serversListSorted.find(s => s.usernameOverride)?.usernameOverride + let username = overrides.username || defaultUsername + if (!username) { + username = prompt('Username', lastJoinedUsername || '') + if (!username) return + setDefaultUsername(username) + } + const options = { + username, + server: ip, + proxy: overrides.proxy || selectedProxy, + botVersion: overrides.version, + password: overrides.password, + ignoreQs: true, + autoLoginPassword: server?.autoLogin?.[username], + onSuccessfulPlay () { + if (overrides.shouldSave && !serversList.some(s => s.ip === ip)) { + const newServersList = [...serversList, { + ip, + lastJoined: Date.now(), + }] + // setServersList(newServersList) + setNewServersList(newServersList) // component is not mounted + } + + if (overrides.shouldSave === undefined) { // loading saved + // find and update + const server = serversList.find(s => s.ip === ip) + if (server) { + server.lastJoined = Date.now() + // setServersList([...serversList]) + setNewServersList(serversList) // component is not mounted + } + } + + // save new selected proxy (if new) + if (!proxies.includes(selectedProxy)) { + // setProxies([...proxies, selectedProxy]) + localStorage.setItem('proxies', JSON.stringify([...proxies, selectedProxy])) + } + if (selectedProxy) { + localStorage.setItem('selectedProxy', selectedProxy) + } + }, + serverIndex: overrides.shouldSave ? serversList.length.toString() : indexOrIp // assume last + } satisfies ConnectOptions + dispatchEvent(new CustomEvent('connect', { detail: options })) + // qsOptions + }} + username={defaultUsername} + setUsername={setDefaultUsername} + onWorldAction={(action, index) => { + const server = serversList[index] + if (!server) return + + if (action === 'edit') { + setServerEditScreen(server) + } + if (action === 'delete') { + setServersList(old => old.filter(s => s !== server)) + } + }} + onGeneralAction={(action) => { + if (action === 'create') { + setServerEditScreen(true) + } + if (action === 'cancel') { + hideCurrentModal() + } + }} + worldData={serversListSorted.map(server => { + const additional = additionalData[server.ip] + return { + name: server.index.toString(), + title: server.name || server.ip, + detail: (server.version ?? '') + ' ' + (server.usernameOverride ?? ''), + // lastPlayed: server.lastJoined, + formattedTextOverride: additional?.formattedText, + worldNameRight: additional?.textNameRight ?? '', + iconSrc: additional?.icon, + } + })} + initialProxies={{ + proxies, + selected: selectedProxy, + }} + updateProxies={({ proxies, selected }) => { + // new proxy is saved in joinServer + setProxies(proxies) + setSelectedProxy(selected) + }} + /> +} + +export default () => { + const editServerModalActive = useIsModalActive('editServer') + const isServersListModalActive = useIsModalActive('serversList') + const eitherModal = isServersListModalActive || editServerModalActive + return eitherModal ? : null +} diff --git a/src/react/Singleplayer.tsx b/src/react/Singleplayer.tsx index a4d8c559..76a75e82 100644 --- a/src/react/Singleplayer.tsx +++ b/src/react/Singleplayer.tsx @@ -10,22 +10,25 @@ import styles from './singleplayer.module.css' import Input from './Input' import Button from './Button' import Tabs from './Tabs' +import MessageFormattedString from './MessageFormattedString' export interface WorldProps { name: string title: string - iconBase64?: string size?: number lastPlayed?: number isFocused?: boolean - onFocus?: (name: string) => void + iconSrc?: string detail?: string + formattedTextOverride?: string + worldNameRight?: string + onFocus?: (name: string) => void onInteraction?(interaction: 'enter' | 'space') } -const World = ({ name, isFocused, title, lastPlayed, size, detail = '', onFocus, onInteraction, iconBase64 }: WorldProps) => { +const World = ({ name, isFocused, title, lastPlayed, size, detail = '', onFocus, onInteraction, iconSrc, formattedTextOverride, worldNameRight }: WorldProps) => { const timeRelativeFormatted = useMemo(() => { - if (!lastPlayed) return + if (!lastPlayed) return '' const formatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }) const diff = Date.now() - lastPlayed const minutes = Math.floor(diff / 1000 / 60) @@ -38,7 +41,7 @@ const World = ({ name, isFocused, title, lastPlayed, size, detail = '', onFocus, return formatter.format(-minutes, 'minute') }, [lastPlayed]) const sizeFormatted = useMemo(() => { - if (!size) return + if (!size) return '' return filesize(size) }, [size]) @@ -48,18 +51,29 @@ const World = ({ name, isFocused, title, lastPlayed, size, detail = '', onFocus, onInteraction?.(e.code === 'Enter' ? 'enter' : 'space') } }} onDoubleClick={() => onInteraction?.('enter')}> - world preview + world preview
-
{title}
-
{timeRelativeFormatted} {detail.slice(-30)}
-
{sizeFormatted}
+
+
{title}
+
{worldNameRight}
+
+ {formattedTextOverride ?
+ +
: + <> +
{timeRelativeFormatted} {detail.slice(-30)}
+
{sizeFormatted}
+ }
} interface Props { worldData: WorldProps[] | null // null means loading - providers: Record + serversLayout?: boolean + firstRowChildrenOverride?: React.ReactNode + searchRowChildrenOverride?: React.ReactNode + providers?: Record activeProvider?: string setActiveProvider?: (provider: string) => void providerActions?: Record void) | undefined | JSX.Element> @@ -74,9 +88,24 @@ interface Props { onGeneralAction (action: 'cancel' | 'create'): void } -export default ({ worldData, onGeneralAction, onWorldAction, activeProvider, setActiveProvider, providerActions, providers, disabledProviders, error, isReadonly, warning, warningAction, warningActionLabel }: Props) => { +export default ({ + worldData, + onGeneralAction, + onWorldAction, + firstRowChildrenOverride, + serversLayout, + searchRowChildrenOverride, + activeProvider, + setActiveProvider, + providerActions, + providers = {}, + disabledProviders, + error, + isReadonly, + warning, warningAction, warningActionLabel +}: Props) => { const containerRef = useRef() - const firstButton = useRef(null!) + const firstButton = useRef(null) useTypedEventListener(window, 'keydown', (e) => { if (e.code === 'ArrowDown' || e.code === 'ArrowUp') { @@ -100,10 +129,10 @@ export default ({ worldData, onGeneralAction, onWorldAction, activeProvider, set return
-
- Select Saved World + {serversLayout ? 'Join Java Servers' : 'Select Saved World'} + {searchRowChildrenOverride ||
setSearch(value)} /> -
+
}
{ setActiveProvider?.(tab as any) @@ -147,15 +176,17 @@ export default ({ worldData, onGeneralAction, onWorldAction, activeProvider, set }
-
-
- +
+ {firstRowChildrenOverride ||
+ -
+
}
- + {serversLayout ? : } - + {serversLayout ? + : + }
diff --git a/src/react/SingleplayerProvider.tsx b/src/react/SingleplayerProvider.tsx index 8eb3af0f..35704e8e 100644 --- a/src/react/SingleplayerProvider.tsx +++ b/src/react/SingleplayerProvider.tsx @@ -85,7 +85,7 @@ export const readWorlds = (abortController: AbortController) => { title: levelName ?? folder, lastPlayed: levelDat.LastPlayed && longArrayToNumber(levelDat.LastPlayed), detail: `${levelDat.Version?.Name ?? 'unknown version'}, ${folder}`, - iconBase64, + iconSrc: iconBase64 ? `data:image/png;base64,${iconBase64}` : undefined, size, } satisfies WorldProps }))).filter((x, i) => { diff --git a/src/react/input.module.css b/src/react/input.module.css index 9ad01c90..ce889645 100644 --- a/src/react/input.module.css +++ b/src/react/input.module.css @@ -1,39 +1,40 @@ .container { - position: relative; - width: 200px; - height: 20px; - background: black; - border: 1px solid grey; - box-sizing: content-box; + position: relative; + width: 200px; + height: 20px; + background: black; + border: 1px solid grey; + box-sizing: content-box; } .input { - position: relative; - outline: none; - border: none; - background: none; - left: 1px; - width: calc(100% - 2px); - height: 100%; - font-family: minecraft, mojangles, monospace; - font-size: 10px; - color: white; - text-shadow: 1px 1px #222; + position: relative; + outline: none; + border: none; + background: none; + left: 1px; + width: calc(100% - 2px); + height: 100%; + font-family: minecraft, mojangles, monospace; + font-size: 10px; + color: white; + text-shadow: 1px 1px #222; + padding-left: 2px; } .container:hover, - .container:focus-within { - border-color: white; - } +.container:focus-within { + border-color: white; +} - input::-webkit-outer-spin-button, - input::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; - } +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} - /* Firefox */ - input[type=number] { - appearance: textfield; - -moz-appearance: textfield; - } +/* Firefox */ +input[type=number] { + appearance: textfield; + -moz-appearance: textfield; +} diff --git a/src/react/simpleHooks.ts b/src/react/simpleHooks.ts new file mode 100644 index 00000000..9202bfa2 --- /dev/null +++ b/src/react/simpleHooks.ts @@ -0,0 +1,6 @@ +import { useMedia } from 'react-use' + +const SMALL_SCREEN_MEDIA = '@media (max-width: 440px)' +export const useIsSmallWidth = () => { + return useMedia(SMALL_SCREEN_MEDIA.replace('@media ', '')) +} diff --git a/src/react/singleplayer.module.css b/src/react/singleplayer.module.css index 1e092b39..fef43b76 100644 --- a/src/react/singleplayer.module.css +++ b/src/react/singleplayer.module.css @@ -28,11 +28,25 @@ display: flex; outline: none; } +.world_title { + display: flex; + justify-content: space-between; + align-items: center; +} +.world_title_right { + color: #999; + font-size: 9px; +} .world_info { margin-left: 3px; display: flex; flex-direction: column; font-size: 11px; + white-space: nowrap; +} +.world_info_formatted { + font-size: 10px; + white-space: pre; } .world_info_description_line { color: #999; diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 4c5f1516..419d8dff 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -33,6 +33,7 @@ import TouchAreasControlsProvider from './react/TouchAreasControlsProvider' import NotificationProvider, { showNotification } from './react/NotificationProvider' import HotbarRenderApp from './react/HotbarRenderApp' import Crosshair from './react/Crosshair' +import ServersListProvider from './react/ServersListProvider' const RobustPortal = ({ children, to }) => { return createPortal({children}, to) @@ -139,6 +140,7 @@ const App = () => { + diff --git a/src/watchOptions.ts b/src/watchOptions.ts index 009463be..56fc9c2c 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -2,10 +2,10 @@ import { subscribeKey } from 'valtio/utils' import { WorldRendererThree } from 'prismarine-viewer/viewer/lib/worldrendererThree' +import { isMobile } from 'prismarine-viewer/viewer/lib/simpleUtils' import { options, watchValue } from './optionsStorage' import { reloadChunks } from './utils' import { miscUiState } from './globalState' -import { isMobile } from './menus/components/common' subscribeKey(options, 'renderDistance', reloadChunks) subscribeKey(options, 'multiplayerRenderDistance', reloadChunks) From ab9e5db4453e7a31d33f30e0e4439030a4e517d2 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Sun, 5 May 2024 02:58:08 +0300 Subject: [PATCH 0060/1097] up flying squid --- package.json | 4 +- pnpm-lock.yaml | 165 +++++++++++++------------------------------------ 2 files changed, 44 insertions(+), 125 deletions(-) diff --git a/package.json b/package.json index 4d99a6d5..d1f4c7eb 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "esbuild": "^0.19.3", "esbuild-plugin-polyfill-node": "^0.3.0", "express": "^4.18.2", - "flying-squid": "npm:@zardoy/flying-squid@^0.0.17", + "flying-squid": "npm:@zardoy/flying-squid@^0.0.19", "fs-extra": "^11.1.1", "google-drive-browserfs": "github:zardoy/browserfs#google-drive", "iconify-icon": "^1.0.8", @@ -96,8 +96,6 @@ "@storybook/blocks": "^7.4.6", "@storybook/react": "^7.4.6", "@storybook/react-vite": "^7.4.6", - "@storybook/web-components": "^7.4.6", - "@storybook/web-components-vite": "^7.4.6", "@types/lodash-es": "^4.17.9", "@types/react-transition-group": "^4.4.7", "@types/stats.js": "^0.17.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ef5b1d0..9d1b69cc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -93,8 +93,8 @@ importers: specifier: ^4.18.2 version: 4.18.2 flying-squid: - specifier: npm:@zardoy/flying-squid@^0.0.17 - version: '@zardoy/flying-squid@0.0.17(encoding@0.1.13)' + specifier: npm:@zardoy/flying-squid@^0.0.19 + version: '@zardoy/flying-squid@0.0.19(encoding@0.1.13)' fs-extra: specifier: ^11.1.1 version: 11.1.1 @@ -130,7 +130,7 @@ importers: version: 6.1.1 prismarine-provider-anvil: specifier: github:zardoy/prismarine-provider-anvil#everything - version: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/0ddcd9d48574113308e1fbebef60816aced0846f(minecraft-data@3.62.0) + version: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.62.0) prosemirror-example-setup: specifier: ^1.2.2 version: 1.2.2 @@ -211,12 +211,6 @@ importers: '@storybook/react-vite': specifier: ^7.4.6 version: 7.4.6(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(rollup@2.79.1)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) - '@storybook/web-components': - specifier: ^7.4.6 - version: 7.4.6(encoding@0.1.13)(lit@2.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/web-components-vite': - specifier: ^7.4.6 - version: 7.4.6(encoding@0.1.13)(lit@2.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) '@types/lodash-es': specifier: ^4.17.9 version: 4.17.9 @@ -409,7 +403,7 @@ importers: dependencies: vite: specifier: ^4.4.9 - version: 4.4.10(@types/node@20.12.7)(terser@5.19.2) + version: 4.4.10(@types/node@20.12.8)(terser@5.19.2) packages: @@ -1922,12 +1916,6 @@ packages: '@juggle/resize-observer@3.3.1': resolution: {integrity: sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==} - '@lit-labs/ssr-dom-shim@1.1.1': - resolution: {integrity: sha512-kXOeFbfCm4fFf2A3WwVEeQj55tMZa8c8/f9AKHMobQMkzNUfUj+antR3fRPaZJawsa1aZiP/Da3ndpZrwEe4rQ==} - - '@lit/reactive-element@1.6.3': - resolution: {integrity: sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==} - '@mapbox/node-pre-gyp@1.0.11': resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} hasBin: true @@ -2619,19 +2607,6 @@ packages: '@storybook/types@7.4.6': resolution: {integrity: sha512-6QLXtMVsFZFpzPkdGWsu/iuc8na9dnS67AMOBKm5qCLPwtUJOYkwhMdFRSSeJthLRpzV7JLAL8Kwvl7MFP3QSw==} - '@storybook/web-components-vite@7.4.6': - resolution: {integrity: sha512-L/y6MTLbqfHaM0faK9Yl8n5PIyW4daZrtk7NfaOT6UjgNFjOx3o4CctYew6oj90cNk5HdZQX2OZny043GxDLZw==} - engines: {node: ^14.18 || >=16} - peerDependencies: - react: ^18.2.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - - '@storybook/web-components@7.4.6': - resolution: {integrity: sha512-HWqkZtdkmNimkzMmE0mGRys2ee9qgEeDVCruiffySVquBRMQ6n1xgvHZYaO6OLlMeH0YHPg083ZqUasS5GsYVg==} - engines: {node: '>=16.0.0'} - peerDependencies: - lit: ^2.0.0 - '@surma/rollup-plugin-off-main-thread@2.2.3': resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} @@ -2792,8 +2767,8 @@ packages: '@types/node@20.11.19': resolution: {integrity: sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==} - '@types/node@20.12.7': - resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} + '@types/node@20.12.8': + resolution: {integrity: sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==} '@types/node@20.8.0': resolution: {integrity: sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ==} @@ -2837,8 +2812,8 @@ packages: '@types/react@18.2.20': resolution: {integrity: sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw==} - '@types/readable-stream@4.0.11': - resolution: {integrity: sha512-R3eUMUTTKoIoaz7UpYLxvZCrOmCRPRbAmoDDHKcimTEySltaJhF8hLzj4+EzyDifiX5eK6oDQGSfmNnXjxZzYQ==} + '@types/readable-stream@4.0.12': + resolution: {integrity: sha512-SCaw+bs9o/HCX1eTa3glTcQgW1oPxof49mqP2Qikik3xzTimNv2M4p43BQHhBuf7CwOJdQW0s1SrWU3MZxz6lw==} '@types/resolve@1.17.1': resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} @@ -3059,8 +3034,8 @@ packages: resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==} engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'} - '@zardoy/flying-squid@0.0.17': - resolution: {integrity: sha512-qGCS7aRmMflDdIN7IGLpDc0W2gUYc5OQ45KEn3XtcxwOP0Q7zyvo3mnsD5KSV3n2lyhQ4783Ov8V6J86xea0lw==} + '@zardoy/flying-squid@0.0.19': + resolution: {integrity: sha512-q0eW/AO66bA5YQfGd+mnZjenZ7oocCrxlU4ktJbS4vfhjC2PPLzXLpWhXnzqN9A3VSzMzraV/9SY9kGQkw8xNA==} engines: {node: '>=8'} hasBin: true @@ -4295,8 +4270,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-iterator-helpers@1.0.18: - resolution: {integrity: sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==} + es-iterator-helpers@1.0.19: + resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} engines: {node: '>= 0.4'} es-module-lexer@0.9.3: @@ -4963,6 +4938,10 @@ packages: resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} engines: {node: '>= 0.4'} + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -5697,15 +5676,6 @@ packages: enquirer: optional: true - lit-element@3.3.3: - resolution: {integrity: sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==} - - lit-html@2.8.0: - resolution: {integrity: sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==} - - lit@2.8.0: - resolution: {integrity: sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==} - load-bmfont@1.4.1: resolution: {integrity: sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA==} @@ -6742,8 +6712,8 @@ packages: prismarine-physics@1.8.0: resolution: {integrity: sha512-gbM+S+bmVtOKVv+Z0WGaHMeEeBHISIDsRDRlv8sr0dex3ZJRhuq8djA02CBreguXtI18ZKh6q3TSj2qDr45NHA==} - prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/0ddcd9d48574113308e1fbebef60816aced0846f: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/0ddcd9d48574113308e1fbebef60816aced0846f} + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29} version: 2.7.0 prismarine-realms@1.3.2: @@ -6937,6 +6907,9 @@ packages: rambda@6.9.0: resolution: {integrity: sha512-yosVdGg1hNGkXPzqGiOYNEpXKjEOxzUCg2rB0l+NKdyCaSf4z+i5ojbN0IqDSezMMf71YEglI+ZUTgTffn5afw==} + rambda@9.2.0: + resolution: {integrity: sha512-RjM8TBNPR+iSvWLqbBpFveDfEf2RPRKHuwBHjQdXsYFDwn3MIvgmJiqVVC1CIQKnOwzeDQd44zqDFgSKQ7RT1Q==} + ramda@0.29.0: resolution: {integrity: sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA==} @@ -10306,12 +10279,6 @@ snapshots: '@juggle/resize-observer@3.3.1': {} - '@lit-labs/ssr-dom-shim@1.1.1': {} - - '@lit/reactive-element@1.6.3': - dependencies: - '@lit-labs/ssr-dom-shim': 1.1.1 - '@mapbox/node-pre-gyp@1.0.11(encoding@0.1.13)': dependencies: detect-libc: 2.0.2 @@ -11438,44 +11405,6 @@ snapshots: '@types/express': 4.17.18 file-system-cache: 2.3.0 - '@storybook/web-components-vite@7.4.6(encoding@0.1.13)(lit@2.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2))': - dependencies: - '@storybook/builder-vite': 7.4.6(encoding@0.1.13)(typescript@5.5.0-beta)(vite@4.5.3(@types/node@20.8.0)(terser@5.19.2)) - '@storybook/core-server': 7.4.6(encoding@0.1.13) - '@storybook/node-logger': 7.4.6 - '@storybook/web-components': 7.4.6(encoding@0.1.13)(lit@2.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - magic-string: 0.30.4 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - transitivePeerDependencies: - - '@preact/preset-vite' - - bufferutil - - encoding - - lit - - supports-color - - typescript - - utf-8-validate - - vite - - vite-plugin-glimmerx - - '@storybook/web-components@7.4.6(encoding@0.1.13)(lit@2.8.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': - dependencies: - '@storybook/client-logger': 7.4.6 - '@storybook/core-client': 7.4.6 - '@storybook/docs-tools': 7.4.6(encoding@0.1.13) - '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@storybook/preview-api': 7.4.6 - '@storybook/types': 7.4.6 - lit: 2.8.0 - tiny-invariant: 1.3.1 - ts-dedent: 2.2.0 - transitivePeerDependencies: - - encoding - - react - - react-dom - - supports-color - '@surma/rollup-plugin-off-main-thread@2.2.3': dependencies: ejs: 3.1.9 @@ -11643,7 +11572,7 @@ snapshots: undici-types: 5.26.5 optional: true - '@types/node@20.12.7': + '@types/node@20.12.8': dependencies: undici-types: 5.26.5 @@ -11685,9 +11614,9 @@ snapshots: '@types/scheduler': 0.16.3 csstype: 3.1.2 - '@types/readable-stream@4.0.11': + '@types/readable-stream@4.0.12': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.12.8 safe-buffer: 5.1.2 '@types/resolve@1.17.1': @@ -11975,7 +11904,7 @@ snapshots: '@types/emscripten': 1.39.8 tslib: 1.14.1 - '@zardoy/flying-squid@0.0.17(encoding@0.1.13)': + '@zardoy/flying-squid@0.0.19(encoding@0.1.13)': dependencies: change-case: 4.1.2 colors: 1.4.0 @@ -11994,9 +11923,10 @@ snapshots: prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 - prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/0ddcd9d48574113308e1fbebef60816aced0846f(minecraft-data@3.62.0) + prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.62.0) prismarine-windows: 2.9.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 + rambda: 9.2.0 random-seed: 0.3.0 range: 0.0.3 readline: 1.3.0 @@ -13540,7 +13470,7 @@ snapshots: function.prototype.name: 1.1.6 get-intrinsic: 1.2.4 get-symbol-description: 1.0.2 - globalthis: 1.0.3 + globalthis: 1.0.4 gopd: 1.0.1 has-property-descriptors: 1.0.2 has-proto: 1.0.3 @@ -13578,7 +13508,7 @@ snapshots: es-errors@1.3.0: {} - es-iterator-helpers@1.0.18: + es-iterator-helpers@1.0.19: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -13587,7 +13517,7 @@ snapshots: es-set-tostringtag: 2.0.3 function-bind: 1.1.2 get-intrinsic: 1.2.4 - globalthis: 1.0.3 + globalthis: 1.0.4 has-property-descriptors: 1.0.2 has-proto: 1.0.3 has-symbols: 1.0.3 @@ -13864,7 +13794,7 @@ snapshots: array.prototype.toreversed: 1.1.2 array.prototype.tosorted: 1.1.3 doctrine: 2.1.0 - es-iterator-helpers: 1.0.18 + es-iterator-helpers: 1.0.19 eslint: 8.50.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.5 @@ -14490,6 +14420,11 @@ snapshots: dependencies: define-properties: 1.2.1 + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.0.1 + globby@11.1.0: dependencies: array-union: 2.1.0 @@ -15271,22 +15206,6 @@ snapshots: optionalDependencies: enquirer: 2.4.1 - lit-element@3.3.3: - dependencies: - '@lit-labs/ssr-dom-shim': 1.1.1 - '@lit/reactive-element': 1.6.3 - lit-html: 2.8.0 - - lit-html@2.8.0: - dependencies: - '@types/trusted-types': 2.0.3 - - lit@2.8.0: - dependencies: - '@lit/reactive-element': 1.6.3 - lit-element: 3.3.3 - lit-html: 2.8.0 - load-bmfont@1.4.1: dependencies: buffer-equal: 0.0.1 @@ -15744,7 +15663,7 @@ snapshots: minecraft-protocol@https://codeload.github.com/zardoy/minecraft-protocol/tar.gz/2c14a686bfe7cbd9a5c87b629b402295ee86219f(encoding@0.1.13): dependencies: - '@types/readable-stream': 4.0.11 + '@types/readable-stream': 4.0.12 aes-js: 3.1.2 buffer-equal: 1.0.1 debug: 4.3.4(supports-color@8.1.1) @@ -16563,7 +16482,7 @@ snapshots: prismarine-nbt: 2.5.0 vec3: 0.1.8 - prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/0ddcd9d48574113308e1fbebef60816aced0846f(minecraft-data@3.62.0): + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.62.0): dependencies: prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.62.0) prismarine-nbt: 2.5.0 @@ -16825,6 +16744,8 @@ snapshots: rambda@6.9.0: {} + rambda@9.2.0: {} + ramda@0.29.0: {} randexp@0.4.6: @@ -17108,7 +17029,7 @@ snapshots: es-abstract: 1.23.3 es-errors: 1.3.0 get-intrinsic: 1.2.4 - globalthis: 1.0.3 + globalthis: 1.0.4 which-builtin-type: 1.1.3 regenerate-unicode-properties@10.1.0: @@ -18447,13 +18368,13 @@ snapshots: - supports-color - terser - vite@4.4.10(@types/node@20.12.7)(terser@5.19.2): + vite@4.4.10(@types/node@20.12.8)(terser@5.19.2): dependencies: esbuild: 0.18.20 postcss: 8.4.31 rollup: 3.29.4 optionalDependencies: - '@types/node': 20.12.7 + '@types/node': 20.12.8 fsevents: 2.3.3 terser: 5.19.2 From 1e7153c2e299273577ad7876d6445b709c1ebf20 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Sun, 5 May 2024 03:25:08 +0300 Subject: [PATCH 0061/1097] feat: publish all stories UI components to npm! (#111) --- .github/workflows/ci.yml | 1 + .github/workflows/publish.yml | 7 + .gitignore | 4 +- README.MD | 5 +- README.NPM.MD | 32 ++++ experiments/UiStandaloneExample.tsx | 71 +++++++++ package.json | 14 +- package.npm.json | 36 +++++ pnpm-lock.yaml | 51 +++--- scripts/buildNpmReact.ts | 148 ++++++++++++++++++ src/botUtils.test.ts | 4 +- src/botUtils.ts | 11 +- src/controls.ts | 2 +- src/entities.ts | 4 + src/flyingSquidEvents.ts | 2 +- src/globals.d.ts | 44 +----- src/react/AppStatusProvider.tsx | 3 +- src/react/ArmorBar.css | 1 + src/react/ArmorBar.tsx | 4 +- src/react/BarsCommon.tsx | 26 +++ src/react/BossBarOverlay.css | 4 +- src/react/BreathBar.css | 1 + src/react/Button.stories.tsx | 18 +++ src/react/Button.tsx | 28 ++-- src/react/ButtonAppProvider.tsx | 10 ++ src/react/{ChatContainer.css => Chat.css} | 0 src/react/Chat.stories.tsx | 2 +- src/react/{ChatContainer.tsx => Chat.tsx} | 5 +- src/react/ChatProvider.tsx | 6 +- src/react/CreateWorldProvider.tsx | 2 +- src/react/DeathScreenProvider.tsx | 2 +- ...n.module.css => DiveTransition.module.css} | 0 ...stories.tsx => DiveTransition.stories.tsx} | 0 src/react/DiveTransition.tsx | 2 +- src/react/EnterFullscreenButton.tsx | 2 +- src/react/FoodBar.css | 1 + src/react/FoodBar.stories.tsx | 19 +++ src/react/FoodBar.tsx | 33 ++-- src/react/FullScreenWidget.tsx | 2 +- src/react/HealthBar.css | 1 + src/react/HealthBar.stories.tsx | 24 --- src/react/HealthBar.tsx | 51 +++--- src/react/HudBarsProvider.tsx | 28 +--- src/react/Input.tsx | 5 +- src/react/MessageFormatted.tsx | 2 +- src/react/PauseScreen.tsx | 2 +- src/react/PixelartIcon.tsx | 2 +- src/react/PlayerListOverlay.css | 5 +- src/react/PlayerListOverlay.stories.tsx | 10 +- src/react/PlayerListOverlay.tsx | 9 +- src/react/Scoreboard.tsx | 10 +- src/react/SelectOption.tsx | 2 +- src/react/ServersListProvider.tsx | 3 +- src/react/SharedHudVars.tsx | 11 +- src/react/SignEditorProvider.tsx | 2 +- src/react/SingleplayerProvider.tsx | 2 +- src/react/Slider.tsx | 63 ++++---- src/react/SoundMuffler.tsx | 2 +- src/react/TouchAreasControlsProvider.tsx | 2 +- src/react/TouchControls.tsx | 2 +- src/react/globals.d.ts | 45 ++++++ src/react/npmReactEntrypoint.ts | 1 + src/react/utils.ts | 19 +-- src/react/utilsApp.ts | 15 ++ src/reactUi.tsx | 37 +++-- src/styles.css | 1 - src/worldInteractions.ts | 2 + tsconfig.npm.json | 12 ++ 68 files changed, 688 insertions(+), 289 deletions(-) create mode 100644 README.NPM.MD create mode 100644 experiments/UiStandaloneExample.tsx create mode 100644 package.npm.json create mode 100644 scripts/buildNpmReact.ts create mode 100644 src/react/BarsCommon.tsx create mode 100644 src/react/Button.stories.tsx create mode 100644 src/react/ButtonAppProvider.tsx rename src/react/{ChatContainer.css => Chat.css} (100%) rename src/react/{ChatContainer.tsx => Chat.tsx} (99%) rename src/react/{diveAnimation.module.css => DiveTransition.module.css} (100%) rename src/react/{Dive.stories.tsx => DiveTransition.stories.tsx} (100%) create mode 100644 src/react/FoodBar.stories.tsx create mode 100644 src/react/globals.d.ts create mode 100644 src/react/npmReactEntrypoint.ts create mode 100644 src/react/utilsApp.ts create mode 100644 tsconfig.npm.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b08045be..0663fce7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,6 +18,7 @@ jobs: - run: pnpm check-build - run: pnpm test-unit - run: pnpm lint + - run: pnpm tsx scripts/buildNpmReact.ts - run: nohup pnpm prod-start & - run: nohup pnpm test-mc-server & - uses: cypress-io/github-action@v5 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index cbc09b43..79bc5ffd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -33,9 +33,16 @@ jobs: pnpx zardoy-release node --footer "This release URL: ${{ steps.deploy.outputs.stdout }}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - run: | + pnpx zardoy-release npm + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: cp vercel.json .vercel/output/static/vercel.json - uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: .vercel/output/static force_orphan: true + - run: pnpm tsx scripts/buildNpmReact.ts + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index c4434877..240b751a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ package-lock.json Thumbs.db build localSettings.mjs -dist +dist* .DS_Store .idea/ world @@ -17,3 +17,5 @@ out .vercel generated storybook-static + +src/react/npmReactComponents.ts diff --git a/README.MD b/README.MD index 7a93ce7e..1b8b84ac 100644 --- a/README.MD +++ b/README.MD @@ -4,7 +4,7 @@ A true Minecraft client running in your browser! A port of the original game to the web, written in JavaScript using modern web technologies. -This project is a work in progress, but I consider it to be usable. If you encounter any bugs or usability issues, please report them! +If you encounter any bugs or usability issues, please report them! You can try this out at [mcraft.fun](https://mcraft.fun/), [pcm.gg](https://pcm.gg) (short link) [mcon.vercel.app](https://mcon.vercel.app/) or the GitHub pages deploy. Every commit from the `develop` (default) branch is deployed to [s.mcraft.fun](https://s.mcraft.fun/) - so it's usually newer, but might be less stable. @@ -19,6 +19,8 @@ You can try this out at [mcraft.fun](https://mcraft.fun/), [pcm.gg](https://pcm. - Resource pack support - even even more! +All components that are in [Storybook](https://mcraft.fun/storybook) are published as npm module and can be used in other projects: [`minecraft-react`](https://npmjs.com/minecraft-react) + ### Recommended Settings - Controls -> **Raw Input** -> **On** - This will make the controls more precise @@ -65,7 +67,6 @@ To open the console, press `F12`, or if you are on mobile, you can type `#debug` It should be easy to build/start the project locally. See [CONTRIBUTING.MD](./CONTRIBUTING.md) for more info. -There is storybook for fast UI development. Run `pnpm storybook` to start it. There is world renderer playground ([link](https://mcon.vercel.app/playground.html)). However, there are many things that can be done in online version. You can access some global variables in the console and useful examples: diff --git a/README.NPM.MD b/README.NPM.MD new file mode 100644 index 00000000..24c90bc9 --- /dev/null +++ b/README.NPM.MD @@ -0,0 +1,32 @@ +# Minecraft React + +```bash +yarn add minecraft-react +``` + +## Usage + +```jsx +import { Scoreboard } from 'minecraft-react' + +const App = () => { + return ( + + ) +} +``` + +See [Storybook](https://mcraft.fun/storybook/) or [Storybook (Mirror link)](https://mcon.vercel.app/storybook/) for more examples and full components list. Also take a look at the full [standalone example](https://github.com/zardoy/prismarine-web-client/tree/experiments/UiStandaloneExample.tsx). + +There are two types of components: + +- Small UI components or HUD components +- Full screen components (like sign editor, worlds selector) diff --git a/experiments/UiStandaloneExample.tsx b/experiments/UiStandaloneExample.tsx new file mode 100644 index 00000000..80f68e8d --- /dev/null +++ b/experiments/UiStandaloneExample.tsx @@ -0,0 +1,71 @@ +import React, { useState } from 'react' +import { createRoot } from 'react-dom/client' +import { + Button, + Slider, + ArmorBar, + BreathBar, + Chat, + HealthBar, + PlayerListOverlay, + Scoreboard, + MessageFormattedString, + XPBar, + FoodBar +} from '../dist-npm' + +const ExampleDemo = () => { + const [sliderValue, setSliderValue] = useState(0) + + return ( +
+ + setSliderValue(value)} /> + + { + console.log('typed', message) + // close + }} + /> + + + + + "§bRed" displays as + + +
+ ) +} + +createRoot(document.body as Element).render() diff --git a/package.json b/package.json index d1f4c7eb..25a87472 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,12 @@ "web", "client" ], - "author": "PrismarineJS", + "publish": { + "preset": { + "publishOnlyIfChanged": true, + "runBuild": false + } + }, "license": "MIT", "dependencies": { "@dimaka/interface": "0.0.3-alpha.0", @@ -48,6 +53,7 @@ "adm-zip": "^0.5.12", "browserfs": "github:zardoy/browserfs#build", "change-case": "^5.1.2", + "classnames": "^2.5.1", "compression": "^1.7.4", "cors": "^2.8.5", "cypress-plugin-snapshots": "^1.4.4", @@ -78,11 +84,15 @@ "react-dom": "^18.2.0", "react-transition-group": "^4.4.5", "remark": "^15.0.1", + "filesize": "^10.0.12", "sanitize-filename": "^1.6.3", "skinview3d": "^3.0.1", "source-map-js": "^1.0.2", "stats-gl": "^1.0.5", "stats.js": "^0.17.0", + "use-typed-event-listener": "^4.0.2", + "mojangson": "^2.0.4", + "prosemirror-menu": "^1.2.4", "tabbable": "^6.2.0", "title-case": "3.x", "ua-parser-js": "^1.0.37", @@ -113,7 +123,6 @@ "eslint": "^8.50.0", "eslint-config-zardoy": "^0.2.17", "events": "^3.3.0", - "filesize": "^10.0.12", "http-browserify": "^1.7.0", "http-server": "^14.1.1", "https-browserify": "^1.0.0", @@ -132,7 +141,6 @@ "three": "0.154.0", "timers-browserify": "^2.0.12", "typescript": "5.5.0-beta", - "use-typed-event-listener": "^4.0.2", "vitest": "^0.34.6", "yaml": "^2.3.2" }, diff --git a/package.npm.json b/package.npm.json new file mode 100644 index 00000000..bae8b60f --- /dev/null +++ b/package.npm.json @@ -0,0 +1,36 @@ +{ + "name": "minecraft-react", + "description": "A Minecraft-like React UI library", + "keywords": [ + "minecraft", + "minecraft style" + ], + "license": "MIT", + "sideEffects": false, + "files": [ + "**" + ], + "exports": { + ".": { + "default": "./dist/react/npmReactComponents.js", + "types": "./dist/react/npmReactComponents.d.ts" + }, + "./*": { + "default": "./dist/react/*", + "types": "./dist/react/*" + }, + "./dist": { + "default": "./dist/*", + "types": "./dist/*" + } + }, + "module": "./dist/react/npmReactComponents.js", + "types": "./dist/react/npmReactComponents.d.ts", + "repository": "zardoy/prismarine-web-client", + "version": "0.0.0-dev", + "dependencies": {}, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9d1b69cc..054539d5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,6 +68,9 @@ importers: change-case: specifier: ^5.1.2 version: 5.1.2 + classnames: + specifier: ^2.5.1 + version: 2.5.1 compression: specifier: ^1.7.4 version: 1.7.4 @@ -92,6 +95,9 @@ importers: express: specifier: ^4.18.2 version: 4.18.2 + filesize: + specifier: ^10.0.12 + version: 10.0.12 flying-squid: specifier: npm:@zardoy/flying-squid@^0.0.19 version: '@zardoy/flying-squid@0.0.19(encoding@0.1.13)' @@ -116,6 +122,9 @@ importers: minecraft-data: specifier: 3.62.0 version: 3.62.0 + mojangson: + specifier: ^2.0.4 + version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070 @@ -137,6 +146,9 @@ importers: prosemirror-markdown: specifier: ^1.12.0 version: 1.12.0 + prosemirror-menu: + specifier: ^1.2.4 + version: 1.2.4 prosemirror-state: specifier: ^1.4.3 version: 1.4.3 @@ -182,6 +194,9 @@ importers: ua-parser-js: specifier: ^1.0.37 version: 1.0.37 + use-typed-event-listener: + specifier: ^4.0.2 + version: 4.0.2(react@18.2.0)(typescript@5.5.0-beta) valtio: specifier: ^1.11.1 version: 1.11.2(@types/react@18.2.20)(react@18.2.0) @@ -262,9 +277,6 @@ importers: events: specifier: ^3.3.0 version: 3.3.0 - filesize: - specifier: ^10.0.12 - version: 10.0.12 http-browserify: specifier: ^1.7.0 version: 1.7.0 @@ -319,9 +331,6 @@ importers: typescript: specifier: 5.5.0-beta version: 5.5.0-beta - use-typed-event-listener: - specifier: ^4.0.2 - version: 4.0.2(react@18.2.0)(typescript@5.5.0-beta) vitest: specifier: ^0.34.6 version: 0.34.6(terser@5.19.2) @@ -3635,8 +3644,8 @@ packages: cipher-base@1.0.4: resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} - classnames@2.3.2: - resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} + classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} @@ -9968,7 +9977,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.2 - '@types/node': 20.8.0 + '@types/node': 20.12.8 '@types/yargs': 17.0.28 chalk: 4.1.2 @@ -11459,11 +11468,11 @@ snapshots: '@types/cors@2.8.15': dependencies: - '@types/node': 20.8.0 + '@types/node': 20.12.8 '@types/cross-spawn@6.0.3': dependencies: - '@types/node': 20.8.10 + '@types/node': 20.12.8 '@types/debug@4.1.12': dependencies: @@ -11512,7 +11521,7 @@ snapshots: '@types/graceful-fs@4.1.7': dependencies: - '@types/node': 20.8.10 + '@types/node': 20.12.8 '@types/http-cache-semantics@4.0.2': {} @@ -11621,7 +11630,7 @@ snapshots: '@types/resolve@1.17.1': dependencies: - '@types/node': 20.8.10 + '@types/node': 20.12.8 '@types/sat@0.0.31': {} @@ -11632,7 +11641,7 @@ snapshots: '@types/send@0.17.2': dependencies: '@types/mime': 1.3.3 - '@types/node': 20.8.10 + '@types/node': 20.12.8 '@types/serve-static@1.15.3': dependencies: @@ -11941,7 +11950,7 @@ snapshots: '@zardoy/react-util@0.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - classnames: 2.3.2 + classnames: 2.5.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -12674,7 +12683,7 @@ snapshots: inherits: 2.0.4 safe-buffer: 5.2.1 - classnames@2.3.2: {} + classnames@2.5.1: {} clean-regexp@1.0.0: dependencies: @@ -13373,7 +13382,7 @@ snapshots: dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.15 - '@types/node': 20.8.0 + '@types/node': 20.12.8 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.4.2 @@ -14976,7 +14985,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.7 - '@types/node': 20.8.0 + '@types/node': 20.12.8 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -14993,7 +15002,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.8.0 + '@types/node': 20.12.8 chalk: 4.1.2 ci-info: 3.8.0 graceful-fs: 4.2.11 @@ -15001,13 +15010,13 @@ snapshots: jest-worker@26.6.2: dependencies: - '@types/node': 20.8.10 + '@types/node': 20.12.8 merge-stream: 2.0.0 supports-color: 7.2.0 jest-worker@29.7.0: dependencies: - '@types/node': 20.8.10 + '@types/node': 20.12.8 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 diff --git a/scripts/buildNpmReact.ts b/scripts/buildNpmReact.ts new file mode 100644 index 00000000..71513cb3 --- /dev/null +++ b/scripts/buildNpmReact.ts @@ -0,0 +1,148 @@ +import fs from 'fs' +import path from 'path' +import { build, transform } from 'esbuild' +import { execSync } from 'child_process' +// import { copy } from 'fs-extra' +import { glob } from 'glob' + +const isAbsolute = (path: string) => path.startsWith('/') || /^[A-Z]:/i.test(path) + +fs.promises.readdir(path.resolve(__dirname, '../src/react')).then(async (files) => { + const components = files + .filter((file) => { + if (file.startsWith('Concept')) return false + return file.endsWith('.stories.tsx'); + }) + .map((file) => { + return file.replace('.stories.tsx', '') + }) + + const content = components.map((component) => { + return `export { default as ${component} } from './${component}'` + }).join('\n') + + await fs.promises.writeFile( + path.resolve(__dirname, '../src/react/npmReactComponents.ts'), + content + ) + + execSync('pnpm tsc -p tsconfig.npm.json', { + cwd: path.resolve(__dirname, '../'), + stdio: 'inherit', + }) + + const packageJson = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../package.npm.json'), 'utf-8')) + const packageJsonRoot = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8')) + const external = Object.keys(packageJson.peerDependencies) + const dependencies = new Set() + const version = packageJsonRoot.version + packageJson.version = version + + const externalize = ['minecraft-assets', 'prismarine-viewer'] + const { metafile } = await build({ + entryPoints: [path.resolve(__dirname, '../src/react/npmReactComponents.ts')], + bundle: true, + outfile: path.resolve(__dirname, '../dist-npm/bundle.esm.js'), + format: 'esm', + platform: 'browser', + target: 'es2020', + external: external, + metafile: true, + minify: true, + write: false, // todo + loader: { + '.png': 'dataurl', + }, + plugins: [ + // on external module resolve + { + name: 'collect-imports', + setup (build) { + build.onResolve({ filter: /.*/ }, (args) => { + if (args.importer.includes('node_modules') || external.some(x => args.path.startsWith(x)) || isAbsolute(args.path)) { + return undefined + } + if (args.path.startsWith('./') || args.path.startsWith('../')) { + if (args.path.endsWith('.png') || args.path.endsWith('.css') || args.path.endsWith('.jpg') || args.path.endsWith('.jpeg')) { + const absoluteImporting = path.join(path.dirname(args.importer), args.path) + const absoluteRoot = path.resolve(__dirname, '../src') + const relativeToRoot = path.relative(absoluteRoot, absoluteImporting) + fs.copyFileSync(absoluteImporting, path.resolve(__dirname, '../dist-npm/dist-pre', relativeToRoot)) + } + // default behavior + return undefined + } + const dep = args.path.startsWith('@') ? args.path.split('/').slice(0, 2).join('/') : args.path.split('/')[0] + if (!dependencies.has(dep)) { + dependencies.add(dep) + console.log('Adding dependency:', dep, 'from', args.importer) + } + // return { external: true } + }) + }, + }, + ], + }) + for (const dependency of dependencies) { + if (externalize.includes(dependency)) continue + if (!packageJsonRoot.dependencies[dependency]) throw new Error(`Dependency ${dependency} not found in package.json`) + packageJson.dependencies[dependency] = packageJsonRoot.dependencies[dependency] + } + fs.writeFileSync(path.resolve(__dirname, '../dist-npm/package.json'), JSON.stringify(packageJson, null, 2)) + // fs.promises.writeFile('./dist-npm/metafile.json', JSON.stringify(metafile, null, 2)) + + await build({ + entryPoints: ['dist-npm/dist-pre/**/*.js'], + outdir: 'dist-npm/dist', + // allowOverwrite: true, + jsx: 'preserve', + bundle: true, + target: 'esnext', + platform: 'browser', + format: 'esm', + loader: { + '.css': 'copy', + '.module.css': 'copy', + '.png': 'copy', + }, + minifyWhitespace: false, + logOverride: { + // 'ignored-bare-import': "info" + }, + plugins: [ + { + name: 'all-external', + setup (build) { + build.onResolve({ filter: /.*/ }, (args) => { + // todo use workspace deps + if (externalize.some(x => args.path.startsWith(x))) { + return undefined // bundle + } + if (args.path.endsWith('.css') || args.path.endsWith('.png') || args.path.endsWith('.jpg') || args.path.endsWith('.jpeg')) { + return undefined // loader action + } + return { + path: args.path, + external: true, + } + }) + }, + } + ], + }) + + const paths = await glob('dist-npm/dist-pre/**/*.d.ts') + // copy to dist + for (const p of paths) { + const relative = path.relative('dist-npm/dist-pre', p) + const target = path.resolve('dist-npm/dist', relative) + fs.copyFileSync(p, target) + } + // rm dist-pre + fs.rmSync('dist-npm/dist-pre', { recursive: true }) + fs.copyFileSync(path.resolve(__dirname, '../README.NPM.MD'), path.resolve(__dirname, '../dist-npm/README.md')) + + if (version !== '0.0.0-dev') { + execSync('npm publish', { cwd: path.resolve(__dirname, '../dist-npm') }) + } +}) diff --git a/src/botUtils.test.ts b/src/botUtils.test.ts index 91531138..99aa07b4 100644 --- a/src/botUtils.test.ts +++ b/src/botUtils.test.ts @@ -2,8 +2,8 @@ import { test, expect } from 'vitest' import mcData from 'minecraft-data' import { formatMessage } from './botUtils' -globalThis.window ??= {} as any -globalThis.window.loadedData ??= mcData('1.20.1') +//@ts-expect-error +globalThis.loadedData ??= mcData('1.20.1') const mapIncludeDefined = (props) => { return (x) => { diff --git a/src/botUtils.ts b/src/botUtils.ts index a76f889b..fb4000a1 100644 --- a/src/botUtils.ts +++ b/src/botUtils.ts @@ -1,6 +1,7 @@ // this should actually be moved to mineflayer / prismarine-viewer import { fromFormattedString, TextComponent } from '@xmcl/text-component' +import type { IndexedData } from 'minecraft-data' export type MessageFormatPart = Pick & { text: string @@ -26,8 +27,10 @@ type MessageInput = { json?: any } -// todo move to sign-renderer, replace with prismarine-chat -export const formatMessage = (message: MessageInput) => { +const global = globalThis as any + +// todo move to sign-renderer, replace with prismarine-chat, fix mcData issue! +export const formatMessage = (message: MessageInput, mcData: IndexedData = global.loadedData) => { let msglist: MessageFormatPart[] = [] const readMsg = (msg: MessageInput) => { @@ -47,7 +50,7 @@ export const formatMessage = (message: MessageInput) => { ...styles }) } else if (msg.translate) { - const tText = window.loadedData.language[msg.translate] ?? msg.translate + const tText = mcData?.language[msg.translate] ?? msg.translate if (msg.with) { const splitted = tText.split(/%s|%\d+\$s/g) @@ -114,6 +117,6 @@ const blockToItemRemaps = { } export const getItemFromBlock = (block: import('prismarine-block').Block) => { - const item = loadedData.itemsByName[blockToItemRemaps[block.name] ?? block.name] + const item = global.mcData.itemsByName[blockToItemRemaps[block.name] ?? block.name] return item } diff --git a/src/controls.ts b/src/controls.ts index 26405082..f5e18ae7 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -10,7 +10,7 @@ import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCur import { goFullscreen, pointerLock, reloadChunks } from './utils' import { options } from './optionsStorage' import { openPlayerInventory } from './inventoryWindows' -import { chatInputValueGlobal } from './react/ChatContainer' +import { chatInputValueGlobal } from './react/Chat' import { fsState } from './loadSave' import { showOptionsModal } from './react/SelectOption' import widgets from './react/widgets' diff --git a/src/entities.ts b/src/entities.ts index 3e075f71..dbb59bed 100644 --- a/src/entities.ts +++ b/src/entities.ts @@ -58,7 +58,11 @@ customEvents.on('gameLoaded', () => { } } + let lastCall = 0 bot.on('physicsTick', () => { + // throttle, tps: 6 + if (Date.now() - lastCall < 166) return + lastCall = Date.now() for (const [id, { tracking, info }] of Object.entries(bot.tracker.trackingData)) { if (!tracking) continue const e = bot.entities[id] diff --git a/src/flyingSquidEvents.ts b/src/flyingSquidEvents.ts index fbab268b..fb5b00e3 100644 --- a/src/flyingSquidEvents.ts +++ b/src/flyingSquidEvents.ts @@ -1,5 +1,5 @@ import { showModal } from './globalState' -import { chatInputValueGlobal } from './react/ChatContainer' +import { chatInputValueGlobal } from './react/Chat' import { showNotification } from './react/NotificationProvider' export default () => { diff --git a/src/globals.d.ts b/src/globals.d.ts index 7d2a478c..6a38a21d 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -30,46 +30,4 @@ declare interface Document { exitPointerLock?(): void } -declare namespace JSX { - interface IntrinsicElements { - [elemName: string]: any - } -} - -declare interface Window extends Record {} - -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 -} - -declare module '*.module.css' { - const css: Record - export default css -} -declare module '*.css' { - const css: string - export default css -} -declare module '*.json' { - const json: any - export = json -} -declare module '*.png' { - const png: string - export default png -} - -interface PromiseConstructor { - withResolvers (): { - resolve: (value: T) => void; - reject: (reason: any) => void; - promise: Promise; - } -} +declare interface Window extends Record { } diff --git a/src/react/AppStatusProvider.tsx b/src/react/AppStatusProvider.tsx index 52c95383..6ae39308 100644 --- a/src/react/AppStatusProvider.tsx +++ b/src/react/AppStatusProvider.tsx @@ -6,7 +6,8 @@ import { fsState } from '../loadSave' import { guessProblem } from '../guessProblem' import AppStatus from './AppStatus' import DiveTransition from './DiveTransition' -import { useDidUpdateEffect, useIsModalActive } from './utils' +import { useDidUpdateEffect } from './utils' +import { useIsModalActive } from './utilsApp' import Button from './Button' const initialState = { diff --git a/src/react/ArmorBar.css b/src/react/ArmorBar.css index ae13935e..ca579a72 100644 --- a/src/react/ArmorBar.css +++ b/src/react/ArmorBar.css @@ -9,6 +9,7 @@ --bg-x: calc(-1 * 16px); --bg-y: calc(-1 * 9px); pointer-events: none; + image-rendering: pixelated; } .armor { diff --git a/src/react/ArmorBar.tsx b/src/react/ArmorBar.tsx index cc9c66cd..777f753d 100644 --- a/src/react/ArmorBar.tsx +++ b/src/react/ArmorBar.tsx @@ -40,7 +40,7 @@ export default ( { Array.from({ length: 10 }, () => 0) .map( - (num, index) =>
) @@ -48,5 +48,3 @@ export default (
} - - diff --git a/src/react/BarsCommon.tsx b/src/react/BarsCommon.tsx new file mode 100644 index 00000000..1ddc89cc --- /dev/null +++ b/src/react/BarsCommon.tsx @@ -0,0 +1,26 @@ +const getEffectClass = (effect) => { + switch (effect.id) { + case 19: + return 'poisoned' + case 20: + return 'withered' + case 22: + return 'absorption' + default: + return '' + } +} + +export const barEffectAdded = (htmlElement, effect) => { + const effectClass = getEffectClass(effect) + if (effectClass) { + htmlElement.classList.add(effectClass) + } +} + +export const barEffectEnded = (htmlElement, effect) => { + const effectClass = getEffectClass(effect) + if (effectClass) { + htmlElement.classList.remove(effectClass) + } +} diff --git a/src/react/BossBarOverlay.css b/src/react/BossBarOverlay.css index fdbeb594..95ce44ec 100644 --- a/src/react/BossBarOverlay.css +++ b/src/react/BossBarOverlay.css @@ -18,7 +18,7 @@ color: #fff; } .bossbar { - background-image: url("textures/1.18.1/gui/bars.png"); + background-image: url("minecraft-assets/minecraft-assets/data/1.18.1/gui/bars.png"); width: 182px; height: 5px; position: relative; @@ -30,5 +30,5 @@ left: 0; height: 5px; width: 0; - background-image: url("textures/1.18.1/gui/bars.png"); + background-image: url("minecraft-assets/minecraft-assets/data/1.18.1/gui/bars.png"); } diff --git a/src/react/BreathBar.css b/src/react/BreathBar.css index a7e38c7c..e98cf7c2 100644 --- a/src/react/BreathBar.css +++ b/src/react/BreathBar.css @@ -10,6 +10,7 @@ --bg-x: calc(-1 * 16px); --bg-y: calc(-1 * 18px); pointer-events: none; + image-rendering: pixelated; } .breath { diff --git a/src/react/Button.stories.tsx b/src/react/Button.stories.tsx new file mode 100644 index 00000000..88ad0074 --- /dev/null +++ b/src/react/Button.stories.tsx @@ -0,0 +1,18 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import Button from './Button' + +const meta: Meta = { + component: Button, +} + +export default meta +type Story = StoryObj; + +export const Primary: Story = { + args: { + label: 'Hello!', + icon: 'pixelarticons:lock-open', + inScreen: false, + }, +} diff --git a/src/react/Button.tsx b/src/react/Button.tsx index db7e575a..20dc0801 100644 --- a/src/react/Button.tsx +++ b/src/react/Button.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames' -import { FC, Ref } from 'react' -import { loadSound, playSound } from '../basicSounds' +import { createContext, FC, Ref, useContext } from 'react' import buttonCss from './button.module.css' +import SharedHudVars from './SharedHudVars' // testing in storybook from deathscreen @@ -13,11 +13,19 @@ interface Props extends React.ComponentProps<'button'> { rootRef?: Ref } -void loadSound('button_click.mp3') +const ButtonContext = createContext({ + onClick () { }, +}) + +export const ButtonProvider: FC<{children, onClick}> = ({ children, onClick }) => { + return {children} +} export default (({ label, icon, children, inScreen, rootRef, type = 'button', ...args }) => { + const ctx = useContext(ButtonContext) + const onClick = (e) => { - void playSound('button_click.mp3') + ctx.onClick() args.onClick?.(e) } if (inScreen) { @@ -29,9 +37,11 @@ export default (({ label, icon, children, inScreen, rootRef, type = 'button', .. args.style.width = 20 } - return + return + + }) satisfies FC diff --git a/src/react/ButtonAppProvider.tsx b/src/react/ButtonAppProvider.tsx new file mode 100644 index 00000000..206b52a2 --- /dev/null +++ b/src/react/ButtonAppProvider.tsx @@ -0,0 +1,10 @@ +import { loadSound, playSound } from '../basicSounds' +import { ButtonProvider } from './Button' + +void loadSound('button_click.mp3') + +export default ({ children }) => { + return { + void playSound('button_click.mp3') + }}>{children} +} diff --git a/src/react/ChatContainer.css b/src/react/Chat.css similarity index 100% rename from src/react/ChatContainer.css rename to src/react/Chat.css diff --git a/src/react/Chat.stories.tsx b/src/react/Chat.stories.tsx index c568f23b..901368d5 100644 --- a/src/react/Chat.stories.tsx +++ b/src/react/Chat.stories.tsx @@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react' import { useEffect, useState } from 'react' import { formatMessage } from '../botUtils' -import Chat, { fadeMessage, chatInputValueGlobal } from './ChatContainer' +import Chat, { fadeMessage, chatInputValueGlobal } from './Chat' import Button from './Button' window.spamMessage = window.spamMessage ?? '' diff --git a/src/react/ChatContainer.tsx b/src/react/Chat.tsx similarity index 99% rename from src/react/ChatContainer.tsx rename to src/react/Chat.tsx index 86a3641a..b05f9930 100644 --- a/src/react/ChatContainer.tsx +++ b/src/react/Chat.tsx @@ -3,9 +3,8 @@ import { useEffect, useMemo, useRef, useState } from 'react' import { isCypress } from '../standaloneUtils' import { MessageFormatPart } from '../botUtils' import { MessagePart } from './MessageFormatted' -import './ChatContainer.css' -import { isIos } from './utils' -import { reactKeyForMessage } from './Scoreboard' +import './Chat.css' +import { isIos, reactKeyForMessage } from './utils' export type Message = { parts: MessageFormatPart[], diff --git a/src/react/ChatProvider.tsx b/src/react/ChatProvider.tsx index 1a4d88b6..0322c60f 100644 --- a/src/react/ChatProvider.tsx +++ b/src/react/ChatProvider.tsx @@ -4,8 +4,8 @@ import { formatMessage } from '../botUtils' import { getBuiltinCommandsList, tryHandleBuiltinCommand } from '../builtinCommands' import { hideCurrentModal, miscUiState } from '../globalState' import { options } from '../optionsStorage' -import ChatContainer, { Message, fadeMessage } from './ChatContainer' -import { useIsModalActive } from './utils' +import Chat, { Message, fadeMessage } from './Chat' +import { useIsModalActive } from './utilsApp' import { hideNotification, showNotification } from './NotificationProvider' import { updateLoadedServerData } from './ServersListProvider' @@ -37,7 +37,7 @@ export default () => { }) }, []) - return { diff --git a/src/react/DeathScreenProvider.tsx b/src/react/DeathScreenProvider.tsx index 930ed070..4e68dbec 100644 --- a/src/react/DeathScreenProvider.tsx +++ b/src/react/DeathScreenProvider.tsx @@ -5,7 +5,7 @@ import { MessageFormatPart, formatMessage } from '../botUtils' import { showModal, hideModal } from '../globalState' import { options } from '../optionsStorage' import DeathScreen from './DeathScreen' -import { useIsModalActive } from './utils' +import { useIsModalActive } from './utilsApp' const dieReasonProxy = proxy({ value: null as MessageFormatPart[] | null }) diff --git a/src/react/diveAnimation.module.css b/src/react/DiveTransition.module.css similarity index 100% rename from src/react/diveAnimation.module.css rename to src/react/DiveTransition.module.css diff --git a/src/react/Dive.stories.tsx b/src/react/DiveTransition.stories.tsx similarity index 100% rename from src/react/Dive.stories.tsx rename to src/react/DiveTransition.stories.tsx diff --git a/src/react/DiveTransition.tsx b/src/react/DiveTransition.tsx index a3188305..cd78dd66 100644 --- a/src/react/DiveTransition.tsx +++ b/src/react/DiveTransition.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react' import { Transition } from 'react-transition-group' -import styles from './diveAnimation.module.css' +import styles from './DiveTransition.module.css' // dive animation from framework7 diff --git a/src/react/EnterFullscreenButton.tsx b/src/react/EnterFullscreenButton.tsx index 12c47f40..ad78ddad 100644 --- a/src/react/EnterFullscreenButton.tsx +++ b/src/react/EnterFullscreenButton.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react' import Button from './Button' -import { useUsingTouch } from './utils' +import { useUsingTouch } from './utilsApp' export default () => { const [fullScreen, setFullScreen] = useState(false) diff --git a/src/react/FoodBar.css b/src/react/FoodBar.css index bd31e818..ca3629cd 100644 --- a/src/react/FoodBar.css +++ b/src/react/FoodBar.css @@ -12,6 +12,7 @@ --bg-x: calc(-1 * (16px + 9px * var(--lightened))); --bg-y: calc(-1 * 27px); pointer-events: none; + image-rendering: pixelated; } .foodbar.poisoned { diff --git a/src/react/FoodBar.stories.tsx b/src/react/FoodBar.stories.tsx new file mode 100644 index 00000000..abf351e3 --- /dev/null +++ b/src/react/FoodBar.stories.tsx @@ -0,0 +1,19 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import FoodBar from './FoodBar' + +const meta: Meta = { + component: FoodBar +} + +export default meta +type Story = StoryObj; + +export const Primary: Story = { + args: { + gameMode: 'survival', + food: 10, + effectToAdd: 19, + effectToRemove: 20, + } +} diff --git a/src/react/FoodBar.tsx b/src/react/FoodBar.tsx index c7680b68..d4141e45 100644 --- a/src/react/FoodBar.tsx +++ b/src/react/FoodBar.tsx @@ -1,15 +1,16 @@ import { useRef, useState, useEffect } from 'react' import SharedHudVars from './SharedHudVars' import './FoodBar.css' +import { barEffectAdded, barEffectEnded } from './BarsCommon' export type FoodBarProps = { - gameMode: string, + gameMode?: string, food: number, - effectToAdd: number | null, - effectToRemove: number | null, - effectAdded: (htmlElement: HTMLDivElement | null, effect: number | null) => void, - effectEnded: (htmlElement: HTMLDivElement | null, effect: number | null) => void, + effectToAdd?: number | null, + effectToRemove?: number | null, + resetEffects?: () => void, + style?: React.CSSProperties } export default ( @@ -18,8 +19,8 @@ export default ( food, effectToAdd, effectToRemove, - effectAdded, - effectEnded + resetEffects, + style }: FoodBarProps) => { const foodRef = useRef(null) @@ -54,15 +55,17 @@ export default ( }, [food]) useEffect(() => { - effectAdded(foodRef.current, effectToAdd) - }, [effectToAdd]) + if (effectToAdd) { + barEffectAdded(foodRef.current, effectToAdd) + } + if (effectToRemove) { + barEffectEnded(foodRef.current, effectToRemove) + } + resetEffects?.() + }, [effectToAdd, effectToRemove]) - useEffect(() => { - effectEnded(foodRef.current, effectToRemove) - }, [effectToRemove]) - - return -
+ return +
{ Array.from({ length: 10 }, () => 0) .map( diff --git a/src/react/FullScreenWidget.tsx b/src/react/FullScreenWidget.tsx index ecec1813..79869446 100644 --- a/src/react/FullScreenWidget.tsx +++ b/src/react/FullScreenWidget.tsx @@ -1,5 +1,5 @@ import Screen from './Screen' -import { useIsWidgetActive } from './utils' +import { useIsWidgetActive } from './utilsApp' export default ({ name, title, children }) => { const isWidgetActive = useIsWidgetActive(name) diff --git a/src/react/HealthBar.css b/src/react/HealthBar.css index bbf0f205..a6fefe09 100644 --- a/src/react/HealthBar.css +++ b/src/react/HealthBar.css @@ -12,6 +12,7 @@ --bg-x: calc(-1 * (16px + 9px * var(--lightened))); --bg-y: calc(-1 * var(--hardcore) * 45px); pointer-events: none; + image-rendering: pixelated; } .health.creative { diff --git a/src/react/HealthBar.stories.tsx b/src/react/HealthBar.stories.tsx index bcec2e0a..69e84429 100644 --- a/src/react/HealthBar.stories.tsx +++ b/src/react/HealthBar.stories.tsx @@ -9,19 +9,6 @@ const meta: Meta = { export default meta type Story = StoryObj; -const getEffectClass = (effect) => { - switch (effect.id) { - case 19: - return 'poisoned' - case 20: - return 'withered' - case 22: - return 'absorption' - default: - return '' - } -} - export const Primary: Story = { args: { gameMode: 'survival', @@ -30,16 +17,5 @@ export const Primary: Story = { healthValue: 10, effectToAdd: 19, effectToRemove: 20, - effectAdded (htmlElement, effect) { - const effectClass = getEffectClass(effect) - if (!effectClass) return - if (htmlElement) htmlElement.classList.add(effectClass) - }, - effectEnded (htmlElement, effect) { - const effectClass = getEffectClass(effect) - if (!effectClass) return - if (htmlElement) htmlElement.classList.remove(effectClass) - } - } } diff --git a/src/react/HealthBar.tsx b/src/react/HealthBar.tsx index 46ed8a34..14e27fe6 100644 --- a/src/react/HealthBar.tsx +++ b/src/react/HealthBar.tsx @@ -1,41 +1,36 @@ -import { useRef, useState, useEffect } from 'react' +import { useRef, useEffect } from 'react' import SharedHudVars from './SharedHudVars' import './HealthBar.css' +import { barEffectAdded, barEffectEnded } from './BarsCommon' export type HealthBarProps = { - gameMode: string, + gameMode?: string, isHardcore: boolean, damaged: boolean, healthValue: number, - effectToAdd: number | null, - effectToRemove: number | null, - effectAdded: (htmlElement: HTMLDivElement | null, effect: number | null) => void, - effectEnded: (htmlElement: HTMLDivElement | null, effect: number | null) => void, + effectToAdd?: number | null, + effectToRemove?: number | null, + resetEffects?: () => void + style?: React.CSSProperties } export default ( { - gameMode, - isHardcore, - damaged, - healthValue, + gameMode, + isHardcore, + damaged, + healthValue, effectToAdd, effectToRemove, - effectAdded, - effectEnded + resetEffects, + style }: HealthBarProps) => { const healthRef = useRef(null) - const [className, setClassName] = useState('') useEffect(() => { if (healthRef.current) { healthRef.current.classList.toggle('creative', gameMode === 'creative' || gameMode === 'spectator') - // if (gameMode === 'creative' || gameMode === 'spectator') { - // healthRef.current.classList.add('creative') - // } else { - // healthRef.current.classList.remove('creative') - // } } }, [gameMode]) @@ -89,24 +84,24 @@ export default ( }, [healthValue]) useEffect(() => { - effectAdded(healthRef.current, effectToAdd) - }, [effectToAdd]) - - useEffect(() => { - effectEnded(healthRef.current, effectToRemove) - }, [effectToRemove]) + if (effectToAdd) { + barEffectAdded(healthRef.current, effectToAdd) + } + if (effectToRemove) { + barEffectEnded(healthRef.current, effectToRemove) + } + resetEffects?.() + }, [effectToAdd, effectToRemove]) return -
+
{ Array.from({ length: 10 }, () => 0) .map( - (num, index) =>
) }
} - - diff --git a/src/react/HudBarsProvider.tsx b/src/react/HudBarsProvider.tsx index 0b0cec24..746d4819 100644 --- a/src/react/HudBarsProvider.tsx +++ b/src/react/HudBarsProvider.tsx @@ -32,22 +32,6 @@ export default () => { } } - const effectAdded = (htmlElement, effect) => { - const effectClass = getEffectClass(effect) - if (effectClass) { - htmlElement.classList.add(effectClass) - } - setEffectToAdd(null) - } - - const effectEnded = (htmlElement, effect) => { - const effectClass = getEffectClass(effect) - if (effectClass) { - htmlElement.classList.remove(effectClass) - } - setEffectToRemove(null) - } - const onDamage = () => { setDamaged(prev => true) if (hurtTimeout.current) clearTimeout(hurtTimeout.current) @@ -114,8 +98,10 @@ export default () => { healthValue={healthValue} effectToAdd={effectToAdd} effectToRemove={effectToRemove} - effectAdded={effectAdded} - effectEnded={effectEnded} + resetEffects={() => { + setEffectToAdd(null) + setEffectToRemove(null) + }} /> { food={food} effectToAdd={effectToAdd} effectToRemove={effectToRemove} - effectAdded={effectAdded} - effectEnded={effectEnded} + resetEffects={() => { + setEffectToAdd(null) + setEffectToRemove(null) + }} /> { rootStyles?: React.CSSProperties @@ -10,11 +10,10 @@ interface Props extends React.ComponentProps<'input'> { export default ({ autoFocus, rootStyles, inputRef, ...inputProps }: Props) => { const ref = useRef(null!) - const isTouch = useUsingTouch() useEffect(() => { if (inputRef) (inputRef as any).current = ref.current - if (!autoFocus || isTouch) return // Don't make screen keyboard popup on mobile + if (!autoFocus || isMobile()) return // Don't make screen keyboard popup on mobile ref.current.focus() }, []) diff --git a/src/react/MessageFormatted.tsx b/src/react/MessageFormatted.tsx index baab8171..6b9620ca 100644 --- a/src/react/MessageFormatted.tsx +++ b/src/react/MessageFormatted.tsx @@ -4,7 +4,7 @@ import { noCase } from 'change-case' import mojangson from 'mojangson' import { openURL } from 'prismarine-viewer/viewer/lib/simpleUtils' import { MessageFormatPart } from '../botUtils' -import { chatInputValueGlobal } from './ChatContainer' +import { chatInputValueGlobal } from './Chat' import './MessageFormatted.css' const hoverItemToText = (hoverEvent: MessageFormatPart['hoverEvent']) => { diff --git a/src/react/PauseScreen.tsx b/src/react/PauseScreen.tsx index 92e6c8c7..a224f9e6 100644 --- a/src/react/PauseScreen.tsx +++ b/src/react/PauseScreen.tsx @@ -15,7 +15,7 @@ import { disconnect } from '../flyingSquidUtils' import { pointerLock, setLoadingScreenStatus } from '../utils' import { closeWan, openToWanAndCopyJoinLink, getJoinLink } from '../localServerMultiplayer' import { copyFilesAsyncWithProgress, mkdirRecursive, uniqueFileNameFromWorldName } from '../browserfs' -import { useIsModalActive } from './utils' +import { useIsModalActive } from './utilsApp' import { showOptionsModal } from './SelectOption' import Button from './Button' import Screen from './Screen' diff --git a/src/react/PixelartIcon.tsx b/src/react/PixelartIcon.tsx index a54cd40e..919b8309 100644 --- a/src/react/PixelartIcon.tsx +++ b/src/react/PixelartIcon.tsx @@ -3,5 +3,5 @@ import { CSSProperties } from 'react' // names: https://pixelarticons.com/free/ export default ({ iconName, width = undefined as undefined | number, styles = {} as CSSProperties, className = undefined }) => { if (width !== undefined) styles = { width, height: width, ...styles } - return + return } diff --git a/src/react/PlayerListOverlay.css b/src/react/PlayerListOverlay.css index b36801c0..aa141181 100644 --- a/src/react/PlayerListOverlay.css +++ b/src/react/PlayerListOverlay.css @@ -3,8 +3,9 @@ position: absolute; background-color: rgba(0, 0, 0, 0.3); top: 9px; - left: 50%; - transform: translate(-50%); + left: 0; + right: 0; + margin: auto; width: fit-content; padding: 1px; display: flex; diff --git a/src/react/PlayerListOverlay.stories.tsx b/src/react/PlayerListOverlay.stories.tsx index cb2d972f..0353e32e 100644 --- a/src/react/PlayerListOverlay.stories.tsx +++ b/src/react/PlayerListOverlay.stories.tsx @@ -11,8 +11,14 @@ type Story = StoryObj; export const Primary: Story = { args: { - playersLists: [], - clientId: '', + playersLists: [ + [ + { username: 'Player 1', ping: 10, uuid: '1' }, + { username: 'Player 2', ping: 20, uuid: '2' }, + { username: 'Player 3', ping: 30, uuid: '3' }, + ] + ], + clientId: '2', tablistHeader: 'Header', tablistFooter: 'Footer', serverIP: '95.163.228.101', diff --git a/src/react/PlayerListOverlay.tsx b/src/react/PlayerListOverlay.tsx index ee43ae2c..a1479c14 100644 --- a/src/react/PlayerListOverlay.tsx +++ b/src/react/PlayerListOverlay.tsx @@ -2,7 +2,7 @@ import MessageFormattedString from './MessageFormattedString' import './PlayerListOverlay.css' -type PlayersLists = Array> +type PlayersLists = Array>> type PlayerListOverlayProps = { playersLists: PlayersLists, @@ -10,11 +10,12 @@ type PlayerListOverlayProps = { tablistHeader: string | Record | null, tablistFooter: string | Record | null, serverIP: string + style?: React.CSSProperties } -export default ({ playersLists, clientId, tablistHeader, tablistFooter, serverIP }: PlayerListOverlayProps) => { +export default ({ playersLists, clientId, tablistHeader, tablistFooter, serverIP, style }: PlayerListOverlayProps) => { - return
+ return
Server IP: {serverIP}
@@ -23,7 +24,7 @@ export default ({ playersLists, clientId, tablistHeader, tablistFooter, serverIP {playersLists.map((list, index) => (
{list.map(player => ( -
+

{player.ping}

diff --git a/src/react/Scoreboard.tsx b/src/react/Scoreboard.tsx index 546a0f58..8970f004 100644 --- a/src/react/Scoreboard.tsx +++ b/src/react/Scoreboard.tsx @@ -1,5 +1,6 @@ import './Scoreboard.css' import MessageFormattedString from './MessageFormattedString' +import { reactKeyForMessage } from './utils' export type ScoreboardItems = Array<{name: string, value: number, displayName?: any}> @@ -8,17 +9,14 @@ type ScoreboardProps = { title: string, items: ScoreboardItems, open: boolean + style?: React.CSSProperties } -export const reactKeyForMessage = (message) => { - return typeof message === 'string' ? message : JSON.stringify(message) -} - -export default function Scoreboard ({ title, items, open }: ScoreboardProps) { +export default function Scoreboard ({ title, items, open, style }: ScoreboardProps) { if (!open) return null return ( -
+
diff --git a/src/react/SelectOption.tsx b/src/react/SelectOption.tsx index b74434e1..e2879e10 100644 --- a/src/react/SelectOption.tsx +++ b/src/react/SelectOption.tsx @@ -1,7 +1,7 @@ import { proxy, useSnapshot } from 'valtio' import { hideCurrentModal, showModal } from '../globalState' import Screen from './Screen' -import { useIsModalActive } from './utils' +import { useIsModalActive } from './utilsApp' import Button from './Button' const state = proxy({ diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index ecd74916..0de15e1e 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -5,7 +5,8 @@ import { ConnectOptions } from '../connect' import { hideCurrentModal, miscUiState, showModal } from '../globalState' import ServersList from './ServersList' import AddServer from './AddServer' -import { useDidUpdateEffect, useIsModalActive } from './utils' +import { useDidUpdateEffect } from './utils' +import { useIsModalActive } from './utilsApp' interface StoreServerItem { ip: string, diff --git a/src/react/SharedHudVars.tsx b/src/react/SharedHudVars.tsx index acdcc237..ca48453a 100644 --- a/src/react/SharedHudVars.tsx +++ b/src/react/SharedHudVars.tsx @@ -1,5 +1,6 @@ import { CSSProperties, useEffect } from 'react' import icons from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/icons.png' +import widgets from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/widgets.png' export default ({ children }) => { useEffect(() => { @@ -8,7 +9,9 @@ export default ({ children }) => { // 2. Easier application to globally override icons with custom image (eg from resourcepacks) const css = /* css */` :root { + --widgets-gui-atlas: url(${widgets}); --gui-icons: url(${icons}), url(${icons}); + --safe-area-inset-bottom: calc(env(safe-area-inset-bottom) / 2); } ` const style = document.createElement('style') @@ -17,11 +20,5 @@ export default ({ children }) => { document.head.appendChild(style) }, []) - const customVars = { - '--safe-area-inset-bottom': 'calc(env(safe-area-inset-bottom) / 2)' - } as CSSProperties - - return
{children}
+ return children } diff --git a/src/react/SignEditorProvider.tsx b/src/react/SignEditorProvider.tsx index b6ade625..666935b6 100644 --- a/src/react/SignEditorProvider.tsx +++ b/src/react/SignEditorProvider.tsx @@ -2,7 +2,7 @@ import { useMemo, useEffect, useState, useRef } from 'react' import { showModal, hideModal } from '../globalState' import { setDoPreventDefault } from '../controls' import { options } from '../optionsStorage' -import { useIsModalActive } from './utils' +import { useIsModalActive } from './utilsApp' import SignEditor, { ResultType } from './SignEditor' diff --git a/src/react/SingleplayerProvider.tsx b/src/react/SingleplayerProvider.tsx index 35704e8e..83d28637 100644 --- a/src/react/SingleplayerProvider.tsx +++ b/src/react/SingleplayerProvider.tsx @@ -9,7 +9,7 @@ import { haveDirectoryPicker, setLoadingScreenStatus } from '../utils' import { exportWorld } from '../builtinCommands' import { googleProviderState, useGoogleLogIn, GoogleDriveProvider, isGoogleDriveAvailable, APP_ID } from '../googledrive' import Singleplayer, { WorldProps } from './Singleplayer' -import { useIsModalActive } from './utils' +import { useIsModalActive } from './utilsApp' import { showOptionsModal } from './SelectOption' import Input from './Input' import GoogleButton from './GoogleButton' diff --git a/src/react/Slider.tsx b/src/react/Slider.tsx index bc6c5890..34cc2717 100644 --- a/src/react/Slider.tsx +++ b/src/react/Slider.tsx @@ -1,6 +1,7 @@ // Slider.tsx import React, { useState, useEffect } from 'react' import styles from './slider.module.css' +import SharedHudVars from './SharedHudVars' interface Props extends React.ComponentProps<'div'> { label: string; @@ -47,36 +48,38 @@ const Slider: React.FC = ({ } return ( -
- { - const newValue = Number(e.target.value) - setValue(newValue) - fireValueUpdate(false, newValue) - }} - // todo improve correct handling of drag end - onLostPointerCapture={() => { - fireValueUpdate(true) - }} - onPointerUp={() => { - fireValueUpdate(true) - }} - onKeyUp={() => { - fireValueUpdate(true) - }} - /> -
-
- -
+ +
+ { + const newValue = Number(e.target.value) + setValue(newValue) + fireValueUpdate(false, newValue) + }} + // todo improve correct handling of drag end + onLostPointerCapture={() => { + fireValueUpdate(true) + }} + onPointerUp={() => { + fireValueUpdate(true) + }} + onKeyUp={() => { + fireValueUpdate(true) + }} + /> +
+
+ +
+
) } diff --git a/src/react/SoundMuffler.tsx b/src/react/SoundMuffler.tsx index 869abc1c..ecbae14d 100644 --- a/src/react/SoundMuffler.tsx +++ b/src/react/SoundMuffler.tsx @@ -5,7 +5,7 @@ import { lastPlayedSounds } from '../soundSystem' import { options } from '../optionsStorage' import Button from './Button' import Screen from './Screen' -import { useIsModalActive } from './utils' +import { useIsModalActive } from './utilsApp' const SoundRow = ({ sound, children }) => { const { mutedSounds } = useSnapshot(options) diff --git a/src/react/TouchAreasControlsProvider.tsx b/src/react/TouchAreasControlsProvider.tsx index 7de8eaca..24479e89 100644 --- a/src/react/TouchAreasControlsProvider.tsx +++ b/src/react/TouchAreasControlsProvider.tsx @@ -2,7 +2,7 @@ import { useSnapshot } from 'valtio' import { activeModalStack, hideModal } from '../globalState' import { options } from '../optionsStorage' import TouchAreasControls from './TouchAreasControls' -import { useIsModalActive, useUsingTouch } from './utils' +import { useIsModalActive, useUsingTouch } from './utilsApp' export default () => { const usingTouch = useUsingTouch() diff --git a/src/react/TouchControls.tsx b/src/react/TouchControls.tsx index db71ae1f..b49d57c4 100644 --- a/src/react/TouchControls.tsx +++ b/src/react/TouchControls.tsx @@ -4,7 +4,7 @@ import { useSnapshot } from 'valtio' import { contro } from '../controls' import { miscUiState, activeModalStack } from '../globalState' import { watchValue, options } from '../optionsStorage' -import { useUsingTouch } from './utils' +import { useUsingTouch } from './utilsApp' // todo useInterfaceState.setState({ diff --git a/src/react/globals.d.ts b/src/react/globals.d.ts new file mode 100644 index 00000000..842d27c4 --- /dev/null +++ b/src/react/globals.d.ts @@ -0,0 +1,45 @@ +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 +} + +declare module '*.module.css' { + const css: Record + export default css +} +declare module '*.css' { + const css: string + export default css +} +declare module '*.json' { + const json: any + export = json +} +declare module '*.png' { + const png: string + export default png +} + +interface PromiseConstructor { + withResolvers (): { + resolve: (value: T) => void; + reject: (reason: any) => void; + promise: Promise; + } +} + +declare namespace JSX { + interface IntrinsicElements { + 'iconify-icon': { + icon: string + style?: React.CSSProperties + class?: string + } + } +} diff --git a/src/react/npmReactEntrypoint.ts b/src/react/npmReactEntrypoint.ts new file mode 100644 index 00000000..643930d7 --- /dev/null +++ b/src/react/npmReactEntrypoint.ts @@ -0,0 +1 @@ +// export * from './npmReactComponents' diff --git a/src/react/utils.ts b/src/react/utils.ts index 900b279f..b8caeddf 100644 --- a/src/react/utils.ts +++ b/src/react/utils.ts @@ -1,16 +1,5 @@ -import { useSnapshot } from 'valtio' import { useEffect, useRef } from 'react' import { UAParser } from 'ua-parser-js' -import { activeModalStack, miscUiState } from '../globalState' - -export const useIsModalActive = (modal: string, useIncludes = false) => { - const allStack = useSnapshot(activeModalStack) - return useIncludes ? allStack.some(x => x.reactType === modal) : allStack.at(-1)?.reactType === modal -} - -export const useIsWidgetActive = (name: string) => { - return useIsModalActive(`widget-${name}`) -} export function useDidUpdateEffect (fn, inputs) { const isMountingRef = useRef(false) @@ -28,10 +17,10 @@ export function useDidUpdateEffect (fn, inputs) { }, inputs) } -export const useUsingTouch = () => { - return useSnapshot(miscUiState).currentTouch -} - export const ua = new UAParser(navigator.userAgent) export const isIos = ua.getOS().name === 'iOS' + +export const reactKeyForMessage = (message) => { + return typeof message === 'string' ? message : JSON.stringify(message) +} diff --git a/src/react/utilsApp.ts b/src/react/utilsApp.ts new file mode 100644 index 00000000..3fd18515 --- /dev/null +++ b/src/react/utilsApp.ts @@ -0,0 +1,15 @@ +import { useSnapshot } from 'valtio' +import { activeModalStack, miscUiState } from '../globalState' + + +export const useUsingTouch = () => { + return useSnapshot(miscUiState).currentTouch +} +export const useIsModalActive = (modal: string, useIncludes = false) => { + const allStack = useSnapshot(activeModalStack) + return useIncludes ? allStack.some(x => x.reactType === modal) : allStack.at(-1)?.reactType === modal +} + +export const useIsWidgetActive = (name: string) => { + return useIsModalActive(`widget-${name}`) +} diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 419d8dff..760a1a7b 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -27,12 +27,13 @@ import PauseScreen from './react/PauseScreen' import SoundMuffler from './react/SoundMuffler' import TouchControls from './react/TouchControls' import widgets from './react/widgets' -import { useIsWidgetActive } from './react/utils' +import { useIsWidgetActive } from './react/utilsApp' import GlobalSearchInput from './GlobalSearchInput' import TouchAreasControlsProvider from './react/TouchAreasControlsProvider' import NotificationProvider, { showNotification } from './react/NotificationProvider' import HotbarRenderApp from './react/HotbarRenderApp' import Crosshair from './react/Crosshair' +import ButtonAppProvider from './react/ButtonAppProvider' import ServersListProvider from './react/ServersListProvider' const RobustPortal = ({ children, to }) => { @@ -112,7 +113,7 @@ const InGameUi = () => { - {/* becaues of z-index */} + {/* because of z-index */} @@ -132,21 +133,23 @@ const WidgetDisplay = ({ name, Component }) => { const App = () => { return
- - - - - - - - - - - - - {/* - */} - + + + + + + + + + + + + + + {/* + */} + +
} diff --git a/src/styles.css b/src/styles.css index 64fc054d..30abc52b 100644 --- a/src/styles.css +++ b/src/styles.css @@ -26,7 +26,6 @@ html { } body { - --widgets-gui-atlas: url('minecraft-assets/minecraft-assets/data/1.17.1/gui/widgets.png'); --title-gui: url('minecraft-assets/minecraft-assets/data/1.17.1/gui/title/minecraft.png'); } diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 544027a5..c3263f2f 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -89,6 +89,8 @@ class WorldInteraction { if (entity && e.button === 2) { bot.attack(entity) + } else { + // bot } }) document.addEventListener('blur', (e) => { diff --git a/tsconfig.npm.json b/tsconfig.npm.json new file mode 100644 index 00000000..0aec498f --- /dev/null +++ b/tsconfig.npm.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "dist-npm/dist-pre", + "noEmit": false, + "declaration": true + }, + "include": [ + "src/react/npmReactComponents.ts", + "src/react/globals.d.ts" + ] +} From 86554050c372904af9d2616bfeaa41ab5a4982f6 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Sun, 5 May 2024 03:26:56 +0300 Subject: [PATCH 0062/1097] up tested ver --- src/loadSave.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/loadSave.ts b/src/loadSave.ts index c332e670..af9d078c 100644 --- a/src/loadSave.ts +++ b/src/loadSave.ts @@ -91,12 +91,13 @@ export const loadSave = async (root = '/world') => { const newVersion = '1.8.8' version = newVersion } - const lastSupportedVersion = supportedVersions.at(-1)! + // const lastSupportedVersion = supportedVersions.at(-1)! + const lastTestedVersion = '1.18.2' const firstSupportedVersion = supportedVersions[0] const lowerBound = isMajorVersionGreater(firstSupportedVersion, version) - const upperBound = isMajorVersionGreater(version, lastSupportedVersion) + const upperBound = isMajorVersionGreater(version, lastTestedVersion) if (lowerBound || upperBound) { - version = prompt(`Version ${version} is not supported, supported versions are ${supportedVersions.join(', ')}, what try to use instead?`, lowerBound ? firstSupportedVersion : lastSupportedVersion) + version = prompt(`Version ${version} is not supported, supported versions are ${supportedVersions.join(', ')}, what try to use instead?`, lowerBound ? firstSupportedVersion : lastTestedVersion) if (!version) return } if (levelDat.WorldGenSettings) { From 038dfc415be3fd4b657e804d5299d2a6acd97adc Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 5 May 2024 03:34:46 +0300 Subject: [PATCH 0063/1097] ci: remove wrong command --- .github/workflows/publish.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 79bc5ffd..616a241a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -33,10 +33,6 @@ jobs: pnpx zardoy-release node --footer "This release URL: ${{ steps.deploy.outputs.stdout }}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: | - pnpx zardoy-release npm - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: cp vercel.json .vercel/output/static/vercel.json - uses: peaceiris/actions-gh-pages@v3 with: From 2e93e90d287bf19c22653804e35bf3bb80fd02e9 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 5 May 2024 03:45:57 +0300 Subject: [PATCH 0064/1097] impr auto publish for npm --- .github/workflows/publish.yml | 6 +++++- scripts/buildNpmReact.ts | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 616a241a..18c1a9bf 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -33,12 +33,16 @@ jobs: pnpx zardoy-release node --footer "This release URL: ${{ steps.deploy.outputs.stdout }}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # has possible output: tag + id: release + # has output - run: cp vercel.json .vercel/output/static/vercel.json - uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: .vercel/output/static force_orphan: true - - run: pnpm tsx scripts/buildNpmReact.ts + - run: pnpm tsx scripts/buildNpmReact.ts ${{ steps.release.outputs.tag }} + if: steps.release.outputs.tag env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/scripts/buildNpmReact.ts b/scripts/buildNpmReact.ts index 71513cb3..4516f1b7 100644 --- a/scripts/buildNpmReact.ts +++ b/scripts/buildNpmReact.ts @@ -35,7 +35,8 @@ fs.promises.readdir(path.resolve(__dirname, '../src/react')).then(async (files) const packageJsonRoot = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8')) const external = Object.keys(packageJson.peerDependencies) const dependencies = new Set() - const version = packageJsonRoot.version + let version = process.argv[2] || packageJsonRoot.version + version = version.replace(/^v/, '') packageJson.version = version const externalize = ['minecraft-assets', 'prismarine-viewer'] From 228d60056bbd22c175e2bf174d4f50d8b1c63164 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 5 May 2024 03:57:21 +0300 Subject: [PATCH 0065/1097] hotfix: offline server check crashes other servers checks --- src/react/ServersListProvider.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index 0de15e1e..85c55ed6 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -22,7 +22,8 @@ interface StoreServerItem { } type ServerResponse = { - version: { + online: boolean + version?: { name_raw: string } // display tooltip @@ -34,8 +35,8 @@ type ServerResponse = { name_clean: string }> } - icon: string - motd: { + icon?: string + motd?: { raw: string } // todo circle error icon @@ -159,12 +160,13 @@ const Inner = () => { if (isInLocalNetwork) continue // eslint-disable-next-line no-await-in-loop await fetch(`https://api.mcstatus.io/v2/status/java/${server.ip}`).then(async r => r.json()).then((data: ServerResponse) => { - const versionClean = data.version.name_raw.replace(/^[^\d.]+/, '') + const versionClean = data.version?.name_raw.replace(/^[^\d.]+/, '') + if (!versionClean) return setAdditionalData(old => { return ({ ...old, [server.ip]: { - formattedText: data.motd.raw, + formattedText: data.motd?.raw ?? '', textNameRight: `${versionClean} ${data.players?.online ?? '??'}/${data.players?.max ?? '??'}`, icon: data.icon, } From d1d47b334c7525c9083a2a3b39797fef368c914a Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 6 May 2024 01:04:04 +0300 Subject: [PATCH 0066/1097] fix camera desync issues --- prismarine-viewer/viewer/lib/viewer.ts | 8 +++++++- prismarine-viewer/viewer/lib/worldrendererCommon.ts | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts index 9cb7eb3d..9f8067db 100644 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ b/prismarine-viewer/viewer/lib/viewer.ts @@ -12,7 +12,6 @@ export class Viewer { scene: THREE.Scene ambientLight: THREE.AmbientLight directionalLight: THREE.DirectionalLight - camera: THREE.PerspectiveCamera world: WorldRendererCommon entities: Entities // primitives: Primitives @@ -25,6 +24,13 @@ export class Viewer { renderingUntilNoUpdates = false processEntityOverrides = (e, overrides) => overrides + get camera () { + return this.world.camera + } + set camera (camera) { + this.world.camera = camera + } + constructor(public renderer: THREE.WebGLRenderer, worldConfig = defaultWorldRendererConfig) { // https://discourse.threejs.org/t/updates-to-color-management-in-three-js-r152/50791 THREE.ColorManagement.enabled = false diff --git a/prismarine-viewer/viewer/lib/worldrendererCommon.ts b/prismarine-viewer/viewer/lib/worldrendererCommon.ts index 43983977..05fb6f4e 100644 --- a/prismarine-viewer/viewer/lib/worldrendererCommon.ts +++ b/prismarine-viewer/viewer/lib/worldrendererCommon.ts @@ -54,6 +54,7 @@ export abstract class WorldRendererCommon allChunksFinished = false handleResize = () => { } mesherConfig = defaultMesherConfig + camera: THREE.PerspectiveCamera abstract outputFormat: 'threeJs' | 'webgl' From 36962331d17bdcd65951f00e6383b6eb60662c2e Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 6 May 2024 01:54:29 +0300 Subject: [PATCH 0067/1097] chore: up mc-data, fix cam reset fix: hide add server UI after adding a server --- package.json | 4 +- pnpm-lock.yaml | 60 +++++++++---------- prismarine-viewer/viewer/lib/mesher/models.ts | 4 +- .../viewer/lib/mesher/test/mesherTester.ts | 15 +++-- prismarine-viewer/viewer/lib/viewer.ts | 4 +- .../viewer/lib/worldrendererThree.ts | 2 +- src/react/ServersListProvider.tsx | 9 +-- 7 files changed, 51 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index 25a87472..fdaecb65 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "jszip": "^3.10.1", "lodash-es": "^4.17.21", "minecraft-assets": "^1.12.2", - "minecraft-data": "3.62.0", + "minecraft-data": "3.65.0", "net-browserify": "github:zardoy/prismarinejs-net-browserify", "node-gzip": "^1.1.2", "peerjs": "^1.5.0", @@ -154,7 +154,7 @@ "diamond-square": "github:zardoy/diamond-square", "prismarine-block": "github:zardoy/prismarine-block#next-era", "prismarine-world": "github:zardoy/prismarine-world#next-era", - "minecraft-data": "3.62.0", + "minecraft-data": "3.65.0", "prismarine-provider-anvil": "github:zardoy/prismarine-provider-anvil#everything", "minecraft-protocol": "github:zardoy/minecraft-protocol#everything", "react": "^18.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 054539d5..21d48b30 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ overrides: diamond-square: github:zardoy/diamond-square prismarine-block: github:zardoy/prismarine-block#next-era prismarine-world: github:zardoy/prismarine-world#next-era - minecraft-data: 3.62.0 + minecraft-data: 3.65.0 prismarine-provider-anvil: github:zardoy/prismarine-provider-anvil#everything minecraft-protocol: github:zardoy/minecraft-protocol#everything react: ^18.2.0 @@ -120,8 +120,8 @@ importers: specifier: ^1.12.2 version: 1.12.2 minecraft-data: - specifier: 3.62.0 - version: 3.62.0 + specifier: 3.65.0 + version: 3.65.0 mojangson: specifier: ^2.0.4 version: 2.0.4 @@ -139,7 +139,7 @@ importers: version: 6.1.1 prismarine-provider-anvil: specifier: github:zardoy/prismarine-provider-anvil#everything - version: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.62.0) + version: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0) prosemirror-example-setup: specifier: ^1.2.2 version: 1.2.2 @@ -375,7 +375,7 @@ importers: version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-chunk: specifier: github:zardoy/prismarine-chunk - version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.62.0) + version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) prismarine-schematic: specifier: ^1.2.0 version: 1.2.3 @@ -6028,8 +6028,8 @@ packages: minecraft-assets@1.12.2: resolution: {integrity: sha512-/eMxh3LNjCXOnU6KnQMjBM8dRnoJNpWIg7mD2m2RthraYiQK2FNzPWIKxWm2j3Ufcf5nzFXupgABledE86r4fQ==} - minecraft-data@3.62.0: - resolution: {integrity: sha512-jJXZ/WgyX79tIHlqvfyqG+sJDUekHiA3e9NRUCMGUno4NDrZMcpRI065DnkrI720RHTMb8iadf0NmnBP4Rla5A==} + minecraft-data@3.65.0: + resolution: {integrity: sha512-9K8dOrdrcpUklTdqKBtRcKur0gLZnguTvhM/1Xv52qzh8Unkto4290RJc4ueRIYo1VqN4zzQrRxO8lnqtkERDQ==} minecraft-folder-path@1.2.0: resolution: {integrity: sha512-qaUSbKWoOsH9brn0JQuBhxNAzTDMwrOXorwuRxdJKKKDYvZhtml+6GVCUrY5HRiEsieBEjCUnhVpDuQiKsiFaw==} @@ -6691,7 +6691,7 @@ packages: prismarine-biome@1.3.0: resolution: {integrity: sha512-GY6nZxq93mTErT7jD7jt8YS1aPrOakbJHh39seYsJFXvueIOdHAmW16kYQVrTVMW5MlWLQVxV/EquRwOgr4MnQ==} peerDependencies: - minecraft-data: 3.62.0 + minecraft-data: 3.65.0 prismarine-registry: ^1.1.0 prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0: @@ -11923,16 +11923,16 @@ snapshots: exit-hook: 2.2.1 flatmap: 0.0.3 long: 5.2.3 - minecraft-data: 3.62.0 + minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/zardoy/minecraft-protocol/tar.gz/2c14a686bfe7cbd9a5c87b629b402295ee86219f(encoding@0.1.13) mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.62.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 - prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.62.0) + prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0) prismarine-windows: 2.9.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 rambda: 9.2.0 @@ -13194,8 +13194,8 @@ snapshots: diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687: dependencies: - minecraft-data: 3.62.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.62.0) + minecraft-data: 3.65.0 + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) random-seed: 0.3.0 vec3: 0.1.8 @@ -15659,7 +15659,7 @@ snapshots: minecraft-assets@1.12.2: {} - minecraft-data@3.62.0: {} + minecraft-data@3.65.0: {} minecraft-folder-path@1.2.0: {} @@ -15679,7 +15679,7 @@ snapshots: endian-toggle: 0.0.0 lodash.get: 4.4.2 lodash.merge: 4.6.2 - minecraft-data: 3.62.0 + minecraft-data: 3.65.0 minecraft-folder-path: 1.2.0 node-fetch: 2.7.0(encoding@0.1.13) node-rsa: 0.4.2 @@ -15719,7 +15719,7 @@ snapshots: mineflayer-pathfinder@2.4.4: dependencies: - minecraft-data: 3.62.0 + minecraft-data: 3.65.0 prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-entity: 2.3.1 prismarine-item: 1.14.0 @@ -15729,12 +15729,12 @@ snapshots: mineflayer@https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f(encoding@0.1.13): dependencies: - minecraft-data: 3.62.0 + minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/zardoy/minecraft-protocol/tar.gz/2c14a686bfe7cbd9a5c87b629b402295ee86219f(encoding@0.1.13) - prismarine-biome: 1.3.0(minecraft-data@3.62.0)(prismarine-registry@1.7.0) + prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-chat: 1.9.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.62.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -16431,15 +16431,15 @@ snapshots: - encoding - supports-color - prismarine-biome@1.3.0(minecraft-data@3.62.0)(prismarine-registry@1.7.0): + prismarine-biome@1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0): dependencies: - minecraft-data: 3.62.0 + minecraft-data: 3.65.0 prismarine-registry: 1.7.0 prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0: dependencies: - minecraft-data: 3.62.0 - prismarine-biome: 1.3.0(minecraft-data@3.62.0)(prismarine-registry@1.7.0) + minecraft-data: 3.65.0 + prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-chat: 1.9.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -16452,9 +16452,9 @@ snapshots: prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.62.0): + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0): dependencies: - prismarine-biome: 1.3.0(minecraft-data@3.62.0)(prismarine-registry@1.7.0) + prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 @@ -16487,13 +16487,13 @@ snapshots: prismarine-physics@1.8.0: dependencies: - minecraft-data: 3.62.0 + minecraft-data: 3.65.0 prismarine-nbt: 2.5.0 vec3: 0.1.8 - prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.62.0): + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0): dependencies: - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.62.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) prismarine-nbt: 2.5.0 uint4: 0.1.2 vec3: 0.1.8 @@ -16514,12 +16514,12 @@ snapshots: prismarine-registry@1.7.0: dependencies: - minecraft-data: 3.62.0 + minecraft-data: 3.65.0 prismarine-nbt: 2.5.0 prismarine-schematic@1.2.3: dependencies: - minecraft-data: 3.62.0 + minecraft-data: 3.65.0 prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-nbt: 2.2.1 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 diff --git a/prismarine-viewer/viewer/lib/mesher/models.ts b/prismarine-viewer/viewer/lib/mesher/models.ts index 833de180..bfb96d11 100644 --- a/prismarine-viewer/viewer/lib/mesher/models.ts +++ b/prismarine-viewer/viewer/lib/mesher/models.ts @@ -349,8 +349,7 @@ function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr const aos: number[] = [] const neighborPos = position.plus(new Vec3(...dir)) - let baseLightLevel = world.getLight(neighborPos) - const baseLight = baseLightLevel / 15 + const baseLight = world.getLight(neighborPos) / 15 for (const pos of corners) { let vertex = [ (pos[0] ? maxx : minx), @@ -418,6 +417,7 @@ function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr attr.tiles[`${cursor.x},${cursor.y},${cursor.z}`].faces.push({ face, neighbor: `${neighborPos.x},${neighborPos.y},${neighborPos.z}`, + light: baseLight // texture: eFace.texture.name, }) } diff --git a/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts b/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts index 21c5d129..a665db6b 100644 --- a/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts +++ b/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts @@ -1,6 +1,6 @@ import { setBlockStatesData, getSectionGeometry } from '../models' import { World as MesherWorld } from '../world' -import ChunkLoader from 'prismarine-chunk' +import ChunkLoader, { PCChunk } from 'prismarine-chunk' import { Vec3 } from 'vec3' import MinecraftData from 'minecraft-data' @@ -26,18 +26,25 @@ export const setup = (version, initialBlocks: [number[], string][]) => { return { centerFaces, totalTiles, - centerTileNeighbors + centerTileNeighbors, + faces: sectionGeometry.tiles[`${pos.x},${pos.y},${pos.z}`]?.faces ?? [] } } setBlockStatesData(blockStates, true) - mesherWorld.addColumn(0, 0, chunk1.toJson()) + const reload = () => { + mesherWorld.removeColumn(0, 0) + mesherWorld.addColumn(0, 0, chunk1.toJson()) + } + reload() return { mesherWorld, getGeometry, pos, - mcData + mcData, + reload, + chunk: chunk1 as PCChunk } } diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts index 9f8067db..65091f3e 100644 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ b/prismarine-viewer/viewer/lib/viewer.ts @@ -38,9 +38,9 @@ export class Viewer { this.scene = new THREE.Scene() this.scene.matrixAutoUpdate = false // for perf - this.resetScene() - this.threeJsWorld = new WorldRendererThree(this.scene, this.renderer, this.camera, worldConfig) + this.threeJsWorld = new WorldRendererThree(this.scene, this.renderer, worldConfig) this.setWorld() + this.resetScene() this.entities = new Entities(this.scene) // this.primitives = new Primitives(this.scene, this.camera) diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 1fff112f..a099dbbc 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -20,7 +20,7 @@ export class WorldRendererThree extends WorldRendererCommon { return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).tilesCount, 0) } - constructor(public scene: THREE.Scene, public renderer: THREE.WebGLRenderer, public camera: THREE.PerspectiveCamera, public config: WorldRendererConfig) { + constructor(public scene: THREE.Scene, public renderer: THREE.WebGLRenderer, public config: WorldRendererConfig) { super(config) } diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index 85c55ed6..5da2fc68 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -180,16 +180,13 @@ const Inner = () => { const isEditScreenModal = useIsModalActive('editServer') - useEffect(() => { - if (!isEditScreenModal) { - setServerEditScreen(null) - } - }, [isEditScreenModal]) - useEffect(() => { if (serverEditScreen && !isEditScreenModal) { showModal({ reactType: 'editServer' }) } + if (!serverEditScreen && isEditScreenModal) { + hideCurrentModal() + } }, [serverEditScreen]) if (isEditScreenModal) { From 03b3e56a74eb8c375b67209b88892bea35292378 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 6 May 2024 19:06:44 +0300 Subject: [PATCH 0068/1097] fix: reload the page on quit button until issues with time desync are fixed up squid to restore support for 1.14 worlds --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- src/flyingSquidUtils.ts | 1 + src/react/AppStatus.tsx | 2 +- src/react/PauseScreen.tsx | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index fdaecb65..acee3c83 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "esbuild": "^0.19.3", "esbuild-plugin-polyfill-node": "^0.3.0", "express": "^4.18.2", - "flying-squid": "npm:@zardoy/flying-squid@^0.0.19", + "flying-squid": "npm:@zardoy/flying-squid@^0.0.20", "fs-extra": "^11.1.1", "google-drive-browserfs": "github:zardoy/browserfs#google-drive", "iconify-icon": "^1.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 21d48b30..36cc8e30 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -99,8 +99,8 @@ importers: specifier: ^10.0.12 version: 10.0.12 flying-squid: - specifier: npm:@zardoy/flying-squid@^0.0.19 - version: '@zardoy/flying-squid@0.0.19(encoding@0.1.13)' + specifier: npm:@zardoy/flying-squid@^0.0.20 + version: '@zardoy/flying-squid@0.0.20(encoding@0.1.13)' fs-extra: specifier: ^11.1.1 version: 11.1.1 @@ -3043,8 +3043,8 @@ packages: resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==} engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'} - '@zardoy/flying-squid@0.0.19': - resolution: {integrity: sha512-q0eW/AO66bA5YQfGd+mnZjenZ7oocCrxlU4ktJbS4vfhjC2PPLzXLpWhXnzqN9A3VSzMzraV/9SY9kGQkw8xNA==} + '@zardoy/flying-squid@0.0.20': + resolution: {integrity: sha512-WyejZS2Upzv86g6Ez5Z/4Pd0ea9tkFL2itAj24UNpO7fyzxuTN2Ag1Ouvh+MSkCloXhR4E/yoER2krHW8vzwBw==} engines: {node: '>=8'} hasBin: true @@ -11913,7 +11913,7 @@ snapshots: '@types/emscripten': 1.39.8 tslib: 1.14.1 - '@zardoy/flying-squid@0.0.19(encoding@0.1.13)': + '@zardoy/flying-squid@0.0.20(encoding@0.1.13)': dependencies: change-case: 4.1.2 colors: 1.4.0 diff --git a/src/flyingSquidUtils.ts b/src/flyingSquidUtils.ts index 2590468d..bd312bfb 100644 --- a/src/flyingSquidUtils.ts +++ b/src/flyingSquidUtils.ts @@ -38,4 +38,5 @@ export const disconnect = async () => { } window.history.replaceState({}, '', `${window.location.pathname}`) // remove qs bot.end('You left the server') + location.reload() } diff --git a/src/react/AppStatus.tsx b/src/react/AppStatus.tsx index b1b98c35..9bf2ece1 100644 --- a/src/react/AppStatus.tsx +++ b/src/react/AppStatus.tsx @@ -44,7 +44,7 @@ export default ({ status, isError, hideDots = false, lastStatus = '', backAction <> {backAction && + )} diff --git a/src/react/PauseScreen.tsx b/src/react/PauseScreen.tsx index a224f9e6..0d63df5d 100644 --- a/src/react/PauseScreen.tsx +++ b/src/react/PauseScreen.tsx @@ -137,7 +137,7 @@ export default () => {
) : null}
From 3046524ff6243dbcccb43985cf11970ac02b76f6 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 8 May 2024 20:36:05 +0300 Subject: [PATCH 0069/1097] chore: fix all tests feat: add lockConnect to QS options for alt connection screen UI --- README.MD | 9 +++++---- cypress/e2e/index.spec.ts | 4 ++-- src/react/{AddServer.tsx => AddServerOrConnect.tsx} | 6 +++--- src/react/ServersList.stories.tsx | 4 ++-- src/react/ServersListProvider.tsx | 6 +++--- 5 files changed, 15 insertions(+), 14 deletions(-) rename src/react/{AddServer.tsx => AddServerOrConnect.tsx} (96%) diff --git a/README.MD b/README.MD index 1b8b84ac..bc39fb98 100644 --- a/README.MD +++ b/README.MD @@ -103,10 +103,11 @@ world chunks have a *yellow* border, hostile mobs have a *red* outline, passive Press `Y` to set query parameters to url of your current game state. -- `?server=` - Display connect screen to the server on load -- `?username=` - Set the username on load -- `?proxy=` - Set the proxy server address on load -- `?version=` - Set the version on load +- `?ip=` - Display connect screen to the server on load +- `?username=` - Set the username for server +- `?proxy=` - Set the proxy server address to use for server +- `?version=` - Set the version for server +- `?lockConnect=true` - Disable cancel / save buttons, useful for integrates iframes - `?reconnect=true` - Reconnect to the server on page reloads. Available in **dev mode only** and very useful on server testing. - `?loadSave=` - Load the save on load with the specified folder name (not title) diff --git a/cypress/e2e/index.spec.ts b/cypress/e2e/index.spec.ts index 35399393..455b1283 100644 --- a/cypress/e2e/index.spec.ts +++ b/cypress/e2e/index.spec.ts @@ -38,7 +38,7 @@ const setOptions = (options: Partial) => { } it('Loads & renders singleplayer', () => { - cleanVisit('/?singleplayer=1') + visit('/?singleplayer=1') setOptions({ localServerOptions: { generation: { @@ -52,7 +52,7 @@ it('Loads & renders singleplayer', () => { testWorldLoad() }) -it.only('Joins to server', () => { +it('Joins to server', () => { visit('/?ip=localhost&version=1.16.1') window.localStorage.version = '' // todo replace with data-test diff --git a/src/react/AddServer.tsx b/src/react/AddServerOrConnect.tsx similarity index 96% rename from src/react/AddServer.tsx rename to src/react/AddServerOrConnect.tsx index bae39ac9..54f04af1 100644 --- a/src/react/AddServer.tsx +++ b/src/react/AddServerOrConnect.tsx @@ -38,6 +38,7 @@ export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQ const [usernameOverride, setUsernameOverride] = React.useState(initialData?.usernameOverride ?? qsParams?.get('username') ?? '') const [passwordOverride, setPasswordOverride] = React.useState(initialData?.passwordOverride ?? qsParams?.get('password') ?? '') const smallWidth = useIsSmallWidth() + const lockConnect = qsParams?.get('lockConnect') === 'true' return
setProxyOverride(value)} placeholder={defaults?.proxyOverride} /> setUsernameOverride(value)} placeholder={defaults?.usernameOverride} /> setPasswordOverride(value)} /* placeholder='For advanced usage only' */ /> - - + } }>Cancel} {qsParams?.get('ip') &&
} diff --git a/src/styles.css b/src/styles.css index 30abc52b..fa57e51d 100644 --- a/src/styles.css +++ b/src/styles.css @@ -134,6 +134,18 @@ body { -ms-interpolation-mode: nearest-neighbor; } +.overlay-top-scaled { + position: fixed; + inset: 0; + transform-origin: top left; + transform: scale(var(--guiScale)); + width: calc(100% / var(--guiScale)); + height: calc(100% / var(--guiScale)); + z-index: 80; + image-rendering: pixelated; + pointer-events: none; +} + #viewer-canvas { position: fixed; top: 0; From 620488af201a02fc38bc19a604876a26884c01a2 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Fri, 10 May 2024 05:08:28 +0300 Subject: [PATCH 0075/1097] Add Gamepad UI Cursor component and styles --- src/react/GamepadUiCursor.module.css | 11 ++++++++ src/react/GamepadUiCursor.tsx | 40 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/react/GamepadUiCursor.module.css create mode 100644 src/react/GamepadUiCursor.tsx diff --git a/src/react/GamepadUiCursor.module.css b/src/react/GamepadUiCursor.module.css new file mode 100644 index 00000000..f3f114e4 --- /dev/null +++ b/src/react/GamepadUiCursor.module.css @@ -0,0 +1,11 @@ +.crosshair { + width: 16px; + height: 16px; + background: var(--gui-icons); + background-size: calc(256px * var(--crosshair-scale)); + position: fixed; + z-index: 100; + transform: translate(-50%, -50%); + pointer-events: none; + image-rendering: pixelated; +} diff --git a/src/react/GamepadUiCursor.tsx b/src/react/GamepadUiCursor.tsx new file mode 100644 index 00000000..84c9b63a --- /dev/null +++ b/src/react/GamepadUiCursor.tsx @@ -0,0 +1,40 @@ +import { proxy, useSnapshot } from 'valtio' +import { useEffect } from 'react' +import { activeModalStack, miscUiState } from '../globalState' +import SharedHudVars from './SharedHudVars' +import styles from './GamepadUiCursor.module.css' + +export const gamepadUiCursorState = proxy({ + x: 50, + y: 50, + multiply: 1, + display: false +}) + +export const moveGamepadCursorByPx = (value: number, isX: boolean) => { + value *= gamepadUiCursorState.multiply * 3 + const valueToPercentage = value / (isX ? window.innerWidth : window.innerHeight) * 100 + gamepadUiCursorState[isX ? 'x' : 'y'] += valueToPercentage +} + +export default () => { + const hasModals = useSnapshot(activeModalStack).length > 0 + const { x, y } = useSnapshot(gamepadUiCursorState) + const { usingGamepadInput, gameLoaded } = useSnapshot(miscUiState) + + const doDisplay = usingGamepadInput && (hasModals || !gameLoaded) + + useEffect(() => { + document.body.style.cursor = gameLoaded && !hasModals && usingGamepadInput ? 'none' : 'auto' + }, [usingGamepadInput, hasModals, gameLoaded]) + + useEffect(() => { + gamepadUiCursorState.display = doDisplay + }, [doDisplay]) + + if (!doDisplay) return null + + return +
+ +} From e9443cd2fe0dece8749e291444473a89c6767459 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 9 May 2024 21:17:16 +0300 Subject: [PATCH 0076/1097] ui: fix input alignment --- src/react/input.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/react/input.module.css b/src/react/input.module.css index ce889645..ce181ade 100644 --- a/src/react/input.module.css +++ b/src/react/input.module.css @@ -8,7 +8,7 @@ } .input { - position: relative; + position: absolute; outline: none; border: none; background: none; From 3f068ed0da7ebb4cd6519c0d473683cb86ebd28d Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 10 May 2024 06:03:25 +0300 Subject: [PATCH 0077/1097] fix tsc --- src/react/TouchAreasControls.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/react/TouchAreasControls.tsx b/src/react/TouchAreasControls.tsx index f56db047..b660fcb2 100644 --- a/src/react/TouchAreasControls.tsx +++ b/src/react/TouchAreasControls.tsx @@ -40,12 +40,14 @@ export const handleMovementStickDelta = (e?: { clientX, clientY }) => { } joystickPointer.joystickInner!.style.transform = `translate(${x}px, ${y}px)` + const vector = { + x: x / max, + y: 0, + z: y / max, + } void contro.emit('movementUpdate', { - vector: { - x: x / max, - y: 0, - z: y / max, - }, + vector, + soleVector: vector }) } From b7d317825f1f32a03b235249a2f403e9584d3a82 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 11 May 2024 21:15:51 +0300 Subject: [PATCH 0078/1097] fix lighting in playround for pre-flat versions --- prismarine-viewer/examples/playground.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/prismarine-viewer/examples/playground.ts b/prismarine-viewer/examples/playground.ts index 295cc47d..223fc6f2 100644 --- a/prismarine-viewer/examples/playground.ts +++ b/prismarine-viewer/examples/playground.ts @@ -138,6 +138,7 @@ async function main () { viewer.entities.onSkinUpdate = () => { viewer.render() } + viewer.world.mesherConfig.enableLighting = false viewer.listen(worldView) // Load chunks From 54a7e52cff8c6d372ca93f921188a17399955758 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 11 May 2024 21:20:30 +0300 Subject: [PATCH 0079/1097] add light test utils --- .../viewer/lib/mesher/test/mesherTester.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts b/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts index a665db6b..6103a3d4 100644 --- a/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts +++ b/prismarine-viewer/viewer/lib/mesher/test/mesherTester.ts @@ -38,8 +38,22 @@ export const setup = (version, initialBlocks: [number[], string][]) => { } reload() + const getLights = () => { + return Object.fromEntries(getGeometry().faces.map(({ face, light }) => ([face, light * 15 - 2]))) + } + + const setLight = (x: number, y: number, z: number, val = 0) => { + // create columns first + chunk1.setBlockLight(pos.offset(x, y, z), 15) + chunk1.setSkyLight(pos.offset(x, y, z), 15) + chunk1.setBlockLight(pos.offset(x, y, z), val) + chunk1.setSkyLight(pos.offset(x, y, z), 0) + } + return { mesherWorld, + setLight, + getLights, getGeometry, pos, mcData, From 02fb4c93940ec995ccf89dca52d28c8b44c49781 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 13 May 2024 02:15:58 +0300 Subject: [PATCH 0080/1097] fix different width in server menu --- src/react/singleplayer.module.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/react/singleplayer.module.css b/src/react/singleplayer.module.css index fef43b76..c7ec49f6 100644 --- a/src/react/singleplayer.module.css +++ b/src/react/singleplayer.module.css @@ -23,7 +23,7 @@ .world_root { height: 40px; - width: 300px; + width: 308px; border: 1px solid transparent; display: flex; outline: none; @@ -43,6 +43,7 @@ flex-direction: column; font-size: 11px; white-space: nowrap; + width: 100%; } .world_info_formatted { font-size: 10px; From ef146f7a28c5105f47810d50db6b6995db120924 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 13 May 2024 03:42:31 +0300 Subject: [PATCH 0081/1097] fix(hud): fix safe bottom area for iOS devices when clicked "Hide Toolbar" https://forums.developer.apple.com/forums/thread/716552 chore: add new experiment for demo --- experiments/ios-safe-area-bottom-bug.html | 15 +++++++++++++++ package.json | 2 +- src/react/HotbarRenderApp.tsx | 2 +- src/react/SharedHudVars.tsx | 6 ++++-- 4 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 experiments/ios-safe-area-bottom-bug.html diff --git a/experiments/ios-safe-area-bottom-bug.html b/experiments/ios-safe-area-bottom-bug.html new file mode 100644 index 00000000..53d867f5 --- /dev/null +++ b/experiments/ios-safe-area-bottom-bug.html @@ -0,0 +1,15 @@ + +
+ bottom: env(safe-area-inset-bottom) +
diff --git a/package.json b/package.json index 11324549..92de17cf 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "lint": "eslint \"{src,cypress}/**/*.{ts,js,jsx,tsx}\"", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build && node scripts/build.js moveStorybookFiles", - "start-experiments": "vite --config experiments/vite.config.ts", + "start-experiments": "vite --config experiments/vite.config.ts --host", "watch-other-workers": "echo NOT IMPLEMENTED", "watch-mesher": "node prismarine-viewer/buildMesherWorker.mjs -w", "run-playground": "run-p watch-mesher watch-other-workers playground-server watch-playground", diff --git a/src/react/HotbarRenderApp.tsx b/src/react/HotbarRenderApp.tsx index 5b32e3cc..3b50f49b 100644 --- a/src/react/HotbarRenderApp.tsx +++ b/src/react/HotbarRenderApp.tsx @@ -211,7 +211,7 @@ export default () => { justifyContent: 'center', zIndex: hasModals ? 1 : 8, pointerEvents: 'none', - bottom: 'env(safe-area-inset-bottom)' + bottom: 'var(--hud-bottom-raw)' }} /> diff --git a/src/react/SharedHudVars.tsx b/src/react/SharedHudVars.tsx index 9a9392fd..6cc0c54e 100644 --- a/src/react/SharedHudVars.tsx +++ b/src/react/SharedHudVars.tsx @@ -8,10 +8,12 @@ export default ({ children }): React.ReactElement => { // 1. Don't inline long data URLs for better DX in elements tab // 2. Easier application to globally override icons with custom image (eg from resourcepacks) const css = /* css */` - :root { + html { --widgets-gui-atlas: url(${widgets}); --gui-icons: url(${icons}), url(${icons}); - --safe-area-inset-bottom: calc(env(safe-area-inset-bottom) / 2); + --hud-bottom-max: 0px; + --hud-bottom-raw: max(env(safe-area-inset-bottom), var(--hud-bottom-max)); + --safe-area-inset-bottom: calc(var(--hud-bottom-raw) / 2); } ` const style = document.createElement('style') From 0a1b97857c4c464da0fc306154420b577e9dad9c Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 13 May 2024 03:43:10 +0300 Subject: [PATCH 0082/1097] feat: add a way to specify version from quick connect e.g. test.com:1.18.2 or 192.168.0.100:25566:1.17.1 --- src/react/ServersList.tsx | 12 ++++++++++-- src/react/ServersListProvider.tsx | 7 +++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/react/ServersList.tsx b/src/react/ServersList.tsx index 2fbbd349..f6b89452 100644 --- a/src/react/ServersList.tsx +++ b/src/react/ServersList.tsx @@ -60,14 +60,22 @@ export default ({ initialProxies, updateProxies: updateProxiesProp, joinServer, return { e.preventDefault() - joinServer(serverIp, { + let ip = serverIp + let version + const parts = ip.split(':') + if (parts.length > 1 && parts.at(-1)!.includes('.')) { + version = parts.at(-1)! + ip = parts.slice(0, -1).join(':') + } + joinServer(ip, { shouldSave: save, + versionOverride: version, }) }} >
{/* todo history */} - setServerIp(value)} /> + setServerIp(value)} />
- ) : null } + ) : null} {level > 0 && level < 256 ? (
{level + 1}
- ) : null } + ) : null}
} @@ -56,7 +56,7 @@ const indicatorIcons: Record = { readonlyFiles: 'file-off', } -export default ({ indicators, effects }: {indicators: typeof defaultIndicatorsState, effects: readonly EffectType[]}) => { +export default ({ indicators, effects }: { indicators: typeof defaultIndicatorsState, effects: readonly EffectType[] }) => { const effectsRef = useRef(effects) useEffect(() => { effectsRef.current = effects diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 94ea6b88..9a79de34 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -36,6 +36,7 @@ import Crosshair from './react/Crosshair' import ButtonAppProvider from './react/ButtonAppProvider' import ServersListProvider from './react/ServersListProvider' import GamepadUiCursor from './react/GamepadUiCursor' +import HeldMapUi from './react/HeldMapUi' const RobustPortal = ({ children, to }) => { return createPortal({children}, to) @@ -85,6 +86,12 @@ const GameHud = ({ children }) => { return gameLoaded ? children : null } +const InGameComponent = ({ children }) => { + const { gameLoaded } = useSnapshot(miscUiState) + if (!gameLoaded) return null + return children +} + const InGameUi = () => { const { gameLoaded } = useSnapshot(miscUiState) if (!gameLoaded) return @@ -135,6 +142,14 @@ const WidgetDisplay = ({ name, Component }) => { const App = () => { return
+ +
+ + + +
+
+
@@ -151,6 +166,7 @@ const App = () => { */} + {/* todo correct mounting! */}
diff --git a/src/styles.css b/src/styles.css index fa57e51d..139996e9 100644 --- a/src/styles.css +++ b/src/styles.css @@ -134,7 +134,7 @@ body { -ms-interpolation-mode: nearest-neighbor; } -.overlay-top-scaled { +.overlay-top-scaled, .overlay-bottom-scaled { position: fixed; inset: 0; transform-origin: top left; @@ -146,6 +146,10 @@ body { pointer-events: none; } +.overlay-bottom-scaled { + z-index: 1; +} + #viewer-canvas { position: fixed; top: 0; diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index c3263f2f..2e20de29 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -197,7 +197,7 @@ class WorldInteraction { 'minecart', 'boat', 'tnt_minecart', 'chest_minecart', 'hopper_minecart', 'command_block_minecart', 'armor_stand', 'lead', 'name_tag', // - 'writable_book', 'written_book', 'compass', 'clock', 'filled_map', 'empty_map', + 'writable_book', 'written_book', 'compass', 'clock', 'filled_map', 'empty_map', 'map', 'shears', 'carrot_on_a_stick', 'warped_fungus_on_a_stick', 'spawn_egg', 'trident', 'crossbow', 'elytra', 'shield', 'turtle_helmet', ].includes(bot.heldItem.name) @@ -219,10 +219,10 @@ class WorldInteraction { bot.lookAt = oldLookAt }).catch(console.warn) } - this.lastBlockPlaced = 0 } else { bot.activateItem() // todo offhand } + this.lastBlockPlaced = 0 } // Stop break From 3329d0e75eaffca181d652f0fb80df96a8e3b90c Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 13 May 2024 04:14:16 +0300 Subject: [PATCH 0085/1097] fix: held item display was not updated after server/window GUI manipulation on inventory --- src/index.ts | 9 +++++++++ src/react/HeldMapUi.tsx | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 69886b3b..8dbc46cf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -547,6 +547,15 @@ async function connect (connectOptions: ConnectOptions) { window.Vec3 = Vec3 window.pathfinder = pathfinder + // patch mineflayer + // todo move to mineflayer + bot.inventory.on('updateSlot', (index) => { + if ((index as unknown as number) === bot.quickBarSlot + bot.inventory.hotbarStart) { + //@ts-expect-error + bot.emit('heldItemChanged') + } + }) + miscUiState.gameLoaded = true miscUiState.loadedServerIndex = connectOptions.serverIndex ?? '' customEvents.emit('gameLoaded') diff --git a/src/react/HeldMapUi.tsx b/src/react/HeldMapUi.tsx index 242cba03..9187c98b 100644 --- a/src/react/HeldMapUi.tsx +++ b/src/react/HeldMapUi.tsx @@ -20,13 +20,14 @@ export default () => { return canvas.toDataURL('image/png') }) + // TODO delete maps! const updateHeldMap = () => { setDataUrl(null) if (!bot.heldItem || !['filled_map', 'map'].includes(bot.heldItem.name)) return // setDataUrl(true) const mapNumber = (bot.heldItem?.nbt?.value as any)?.map?.value // if (!mapNumber) return - setDataUrl(bot.mapDownloader.maps[mapNumber] as unknown as string) + setDataUrl(bot.mapDownloader.maps?.[mapNumber] as unknown as string) } bot.on('heldItemChanged' as any, () => { From c1651ce3b55ec846fd459b9c61461ce3040211e2 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 13 May 2024 15:36:11 +0300 Subject: [PATCH 0086/1097] fix: some collision shapes were missing for 1.20.4 --- ...Shapes.mjs => generateMoreCollisionShapes.mjs} | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) rename scripts/{getMoreCollisionShapes.mjs => generateMoreCollisionShapes.mjs} (94%) diff --git a/scripts/getMoreCollisionShapes.mjs b/scripts/generateMoreCollisionShapes.mjs similarity index 94% rename from scripts/getMoreCollisionShapes.mjs rename to scripts/generateMoreCollisionShapes.mjs index 3f772af1..ee178478 100644 --- a/scripts/getMoreCollisionShapes.mjs +++ b/scripts/generateMoreCollisionShapes.mjs @@ -1,8 +1,11 @@ +//@ts-check import minecraftData from 'minecraft-data' import minecraftAssets from 'minecraft-assets' import fs from 'fs' -const latestData = minecraftData('1.20.2') +const latestVersion = minecraftData.versions.pc[0] + +const latestData = minecraftData(latestVersion.minecraftVersion) // dont touch, these are the ones that are already full box const fullBoxInteractionShapes = [ @@ -62,7 +65,7 @@ const fullBoxInteractionShapesTemp = [ 'white_wall_banner', ] -const shapes = latestData.blockCollisionShapes; +const shapes = latestData.blockCollisionShapes const fullShape = shapes.shapes[1] const outputJson = {} @@ -97,8 +100,8 @@ const interestedBlocks = latestData.blocksArray.filter(block => { const { blocksStates, blocksModels } = minecraftAssets(latestData.version.minecraftVersion) const getShapeFromModel = (block,) => { - const blockStates = JSON.parse(fs.readFileSync('./prismarine-viewer/public/blocksStates/1.19.1.json')) - const blockState = blockStates[block]; + const blockStates = JSON.parse(fs.readFileSync('./prismarine-viewer/public/blocksStates/1.19.1.json', 'utf8')) + const blockState = blockStates[block] const perVariant = {} for (const [key, variant] of Object.entries(blockState.variants)) { // const shapes = (Array.isArray(variant) ? variant : [variant]).flatMap((v) => v.model?.elements).filter(Boolean).map(({ from, to }) => [...from, ...to]).reduce((acc, cur) => { @@ -146,7 +149,7 @@ outer: for (const interestedBlock of [...interestedBlocksNoStates, ...interested } } - const hasStates = interestedBlocksStates.includes(interestedBlock); + const hasStates = interestedBlocksStates.includes(interestedBlock) if (hasStates) { const states = blocksStates[interestedBlock] if (!states) { @@ -159,7 +162,7 @@ outer: for (const interestedBlock of [...interestedBlocksNoStates, ...interested continue } let outputStates = {} - for (const {when} of states.multipart) { + for (const { when } of states.multipart) { if (when) { for (const [key, value] of Object.entries(when)) { if (key === 'OR') { From 6f085ac5061e2d38b2f7fa71c1df3127b549186f Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 13 May 2024 15:49:10 +0300 Subject: [PATCH 0087/1097] fix: entity text was not displayed in some edge-cases --- prismarine-viewer/viewer/lib/entities.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.js b/prismarine-viewer/viewer/lib/entities.js index 290c3932..136c77fe 100644 --- a/prismarine-viewer/viewer/lib/entities.js +++ b/prismarine-viewer/viewer/lib/entities.js @@ -1,10 +1,10 @@ //@ts-check -const THREE = require('three') -const TWEEN = require('@tweenjs/tween.js') - -const Entity = require('./entity/EntityMesh') -const { dispose3 } = require('./dispose') -const EventEmitter = require('events') +import * as THREE from 'three' +import * as TWEEN from '@tweenjs/tween.js' +import * as Entity from './entity/EntityMesh' +import { dispose3 } from './dispose' +import nbt from 'prismarine-nbt' +import EventEmitter from 'events' import { PlayerObject, PlayerAnimation } from 'skinview3d' import { loadSkinToCanvas, loadEarsToCanvasFromSkin, inferModelType, loadCapeToCanvas, loadImage } from 'skinview-utils' // todo replace with url @@ -264,7 +264,7 @@ export class Entities extends EventEmitter { displaySimpleText(jsonLike) { if (!jsonLike) return - const parsed = mojangson.simplify(mojangson.parse(jsonLike)) + const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike) const text = flat(parsed).map(x => x.text) return text.join('') } From 8d710e297eb116c45160d19f791cddf1ab485ea0 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 13 May 2024 15:54:33 +0300 Subject: [PATCH 0088/1097] save version override from quick connect --- src/react/ServersListProvider.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index 07bbba31..bd39bc10 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -252,9 +252,10 @@ const Inner = () => { autoLoginPassword: server?.autoLogin?.[username], onSuccessfulPlay () { if (overrides.shouldSave && !serversList.some(s => s.ip === ip)) { - const newServersList = [...serversList, { + const newServersList: StoreServerItem[] = [...serversList, { ip, lastJoined: Date.now(), + versionOverride: overrides.versionOverride, }] // setServersList(newServersList) setNewServersList(newServersList) // component is not mounted From 5198e698160483fcc2aaacb508cee63501d546a2 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 18 May 2024 05:57:50 +0300 Subject: [PATCH 0089/1097] fix: correctly display item names in inventory GUI fix: fix opening nested inventory GUI on servers! --- README.MD | 4 ++++ src/globalState.ts | 6 +++--- src/inventoryWindows.ts | 27 +++++++++++++++++++++------ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/README.MD b/README.MD index ce368540..225cdda2 100644 --- a/README.MD +++ b/README.MD @@ -126,3 +126,7 @@ Press `Y` to set query parameters to url of your current game state. - [Minecraft Protocol](https://github.com/PrismarineJS/node-minecraft-protocol) - Makes connections to servers possible - [Peer.js](https://peerjs.com/) - P2P networking (when you open to wan) - [Three.js](https://threejs.org/) - Helping in 3D rendering + +### Alternatives + +- [https://github.com/ClassiCube/ClassiCube](ClassiCube - Better C# Rewrite) [https://www.classicube.net/](https://www.classicube.net/server/play/?warned=true) diff --git a/src/globalState.ts b/src/globalState.ts index 1b0526f9..4b62f8d6 100644 --- a/src/globalState.ts +++ b/src/globalState.ts @@ -8,7 +8,7 @@ import type { OptionsGroupType } from './optionsGuiScheme' const notHideableModalsWithoutForce = new Set(['app-status']) -type Modal = ({ elem?: HTMLElement & Record } & { reactType?: string }) +type Modal = ({ elem?: HTMLElement & Record } & { reactType: string }) type ContextMenuItem = { callback; label } @@ -57,7 +57,7 @@ const showModalInner = (modal: Modal) => { } export const showModal = (elem: /* (HTMLElement & Record) | */{ reactType: string }) => { - const resolved = elem instanceof HTMLElement ? { elem: ref(elem) } : elem + const resolved = elem const curModal = activeModalStack.at(-1) if (/* elem === curModal?.elem || */(elem.reactType && elem.reactType === curModal?.reactType) || !showModalInner(resolved)) return if (curModal) defaultModalActions.hide(curModal) @@ -123,7 +123,7 @@ export type AppConfig = { defaultProxy?: string // defaultProxySave?: string // defaultVersion?: string - promoteServers?: Array<{ip, description, version?}> + promoteServers?: Array<{ ip, description, version?}> mapsProvider?: string } diff --git a/src/inventoryWindows.ts b/src/inventoryWindows.ts index d9fda1c7..d87d4008 100644 --- a/src/inventoryWindows.ts +++ b/src/inventoryWindows.ts @@ -123,6 +123,11 @@ export const onGameLoad = (onLoad) => { // todo hide up to the window itself! hideCurrentModal() }) + bot.on('respawn', () => { // todo validate logic against native client (maybe login) + if (lastWindow) { + hideCurrentModal() + } + }) customEvents.on('search', (q) => { if (!lastWindow) return @@ -316,10 +321,10 @@ export const getItemNameRaw = (item: Pick const getItemName = (slot: Item | null) => { const parsed = getItemNameRaw(slot) - if (!parsed || parsed['extra']) return + if (!parsed) return // todo display full text renderer from sign renderer const text = flat(parsed as MessageFormatPart).map(x => x.text) - return text + return text.join('') } export const renderSlotExternal = (slot) => { @@ -362,12 +367,15 @@ export const onModalClose = (callback: () => any) => { callback() unsubscribe() } - }) + }, true) } const implementedContainersGuiMap = { // todo allow arbitrary size instead! + 'minecraft:generic_9x1': 'ChestWin', + 'minecraft:generic_9x2': 'ChestWin', 'minecraft:generic_9x3': 'ChestWin', + 'minecraft:generic_9x4': 'Generic95Win', 'minecraft:generic_9x5': 'Generic95Win', // hopper 'minecraft:generic_5x1': 'HopperWin', @@ -401,22 +409,29 @@ export const openItemsCanvas = (type, _bot = bot as typeof bot | null) => { return inv } +let skipClosePacketSending = false const openWindow = (type: string | undefined) => { // if (activeModalStack.some(x => x.reactType?.includes?.('player_win:'))) { if (activeModalStack.length) { // game is not in foreground, don't close current modal - if (type) bot.currentWindow?.['close']() - return + if (type) { + skipClosePacketSending = true + hideCurrentModal() + } else { + bot.currentWindow?.['close']() + return + } } showModal({ reactType: `player_win:${type}`, }) onModalClose(() => { // might be already closed (event fired) - if (type !== undefined && bot.currentWindow) bot.currentWindow['close']() + if (type !== undefined && bot.currentWindow && !skipClosePacketSending) bot.currentWindow['close']() lastWindow.destroy() lastWindow = null as any miscUiState.displaySearchInput = false destroyFn() + skipClosePacketSending = false }) cleanLoadedImagesCache() const inv = openItemsCanvas(type) From 6375df15763c0bae6eb36a59801be43f6ad27384 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 18 May 2024 22:24:52 +0300 Subject: [PATCH 0090/1097] improve readme clarity --- README.MD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.MD b/README.MD index 225cdda2..af966101 100644 --- a/README.MD +++ b/README.MD @@ -120,7 +120,7 @@ Press `Y` to set query parameters to url of your current game state. ### Notable Things that Power this Project - [Mineflayer](https://github.com/PrismarineJS/mineflayer) - Handles all client-side communications with the server (including the builtin one) - forked -- [Flying Squid](https://github.com/prismarineJS/flying-squid) - The builtin server that makes single player possible! Here forked version is used. +- [Forked Flying Squid (Space Squid)](https://github.com/zardoy/space-squid) - The builtin offline server that makes single player & P2P possible! - [Prismarine Provider Anvil](https://github.com/PrismarineJS/prismarine-provider-anvil) - Handles world loading (region format) - [Prismarine Physics](https://github.com/PrismarineJS/prismarine-physics) - Does all the physics calculations - [Minecraft Protocol](https://github.com/PrismarineJS/node-minecraft-protocol) - Makes connections to servers possible @@ -129,4 +129,4 @@ Press `Y` to set query parameters to url of your current game state. ### Alternatives -- [https://github.com/ClassiCube/ClassiCube](ClassiCube - Better C# Rewrite) [https://www.classicube.net/](https://www.classicube.net/server/play/?warned=true) +- [https://github.com/ClassiCube/ClassiCube](ClassiCube - Better C# Rewrite) [DEMO](https://www.classicube.net/server/play/?warned=true) From 6bf1085fbe422b3e926fcb89e29da70ea2804c8d Mon Sep 17 00:00:00 2001 From: gguio <109200692+gguio@users.noreply.github.com> Date: Sat, 18 May 2024 23:51:35 +0400 Subject: [PATCH 0091/1097] feat: Key binds screen (#108) --------- Co-authored-by: gguio Co-authored-by: Vitaly --- esbuild.mjs | 1 + package.json | 2 +- pnpm-lock.yaml | 10 +- src/controls.ts | 28 +- ...tation_console_controller_gamepad_icon.svg | 1 + src/customCommands.ts | 91 ++++ src/optionsGuiScheme.tsx | 23 +- src/react/KeybindingsCustom.tsx | 171 ++++++++ src/react/KeybindingsScreen.module.css | 88 ++++ src/react/KeybindingsScreen.tsx | 388 +++++++++++++++++- src/react/KeybindingsScreenApp.tsx | 51 --- src/react/KeybindingsScreenProvider.tsx | 50 +++ src/react/OptionsGroup.tsx | 2 +- src/react/globals.d.ts | 4 + ...tation_console_controller_gamepad_icon.svg | 1 + ...tation_console_controller_gamepad_icon.svg | 1 + ...square_console_controller_gamepad_icon.svg | 1 + ...iangle_console_controller_gamepad_icon.svg | 1 + src/react/storageProvider.ts | 13 + src/reactUi.tsx | 2 + src/screens.css | 1 + 21 files changed, 858 insertions(+), 72 deletions(-) create mode 100644 src/cross_playstation_console_controller_gamepad_icon.svg create mode 100644 src/customCommands.ts create mode 100644 src/react/KeybindingsCustom.tsx create mode 100644 src/react/KeybindingsScreen.module.css delete mode 100644 src/react/KeybindingsScreenApp.tsx create mode 100644 src/react/KeybindingsScreenProvider.tsx create mode 100644 src/react/ps_icons/circle_playstation_console_controller_gamepad_icon.svg create mode 100644 src/react/ps_icons/cross_playstation_console_controller_gamepad_icon.svg create mode 100644 src/react/ps_icons/playstation_square_console_controller_gamepad_icon.svg create mode 100644 src/react/ps_icons/playstation_triangle_console_controller_gamepad_icon.svg create mode 100644 src/react/storageProvider.ts diff --git a/esbuild.mjs b/esbuild.mjs index 1e8d6478..d68693d8 100644 --- a/esbuild.mjs +++ b/esbuild.mjs @@ -79,6 +79,7 @@ const buildOptions = { loader: { // todo use external or resolve issues with duplicating '.png': 'dataurl', + '.svg': 'dataurl', '.map': 'empty', '.vert': 'text', '.frag': 'text', diff --git a/package.json b/package.json index 4bbeaf81..6905a8b7 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "constants-browserify": "^1.0.0", - "contro-max": "^0.1.6", + "contro-max": "^0.1.7", "crypto-browserify": "^3.12.0", "cypress": "^10.11.0", "cypress-esbuild-preprocessor": "^1.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index beb0c0a9..dcacb13a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -268,8 +268,8 @@ importers: specifier: ^1.0.0 version: 1.0.0 contro-max: - specifier: ^0.1.6 - version: 0.1.6(typescript@5.5.0-beta) + specifier: ^0.1.7 + version: 0.1.7(typescript@5.5.0-beta) crypto-browserify: specifier: ^3.12.0 version: 3.12.0 @@ -3811,8 +3811,8 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - contro-max@0.1.6: - resolution: {integrity: sha512-QsoOcAlbtNgkCGBvwKsh+GUVZ2c5zfMgYQCu+v4MplX5VolkWhMwAcEOBRxt8oENbnRXOKUGQr816Ey1G4/jpg==} + contro-max@0.1.7: + resolution: {integrity: sha512-HIYF1Dl50tUyTKaDsX+mPMDv2OjleNMVedYuBTX0n1wKNm9WxjWu2w74ATjz/8fHVL9GgmziIxAlFStd2je6kg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} convert-source-map@1.9.0: @@ -12851,7 +12851,7 @@ snapshots: content-type@1.0.5: {} - contro-max@0.1.6(typescript@5.5.0-beta): + contro-max@0.1.7(typescript@5.5.0-beta): dependencies: events: 3.3.0 lodash-es: 4.17.21 diff --git a/src/controls.ts b/src/controls.ts index 6dd47be2..6e38b90c 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -6,21 +6,24 @@ import { proxy, subscribe } from 'valtio' import { ControMax } from 'contro-max/build/controMax' import { CommandEventArgument, SchemaCommandInput } from 'contro-max/build/types' import { stringStartsWith } from 'contro-max/build/stringUtils' +import { UserOverridesConfig } from 'contro-max/build/types/store' import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCurrentModal, miscUiState } from './globalState' import { goFullscreen, pointerLock, reloadChunks } from './utils' import { options } from './optionsStorage' import { openPlayerInventory } from './inventoryWindows' import { chatInputValueGlobal } from './react/Chat' import { fsState } from './loadSave' +import { customCommandsConfig } from './customCommands' +import { CustomCommand } from './react/KeybindingsCustom' import { showOptionsModal } from './react/SelectOption' import widgets from './react/widgets' import { getItemFromBlock } from './botUtils' import { gamepadUiCursorState, moveGamepadCursorByPx } from './react/GamepadUiCursor' -// todo move this to shared file with component -export const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}')) + +export const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}')) as UserOverridesConfig subscribe(customKeymaps, () => { - localStorage.keymap = JSON.parse(customKeymaps) + localStorage.keymap = JSON.stringify(customKeymaps) }) const controlOptions = { @@ -53,7 +56,8 @@ export const contro = new ControMax({ }, advanced: { lockUrl: ['KeyY'], - } + }, + custom: {} as Record, // waila: { // showLookingBlockRecipe: ['Numpad3'], // showLookingBlockUsages: ['Numpad4'] @@ -81,6 +85,8 @@ export const contro = new ControMax({ window.controMax = contro export type Command = CommandEventArgument['command'] +// updateCustomBinds() + export const setDoPreventDefault = (state: boolean) => { controlOptions.preventDefault = state } @@ -285,6 +291,20 @@ function cycleHotbarSlot (dir: 1 | -1) { bot.setQuickBarSlot(newHotbarSlot) } +// custom commands hamdler +const customCommandsHandler = (buttonData: { code?: string, button?: string, state: boolean }) => { + if (!buttonData.state || !isGameActive(true)) return + + const codeOrButton = buttonData.code ?? buttonData.button + const inputType = buttonData.code ? 'keys' : 'gamepad' + for (const value of Object.values(contro.userConfig!.custom)) { + if (value[inputType]?.includes(codeOrButton!)) { + customCommandsConfig[(value as CustomCommand).type].handler((value as CustomCommand).inputs) + } + } +} +contro.on('pressedKeyOrButtonChanged', customCommandsHandler) + contro.on('trigger', ({ command }) => { const willContinue = !isGameActive(true) alwaysPressedHandledCommand(command) diff --git a/src/cross_playstation_console_controller_gamepad_icon.svg b/src/cross_playstation_console_controller_gamepad_icon.svg new file mode 100644 index 00000000..d7d176e2 --- /dev/null +++ b/src/cross_playstation_console_controller_gamepad_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/customCommands.ts b/src/customCommands.ts new file mode 100644 index 00000000..eddfc89e --- /dev/null +++ b/src/customCommands.ts @@ -0,0 +1,91 @@ +import { guiOptionsScheme, tryFindOptionConfig } from './optionsGuiScheme' +import { options } from './optionsStorage' + +export const customCommandsConfig = { + chat: { + input: [ + { + type: 'text', + placeholder: 'Command to send e.g. gamemode creative' + } + ], + handler ([command]) { + bot.chat(`/${command.replace(/^\//, '')}`) + } + }, + setOrToggleSetting: { + input: [ + { + type: 'select', + // maybe title case? + options: Object.keys(options) + }, + { + type: 'select', + options: ['toggle', 'set'] + }, + ([setting = '', action = ''] = []) => { + const value = options[setting] + if (!action || value === undefined || action === 'toggle') return null + if (action === 'set') { + const getBase = () => { + const config = tryFindOptionConfig(setting as any) + if (config && 'values' in config) { + return { + type: 'select', + options: config.values + } + } + if (config?.type === 'toggle' || typeof value === 'boolean') { + return { + type: 'select', + options: ['true', 'false'] + } + } + if (config?.type === 'slider' || value.type === 'number') { + return { + type: 'number', + } + } + return { + type: 'text' + } + } + return { + ...getBase(), + placeholder: value + } + } + } + ], + handler ([setting, action, value]) { + if (action === 'toggle') { + const value = options[setting] + const config = tryFindOptionConfig(setting) + if (config && 'values' in config && config.values) { + const { values } = config + const currentIndex = values.indexOf(value) + const nextIndex = (currentIndex + 1) % values.length + options[setting] = values[nextIndex] + } else { + options[setting] = typeof value === 'boolean' ? !value : typeof value === 'number' ? value + 1 : value + } + } else { + options[setting] = value + } + } + }, + jsScripts: { + input: [ + { + type: 'text', + placeholder: 'JavaScript code to run in main thread (sensitive!)' + } + ], + handler ([code]) { + // eslint-disable-next-line no-new-func -- this is a feature, not a bug + new Function(code)() + } + }, + // openCommandsScreen: {} +} diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 1c92a39c..b847fe11 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -184,7 +184,16 @@ export const guiOptionsScheme: { custom () { return Keyboard & Mouse }, - // keybindings + }, + { + custom () { + return + }, mouseSensX: {}, mouseSensY: { min: -1, @@ -282,3 +291,15 @@ const Category = ({ children }) =>
{children}
+ +export const tryFindOptionConfig = (option: keyof AppOptions) => { + for (const group of Object.values(guiOptionsScheme)) { + for (const optionConfig of group) { + if (option in optionConfig) { + return optionConfig[option] + } + } + } + + return null +} diff --git a/src/react/KeybindingsCustom.tsx b/src/react/KeybindingsCustom.tsx new file mode 100644 index 00000000..bee991bf --- /dev/null +++ b/src/react/KeybindingsCustom.tsx @@ -0,0 +1,171 @@ +import { useEffect, useState, useContext } from 'react' +import { customCommandsConfig } from '../customCommands' +import { ButtonWithMatchesAlert, Context } from './KeybindingsScreen' +import Button from './Button' +import styles from './KeybindingsScreen.module.css' +import Input from './Input' + + +export type CustomCommand = { + keys: undefined | string[] + gamepad: undefined | string[] + type: string + inputs: any[] +} + +export type CustomCommandsMap = Record + +export default ( + { + customCommands, + updateCurrBind, + resetBinding, + }: { + customCommands: CustomCommandsMap, + updateCurrBind: (group: string, action: string) => void, + resetBinding: (group: string, action: string, inputType: string) => void, + } +) => { + const { userConfig, setUserConfig } = useContext(Context) + const [customConfig, setCustomConfig] = useState({ ...customCommands }) + + useEffect(() => { + setUserConfig({ ...userConfig, custom: { ...customConfig } }) + }, [customConfig]) + + const addNewCommand = (type: string) => { + // max key + 1 + const newKey = String(Math.max(...Object.keys(customConfig).map(Number).filter(key => !isNaN(key)), 0) + 1) + setCustomConfig(prev => { + const newCustomConf = { ...prev } + newCustomConf[newKey] = { + keys: undefined as string[] | undefined, + gamepad: undefined as string[] | undefined, + type, + inputs: [] as any[] + } + return newCustomConf + }) + } + + return <> +
+ {Object.entries(customCommandsConfig).map(([group, { input }]) => ( +
+
{group}
+ {Object.entries(customConfig).filter(([key, data]) => data.type === group).map((commandData, indexOption) => { + return + })} +
+ ))} +
+ +} + +const CustomCommandContainer = ( + { + indexOption, + commandData, + updateCurrBind, + setCustomConfig, + resetBinding, + groupData + } +) => { + const { userConfig } = useContext(Context) + + const [commandKey, { keys, gamepad, inputs }] = commandData + const [group, { input }] = groupData + + const setInputValue = (optionKey, indexInput, value) => { + setCustomConfig(prev => { + const newConfig = { ...prev } + newConfig[optionKey].inputs = [...prev[optionKey].inputs] + newConfig[optionKey].inputs[indexInput] = value + return newConfig + }) + } + + return
+ {input.map((obj, indexInput) => { + const config = typeof obj === 'function' ? obj(inputs) : obj + if (!config) return null + + return config.type === 'select' + ? + : setInputValue(commandKey, indexInput, e.target.value)} /> + })} +
+ { + userConfig?.['custom']?.[commandKey]?.keys ?
+
+} diff --git a/src/react/KeybindingsScreen.module.css b/src/react/KeybindingsScreen.module.css new file mode 100644 index 00000000..e8a9f69b --- /dev/null +++ b/src/react/KeybindingsScreen.module.css @@ -0,0 +1,88 @@ +.container { + overflow-x: auto; + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; +} + +@media (max-width: 590px) { + .container { + width: 90vw; + } +} + +.group { + display: flex; + flex-direction: column; + gap: 5px; +} + +.group-category { + font-size: 1rem; + text-align: center; + margin-top: 15px; + margin-bottom: 7px; + text-transform: capitalize; +} + +.actionBinds { + position: relative; + display: flex; +} + +.warning-container { + flex-basis: 25%; + display: flex; + flex-direction: column; + height: inherit; +} + +.actionName { + flex-basis: 30%; + margin-right: 5px; + flex-wrap: wrap; + align-self: center; + font-size: 10px; +} + +.undo-keyboard, +.undo-gamepad { + aspect-ratio: 1; +} + +.button { + width: 100%; + font-size: 7px; +} + +.margin-left { + margin-left: 25px; +} + +.matched-bind { + border: 1px solid red; + border-bottom: 1px solid red; +} + +.matched-bind-warning { + display: flex; + color: yellow; + font-family: inherit; + font-size: 5px; + width: fit-content; +} + +.matched-bind-warning a { + color: inherit; +} + +/* ~~~~ custom bindings styles */ + +.chat-command { + font: inherit; + color: white; + display: block; + height: 100%; + flex-grow: 1; +} diff --git a/src/react/KeybindingsScreen.tsx b/src/react/KeybindingsScreen.tsx index 19038a71..97126655 100644 --- a/src/react/KeybindingsScreen.tsx +++ b/src/react/KeybindingsScreen.tsx @@ -1,12 +1,382 @@ +import { useState, useEffect, useRef, createContext, useContext } from 'react' +import { UserOverridesConfig } from 'contro-max/build/types/store' +import { contro as controEx } from '../controls' +import { hideModal } from '../globalState' +import triangle from './ps_icons/playstation_triangle_console_controller_gamepad_icon.svg' +import square from './ps_icons/playstation_square_console_controller_gamepad_icon.svg' +import circle from './ps_icons/circle_playstation_console_controller_gamepad_icon.svg' +import cross from './ps_icons/cross_playstation_console_controller_gamepad_icon.svg' +import PixelartIcon from './PixelartIcon' +import KeybindingsCustom, { CustomCommandsMap } from './KeybindingsCustom' +import { BindingActionsContext } from './KeybindingsScreenProvider' +import Button from './Button' import Screen from './Screen' +import styles from './KeybindingsScreen.module.css' -export default ({ - onBack, - onReset, - onSet, - keybindings -}) => { - return -

Here you can change the keybindings for the game.

-
+ +type HandleClick = (group: string, action: string, index: number, type: string | null) => void + +type setBinding = (data: any, group: string, command: string, buttonIndex: number) => void + +export const Context = createContext( + { + isPS: false as boolean | undefined, + userConfig: controEx?.userConfig ?? {} as UserOverridesConfig | undefined, + setUserConfig (config) { }, + handleClick: (() => { }) as HandleClick, + parseBindingName (binding) { return '' as string }, + bindsMap: { keyboard: {} as any, gamepad: {} as any } + } +) + +export default ( + { + contro, + isPS, + }: { + contro: typeof controEx, + isPS?: boolean + } +) => { + const containerRef = useRef(null) + const bindsMap = useRef({ keyboard: {} as any, gamepad: {} as any }) + const { commands } = contro.inputSchema + const [userConfig, setUserConfig] = useState(contro.userConfig ?? {}) + const [awaitingInputType, setAwaitingInputType] = useState(null as null | 'keyboard' | 'gamepad') + const [groupName, setGroupName] = useState('') + const [actionName, setActionName] = useState('') + const [buttonNum, setButtonNum] = useState(0) + const { updateBinds } = useContext(BindingActionsContext) + const [customCommands, setCustomCommands] = useState(userConfig.custom as CustomCommandsMap ?? {}) + + const updateCurrBind = (group: string, action: string) => { + setGroupName(prev => group) + setActionName(prev => action) + } + + const handleClick: HandleClick = (group, action, index, type) => { + //@ts-expect-error + setAwaitingInputType(type) + updateCurrBind(group, action) + setButtonNum(prev => index) + } + + const setBinding: setBinding = (data, group, command, buttonIndex) => { + setUserConfig(prev => { + const newConfig = { ...prev } + newConfig[group] ??= {} + newConfig[group][command] ??= {} + + // keys and buttons should always exist in commands + const type = 'code' in data ? 'keys' : 'button' in data ? 'gamepad' : null + if (type) { + newConfig[group][command][type] ??= group === 'custom' ? [] : [...contro.inputSchema.commands[group][command][type]] + newConfig[group][command][type]![buttonIndex] = data.code ?? data.button + } + + return newConfig + }) + } + + const resetBinding = (group: string, command: string, inputType: string) => { + if (!userConfig?.[group]?.[command]) return + + setUserConfig(prev => { + const newConfig = { ...prev } + const prop = inputType === 'keyboard' ? 'keys' : 'gamepad' + newConfig[group][command][prop] = undefined + return newConfig + }) + } + + useEffect(() => { + updateBinds(userConfig) + setCustomCommands({ ...userConfig.custom as CustomCommandsMap }) + + updateBindMap() + }, [userConfig]) + + // const updateKeyboardBinding = (e: import('react').KeyboardEvent) => { + // if (!e.code || e.key === 'Escape' || !awaitingInputType) return + // setBinding({ code: e.code, state: true }, groupName, actionName, buttonNum) + // } + + const updateBinding = (data: any) => { + if ((!data.state && awaitingInputType) || !awaitingInputType) { + setAwaitingInputType(null) + return + } + if ('code' in data) { + if (data.code === 'Escape' || ['Mouse0', 'Mouse1', 'Mouse2'].includes(data.code)) { + setAwaitingInputType(null) + return + } + setBinding({ code: data.code, state: true }, groupName, actionName, buttonNum) + } + if ('button' in data) { + contro.enabled = false + void Promise.resolve().then(() => { contro.enabled = true }) + setBinding(data, groupName, actionName, buttonNum) + } + + setAwaitingInputType(null) + } + + const updateBindMap = () => { + bindsMap.current = { keyboard: {} as any, gamepad: {} as any } + if (commands) { + for (const [group, actions] of Object.entries(commands)) { + for (const [action, { keys, gamepad }] of Object.entries(actions)) { + if (keys) { + let currKeys + if (userConfig?.[group]?.[action]?.keys) { + currKeys = userConfig[group][action].keys + } else { + currKeys = keys + } + for (const [index, key] of currKeys.entries()) { + bindsMap.current.keyboard[key] ??= [] + if (!bindsMap.current.keyboard[key].some(obj => obj.group === group && obj.action === action && obj.index === index)) { + bindsMap.current.keyboard[key].push({ group, action, index }) + } + } + } + if (gamepad) { + let currButtons + if (userConfig?.[group]?.[action]?.gamepad) { + currButtons = userConfig[group][action].gamepad + } else { + currButtons = gamepad + } + if (currButtons.length > 0) { + bindsMap.current.gamepad[currButtons[0]] ??= [] + bindsMap.current.gamepad[currButtons[0]].push({ group, action, index: 0 }) + } + } + } + } + } + } + + // fill binds map + useEffect(() => { + updateBindMap() + }, []) + + useEffect(() => { + contro.on('pressedKeyOrButtonChanged', updateBinding) + + return () => { + contro.off('pressedKeyOrButtonChanged', updateBinding) + } + }, [groupName, actionName, awaitingInputType]) + + + return + + {awaitingInputType && } +
+ + + {Object.entries(commands).map(([group, actions], index) => { + if (group === 'custom') return null + return
+
{group}
+ {group === 'general' ? ( +
+ Note: Left, right and middle click keybindings are hardcoded and cannot be changed currently. +
+ ) : null} + {Object.entries(actions).map(([action, { keys, gamepad }]) => { + return
+
{parseActionName(action)}
+ +
+ })} +
+ })} + + +
+
+
+} + +export const ButtonWithMatchesAlert = ({ + group, + action, + index, + inputType, + keys, + gamepad, +}) => { + const { isPS, userConfig, handleClick, parseBindingName, bindsMap } = useContext(Context) + const [buttonSign, setButtonSign] = useState('') + + useEffect(() => { + const type = inputType === 'keyboard' ? 'keys' : 'gamepad' + + const customValue = userConfig?.[group]?.[action]?.[type]?.[index] + if (customValue) { + if (type === 'keys') { + setButtonSign(parseBindingName(customValue)) + } else { + setButtonSign(isPS && buttonsMap[customValue] ? buttonsMap[customValue] : customValue) + } + } else if (type === 'keys') { + setButtonSign(keys?.length ? parseBindingName(keys[index]) : '') + } else { + setButtonSign(gamepad?.[0] ? + isPS ? + buttonsMap[gamepad[0]] ?? gamepad[0] + : gamepad[0] + : '') + } + }, [userConfig, isPS]) + + return
+ + {userConfig?.[group]?.[action]?.[inputType === 'keyboard' ? 'keys' : 'gamepad']?.some( + key => Object.keys(bindsMap[inputType]).includes(key) + && bindsMap[inputType][key].length > 1 + && bindsMap[inputType][key].some( + prop => prop.index === index + && prop.group === group + && prop.action === action + ) + ) ? ( +
+ +
+ This bind is already in use. +
+
+ ) : null} +
+} + +export const AwaitingInputOverlay = ({ isGamepad }) => { + return
+
+ {isGamepad ? 'Press the button on the gamepad ' : 'Press the key, side mouse button '} + or ESC to cancel. +
+ +
+} + +const parseActionName = (action: string) => { + const parts = action.split(/(?=[A-Z])/) + parts[0] = parts[0].charAt(0).toUpperCase() + parts[0].slice(1) + return parts.join(' ') +} + +const parseBindingName = (binding: string | undefined) => { + if (!binding) return '' + const cut = binding.replaceAll(/(Numpad|Digit|Key)/g, '') + const parts = cut.split(/(?=[A-Z\d])/) + return parts.reverse().join(' ') +} + +const buttonsMap = { + 'A': cross, + 'B': circle, + 'X': square, + 'Y': triangle } diff --git a/src/react/KeybindingsScreenApp.tsx b/src/react/KeybindingsScreenApp.tsx deleted file mode 100644 index e0630eab..00000000 --- a/src/react/KeybindingsScreenApp.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { useState } from 'react' -import { contro } from '../controls' -import Button from './Button' -import Screen from './Screen' - -export default () => { - const { commands } = contro.inputSchema - const [awaitingInputType, setAwaitingInputType] = useState(null as null | 'keyboard' | 'gamepad') - - // const - - return - {awaitingInputType && } -

Here you can change the keybindings for the game.

-
- {Object.entries(commands).map(([group, actions]) => { - return
-

{group}

- {Object.entries(actions).map(([action, { keys, gamepadButtons }]) => { - return
- - -
- })} -
- })} -
-
-} - -const AwaitingInputOverlay = ({ isGamepad }) => { - return
- {isGamepad ? 'Press the button on the gamepad' : 'Press the key'}. - Press ESC to cancel. -
-} diff --git a/src/react/KeybindingsScreenProvider.tsx b/src/react/KeybindingsScreenProvider.tsx new file mode 100644 index 00000000..97f04a62 --- /dev/null +++ b/src/react/KeybindingsScreenProvider.tsx @@ -0,0 +1,50 @@ +import { createContext, useState } from 'react' +import { contro } from '../controls' +import KeybindingsScreen from './KeybindingsScreen' +import { useIsModalActive } from './utilsApp' + + +export const updateBinds = (commands: any) => { + contro.inputSchema.commands.custom = Object.fromEntries(Object.entries(commands?.custom ?? {}).map(([key, value]) => { + return [key, { + keys: [], + gamepad: [], + type: '', + inputs: [] + }] + })) + + for (const [group, actions] of Object.entries(commands)) { + contro.userConfig![group] = Object.fromEntries(Object.entries(actions).map(([key, value]) => { + const newValue = { + keys: value?.keys ?? undefined, + gamepad: value?.gamepad ?? undefined, + } + + if (group === 'custom') { + newValue['type'] = (value).type + newValue['inputs'] = (value).inputs + } + + return [key, newValue] + })) + } +} + +const bindingActions = { + updateBinds +} + +export const BindingActionsContext = createContext(bindingActions) + +export default () => { + const [bindActions, setBindActions] = useState(bindingActions) + const isModalActive = useIsModalActive('keybindings') + + if (!isModalActive) return null + + const hasPsGamepad = [...(navigator.getGamepads?.() ?? [])].some(gp => gp?.id.match(/playstation|dualsense|dualshock/i)) // todo: use last used gamepad detection + return + + +} diff --git a/src/react/OptionsGroup.tsx b/src/react/OptionsGroup.tsx index bbfac00e..81df531b 100644 --- a/src/react/OptionsGroup.tsx +++ b/src/react/OptionsGroup.tsx @@ -3,7 +3,7 @@ import { options } from '../optionsStorage' import { OptionsGroupType, guiOptionsScheme } from '../optionsGuiScheme' import OptionsItems, { OptionMeta } from './OptionsItems' -const optionValueToType = (optionValue: any, item: OptionMeta) => { +export const optionValueToType = (optionValue: any, item: OptionMeta) => { if (typeof optionValue === 'boolean' || item.values) return 'toggle' if (typeof optionValue === 'number') return 'slider' if (typeof optionValue === 'string') return 'element' diff --git a/src/react/globals.d.ts b/src/react/globals.d.ts index 842d27c4..108fae54 100644 --- a/src/react/globals.d.ts +++ b/src/react/globals.d.ts @@ -25,6 +25,10 @@ declare module '*.png' { const png: string export default png } +declare module '*.svg' { + const svg: string + export default svg +} interface PromiseConstructor { withResolvers (): { diff --git a/src/react/ps_icons/circle_playstation_console_controller_gamepad_icon.svg b/src/react/ps_icons/circle_playstation_console_controller_gamepad_icon.svg new file mode 100644 index 00000000..d49af336 --- /dev/null +++ b/src/react/ps_icons/circle_playstation_console_controller_gamepad_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/react/ps_icons/cross_playstation_console_controller_gamepad_icon.svg b/src/react/ps_icons/cross_playstation_console_controller_gamepad_icon.svg new file mode 100644 index 00000000..d7d176e2 --- /dev/null +++ b/src/react/ps_icons/cross_playstation_console_controller_gamepad_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/react/ps_icons/playstation_square_console_controller_gamepad_icon.svg b/src/react/ps_icons/playstation_square_console_controller_gamepad_icon.svg new file mode 100644 index 00000000..9f08790e --- /dev/null +++ b/src/react/ps_icons/playstation_square_console_controller_gamepad_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/react/ps_icons/playstation_triangle_console_controller_gamepad_icon.svg b/src/react/ps_icons/playstation_triangle_console_controller_gamepad_icon.svg new file mode 100644 index 00000000..a397c517 --- /dev/null +++ b/src/react/ps_icons/playstation_triangle_console_controller_gamepad_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/react/storageProvider.ts b/src/react/storageProvider.ts new file mode 100644 index 00000000..df97d228 --- /dev/null +++ b/src/react/storageProvider.ts @@ -0,0 +1,13 @@ +import { CustomCommand } from './KeybindingsCustom' + +type StorageData = { + customCommands: Record + // ... +} + +export const getStoredValue = (name: T): StorageData[T] | undefined => { + return localStorage[name] ? JSON.parse(localStorage[name]) : undefined +} +export const setStoredValue = (name: T, value: StorageData[T]) => { + localStorage[name] = JSON.stringify(value) +} diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 9a79de34..e384fbfd 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -36,6 +36,7 @@ import Crosshair from './react/Crosshair' import ButtonAppProvider from './react/ButtonAppProvider' import ServersListProvider from './react/ServersListProvider' import GamepadUiCursor from './react/GamepadUiCursor' +import KeybindingsScreenProvider from './react/KeybindingsScreenProvider' import HeldMapUi from './react/HeldMapUi' const RobustPortal = ({ children, to }) => { @@ -157,6 +158,7 @@ const App = () => { + diff --git a/src/screens.css b/src/screens.css index c4e7fe9b..32765506 100644 --- a/src/screens.css +++ b/src/screens.css @@ -33,6 +33,7 @@ margin-top: 35px; /* todo remove it but without it in chrome android the screen is not scrollable */ overflow: auto; + height: fit-content; /* todo I'm not sure about it */ /* margin-top: calc(100% / 6 - 16px); */ align-items: center; From 97ca34e8f93002d6e54e2c842d13cd4d7cd3ee0e Mon Sep 17 00:00:00 2001 From: Vitaly Date: Sun, 19 May 2024 15:32:50 +0300 Subject: [PATCH 0092/1097] hotfix: input handler crash --- src/controls.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controls.ts b/src/controls.ts index 6e38b90c..7d1e4cdf 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -297,7 +297,7 @@ const customCommandsHandler = (buttonData: { code?: string, button?: string, sta const codeOrButton = buttonData.code ?? buttonData.button const inputType = buttonData.code ? 'keys' : 'gamepad' - for (const value of Object.values(contro.userConfig!.custom)) { + for (const value of Object.values(contro.userConfig!.custom ?? {})) { if (value[inputType]?.includes(codeOrButton!)) { customCommandsConfig[(value as CustomCommand).type].handler((value as CustomCommand).inputs) } From 2bec255b7da0c9142c606cc3c0d9a93fd8cc4cba Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 20 May 2024 05:47:38 +0300 Subject: [PATCH 0093/1097] fix: update flying-squid to respect time in saves! --- package.json | 2 +- pnpm-lock.yaml | 36 +++++-------------- .../viewer/lib/worldDataEmitter.ts | 1 + 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index 6905a8b7..6e73b981 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "esbuild-plugin-polyfill-node": "^0.3.0", "express": "^4.18.2", "filesize": "^10.0.12", - "flying-squid": "npm:@zardoy/flying-squid@^0.0.20", + "flying-squid": "npm:@zardoy/flying-squid@^0.0.24", "fs-extra": "^11.1.1", "google-drive-browserfs": "github:zardoy/browserfs#google-drive", "iconify-icon": "^1.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dcacb13a..6d784e17 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,8 +104,8 @@ importers: specifier: ^10.0.12 version: 10.0.12 flying-squid: - specifier: npm:@zardoy/flying-squid@^0.0.20 - version: '@zardoy/flying-squid@0.0.20(encoding@0.1.13)' + specifier: npm:@zardoy/flying-squid@^0.0.24 + version: '@zardoy/flying-squid@0.0.24(encoding@0.1.13)' fs-extra: specifier: ^11.1.1 version: 11.1.1 @@ -3054,8 +3054,8 @@ packages: resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==} engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'} - '@zardoy/flying-squid@0.0.20': - resolution: {integrity: sha512-WyejZS2Upzv86g6Ez5Z/4Pd0ea9tkFL2itAj24UNpO7fyzxuTN2Ag1Ouvh+MSkCloXhR4E/yoER2krHW8vzwBw==} + '@zardoy/flying-squid@0.0.24': + resolution: {integrity: sha512-C+VNHyh9yYB7aG9OL6r9NR5bF73fyRQ0rHhkvvz901hLBZI3+5nOPdcA6XwJm9XX9BYStXbLTHp6shmo20JRHQ==} engines: {node: '>=8'} hasBin: true @@ -3274,9 +3274,6 @@ packages: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} - asap@1.0.0: - resolution: {integrity: sha512-Ej9qjcXY+8Tuy1cNqiwNMwFRXOy9UwgTeMA8LxreodygIPV48lx8PU1ecFxb5ZeU1DpMKxiq6vGLTxcitWZPbA==} - asn1.js@5.4.1: resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} @@ -4551,9 +4548,6 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - event-promise@0.0.1: - resolution: {integrity: sha512-ouEmk2N0BalybPM0zmj3RHE93AX4p9hAIHZfbbqxolLChqCB6pcLDbYH6zZ8TaiFWImPHfs5kFnNpA0u9RdEaQ==} - event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -6801,9 +6795,6 @@ packages: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} - promise@5.0.0: - resolution: {integrity: sha512-N2BfLz0Sigf7rsm5NnItRwTNqEDUF2ephwEXTcOAf2cO9NwZ9TnIjOmnQNtC0r70CV0S1+uc9mSMmFH7gxk87Q==} - prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -11443,8 +11434,7 @@ snapshots: magic-string: 0.25.9 string.prototype.matchall: 4.0.10 - '@tootallnate/once@2.0.0': - optional: true + '@tootallnate/once@2.0.0': {} '@tweenjs/tween.js@18.6.4': {} @@ -11935,18 +11925,18 @@ snapshots: '@types/emscripten': 1.39.8 tslib: 1.14.1 - '@zardoy/flying-squid@0.0.20(encoding@0.1.13)': + '@zardoy/flying-squid@0.0.24(encoding@0.1.13)': dependencies: + '@tootallnate/once': 2.0.0 change-case: 4.1.2 colors: 1.4.0 diamond-square: https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687 emit-then: 2.0.0 - event-promise: 0.0.1 exit-hook: 2.2.1 flatmap: 0.0.3 long: 5.2.3 minecraft-data: 3.65.0 - minecraft-protocol: 1.47.0(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 @@ -12212,8 +12202,6 @@ snapshots: arrify@1.0.1: {} - asap@1.0.0: {} - asn1.js@5.4.1: dependencies: bn.js: 4.12.0 @@ -13950,10 +13938,6 @@ snapshots: etag@1.8.1: {} - event-promise@0.0.1: - dependencies: - promise: 5.0.0 - event-target-shim@5.0.1: {} eventemitter2@6.4.7: {} @@ -16638,10 +16622,6 @@ snapshots: retry: 0.12.0 optional: true - promise@5.0.0: - dependencies: - asap: 1.0.0 - prompts@2.4.2: dependencies: kleur: 3.0.3 diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index f4ce9675..40cc3413 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -87,6 +87,7 @@ export class WorldDataEmitter extends EventEmitter { }, })) this.emitter.emit('renderDistance', this.viewDistance) + this.emitter.emit('time', bot.time.timeOfDay) }) // node.js stream data event pattern if (this.emitter.listenerCount('blockEntities')) { From 5e9423909167090b244b26b4493d8a6336d4751c Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 20 May 2024 05:47:53 +0300 Subject: [PATCH 0094/1097] feat: big fix: rendering blocks for preflat versions (<1.13)! (#125) --- prismarine-viewer/buildMesherWorker.mjs | 2 + prismarine-viewer/viewer/lib/mesher/mesher.ts | 1 + prismarine-viewer/viewer/lib/mesher/models.ts | 76 +- prismarine-viewer/viewer/lib/mesher/world.ts | 39 +- prismarine-viewer/viewer/lib/viewer.ts | 4 +- .../viewer/prepare/generateTextures.ts | 5 + scripts/esbuildPlugins.mjs | 24 +- src/preflatMap.json | 1741 +++++++++++++++++ 8 files changed, 1880 insertions(+), 12 deletions(-) create mode 100644 src/preflatMap.json diff --git a/prismarine-viewer/buildMesherWorker.mjs b/prismarine-viewer/buildMesherWorker.mjs index 819324de..e9f6a16f 100644 --- a/prismarine-viewer/buildMesherWorker.mjs +++ b/prismarine-viewer/buildMesherWorker.mjs @@ -6,6 +6,7 @@ import path from 'path' import { fileURLToPath } from 'url' import fs from 'fs' import { dynamicMcDataFiles } from './buildMesherConfig.mjs' +import { mesherSharedPlugins } from '../scripts/esbuildPlugins.mjs' const allowedBundleFiles = ['legacy', 'versions', 'protocolVersions', 'features'] @@ -34,6 +35,7 @@ const buildOptions = { 'process.env.BROWSER': '"true"', }, plugins: [ + ...mesherSharedPlugins, { name: 'external-json', setup (build) { diff --git a/prismarine-viewer/viewer/lib/mesher/mesher.ts b/prismarine-viewer/viewer/lib/mesher/mesher.ts index 0bcf7250..bc1d3bbb 100644 --- a/prismarine-viewer/viewer/lib/mesher/mesher.ts +++ b/prismarine-viewer/viewer/lib/mesher/mesher.ts @@ -53,6 +53,7 @@ self.onmessage = ({ data }) => { if (data.config) { world ??= new World(data.config.version) world.config = {...world.config, ...data.config} + globalThis.world = world } if (data.type === 'mesherData') { diff --git a/prismarine-viewer/viewer/lib/mesher/models.ts b/prismarine-viewer/viewer/lib/mesher/models.ts index bfb96d11..40b82ea2 100644 --- a/prismarine-viewer/viewer/lib/mesher/models.ts +++ b/prismarine-viewer/viewer/lib/mesher/models.ts @@ -1,7 +1,9 @@ import { Vec3 } from 'vec3' import type { BlockStatesOutput } from '../../prepare/modelsBuilder' import { World } from './world' -import { Block } from 'prismarine-block' +import { WorldBlock as Block } from './world' +import legacyJson from '../../../../src/preflatMap.json' +import { versionToNumber } from '../../prepare/utils' const tints: any = {} let blockStates: BlockStatesOutput @@ -33,6 +35,53 @@ function prepareTints (tints) { }) } +const calculatedBlocksEntries = Object.entries(legacyJson.clientCalculatedBlocks); +export function preflatBlockCalculation (block: Block, world: World, position: Vec3) { + const type = calculatedBlocksEntries.find(([name, blocks]) => blocks.includes(block.name))?.[0] + if (!type) return + switch (type) { + case 'directional': { + const isSolidConnection = !block.name.includes('redstone') && !block.name.includes('tripwire') + const neighbors = [ + world.getBlock(position.offset(0, 0, 1)), + world.getBlock(position.offset(0, 0, -1)), + world.getBlock(position.offset(1, 0, 0)), + world.getBlock(position.offset(-1, 0, 0)) + ] + // set needed props to true: east:'false',north:'false',south:'false',west:'false' + const props = {} + for (const [i, neighbor] of neighbors.entries()) { + const isConnectedToSolid = isSolidConnection ? (neighbor && !neighbor.transparent) : false + if (isConnectedToSolid || neighbor?.name === block.name) { + props[['south', 'north', 'east', 'west'][i]] = 'true' + } + } + return props + } + // case 'gate_in_wall': {} + case 'block_snowy': { + const aboveIsSnow = world.getBlock(position.offset(0, 1, 0))?.name === 'snow' + return { + snowy: `${aboveIsSnow}` + } + } + case 'door': { + // upper half matches lower in + const half = block.getProperties().half + if (half === 'upper') { + // copy other properties + const lower = world.getBlock(position.offset(0, -1, 0)) + if (lower?.name === block.name) { + return { + ...lower.getProperties(), + half: 'upper' + } + } + } + } + } +} + function tintToGl (tint) { const r = (tint >> 16) & 0xff const g = (tint >> 8) & 0xff @@ -349,7 +398,7 @@ function renderElement (world: World, cursor: Vec3, element, doAO: boolean, attr const aos: number[] = [] const neighborPos = position.plus(new Vec3(...dir)) - const baseLight = world.getLight(neighborPos) / 15 + const baseLight = world.getLight(neighborPos, undefined, undefined, block.name) / 15 for (const pos of corners) { let vertex = [ (pos[0] ? maxx : minx), @@ -462,7 +511,7 @@ export function getSectionGeometry (sx, sy, sz, world: World) { for (cursor.z = sz; cursor.z < sz + 16; cursor.z++) { for (cursor.x = sx; cursor.x < sx + 16; cursor.x++) { const block = world.getBlock(cursor)! - if (block.name.includes('_sign')) { + if (block.name.includes('_sign') || block.name === 'sign') { const key = `${cursor.x},${cursor.y},${cursor.z}` const props: any = block.getProperties() const facingRotationMap = { @@ -478,7 +527,24 @@ export function getSectionGeometry (sx, sy, sz, world: World) { } } const biome = block.biome.name - if (block.variant === undefined) { + + let preflatRecomputeVariant = !!(block as any)._originalProperties + if (world.preflat) { + const patchProperties = preflatBlockCalculation(block, world, cursor) + if (patchProperties) { + //@ts-ignore + block._originalProperties ??= block._properties + //@ts-ignore + block._properties = { ...block._originalProperties, ...patchProperties } + preflatRecomputeVariant = true + } else { + //@ts-ignore + block._properties = block._originalProperties ?? block._properties + //@ts-ignore + block._originalProperties = undefined + } + } + if (block.variant === undefined || preflatRecomputeVariant) { block.variant = getModelVariants(block) } @@ -592,7 +658,7 @@ function matchProperties (block: Block, /* to match against */properties: Record return true } -function getModelVariants (block: import('prismarine-block').Block) { +function getModelVariants (block: Block) { // air, cave_air, void_air and so on... // full list of invisible & special blocks https://minecraft.wiki/w/Model#Blocks_and_fluids if (block.name === '' || block.name === 'air' || block.name.endsWith('_air')) return [] diff --git a/prismarine-viewer/viewer/lib/mesher/world.ts b/prismarine-viewer/viewer/lib/mesher/world.ts index 9a4f0ab3..5f3a281d 100644 --- a/prismarine-viewer/viewer/lib/mesher/world.ts +++ b/prismarine-viewer/viewer/lib/mesher/world.ts @@ -4,6 +4,7 @@ import { Block } from "prismarine-block" import { Vec3 } from 'vec3' import moreBlockDataGeneratedJson from '../moreBlockDataGenerated.json' import { defaultMesherConfig } from './shared' +import legacyJson from '../../../../src/preflatMap.json' const ignoreAoBlocks = Object.keys(moreBlockDataGeneratedJson.noOcclusions) @@ -17,7 +18,7 @@ function isCube (shapes) { return shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1 } -export type WorldBlock = Block & { +export type WorldBlock = Omit & { variant?: any // todo isCube: boolean @@ -30,14 +31,16 @@ export class World { columns = {} as { [key: string]: import('prismarine-chunk/types/index').PCChunk } blockCache = {} biomeCache: { [id: number]: mcData.Biome } + preflat: boolean constructor(version) { this.Chunk = Chunks(version) as any this.biomeCache = mcData(version).biomes + this.preflat = !mcData(version).supportFeature('blockStateId') this.config.version = version } - getLight (pos: Vec3, isNeighbor = false) { + getLight (pos: Vec3, isNeighbor = false, skipMoreChecks = false, curBlockName = '') { const { enableLighting, skyLight } = this.config if (!enableLighting) return 15 // const key = `${pos.x},${pos.y},${pos.z}` @@ -52,8 +55,17 @@ export class World { ) + 2 ) // lightsCache.set(key, result) - if (result === 2 && this.getBlock(pos)?.name.match(/_stairs|slab/)) { // todo this is obviously wrong - result = this.getLight(pos.offset(0, 1, 0)) + if (result === 2 && [this.getBlock(pos)?.name ?? '', curBlockName].some(x => x.match(/_stairs|slab|glass_pane/)) && !skipMoreChecks) { // todo this is obviously wrong + const lights = [ + this.getLight(pos.offset(0, 1, 0), undefined, true), + this.getLight(pos.offset(0, -1, 0), undefined, true), + this.getLight(pos.offset(0, 0, 1), undefined, true), + this.getLight(pos.offset(0, 0, -1), undefined, true), + this.getLight(pos.offset(1, 0, 0), undefined, true), + this.getLight(pos.offset(-1, 0, 0), undefined, true) + ].filter(x => x !== 2) + const min = Math.min(...lights) + result = min } if (isNeighbor && result === 2) result = 15 // TODO return result @@ -91,6 +103,8 @@ export class World { } getBlock (pos: Vec3): WorldBlock | null { + // for easier testing + if (!(pos instanceof Vec3)) pos = new Vec3(...pos as [number, number, number]) const key = columnKey(Math.floor(pos.x / 16) * 16, Math.floor(pos.z / 16) * 16) const column = this.columns[key] @@ -111,6 +125,23 @@ export class World { throw new Error('position is not reliable, use pos parameter instead of block.position') } }) + if (this.preflat) { + const namePropsStr = legacyJson.blocks[b.type + ':' + b.metadata] || legacyJson.blocks[b.type + ':' + '0'] + b.name = namePropsStr.split('[')[0] + const propsStr = namePropsStr.split('[')?.[1]?.split(']'); + if (propsStr) { + const newProperties = Object.fromEntries(propsStr.join('').split(',').map(x => { + let [key, val] = x.split('=') as any + if (!isNaN(val)) val = parseInt(val) + return [key, val] + })) + //@ts-ignore + b._properties = newProperties + } else { + //@ts-ignore + b._properties = {} + } + } } const block = this.blockCache[stateId] diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts index 65091f3e..2a240104 100644 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ b/prismarine-viewer/viewer/lib/viewer.ts @@ -7,6 +7,7 @@ import EventEmitter from 'events' import { WorldRendererThree } from './worldrendererThree' import { generateSpiralMatrix } from 'flying-squid/dist/utils' import { WorldRendererCommon, WorldRendererConfig, defaultWorldRendererConfig } from './worldrendererCommon' +import { versionToNumber } from '../prepare/utils' export class Viewer { scene: THREE.Scene @@ -76,7 +77,8 @@ export class Viewer { } setVersion (userVersion: string) { - const texturesVersion = getVersion(userVersion) + let texturesVersion = getVersion(userVersion) + if (versionToNumber(userVersion) < versionToNumber('1.13')) texturesVersion = '1.13.2' // we normalize to post-flatenning in mesher console.log('[viewer] Using version:', userVersion, 'textures:', texturesVersion) this.world.setVersion(userVersion, texturesVersion) this.entities.clear() diff --git a/prismarine-viewer/viewer/prepare/generateTextures.ts b/prismarine-viewer/viewer/prepare/generateTextures.ts index 2a196ccb..dc838c65 100644 --- a/prismarine-viewer/viewer/prepare/generateTextures.ts +++ b/prismarine-viewer/viewer/prepare/generateTextures.ts @@ -5,6 +5,7 @@ import mcAssets from 'minecraft-assets' import fs from 'fs-extra' import { prepareMoreGeneratedBlocks } from './moreGeneratedBlocks' import { generateItemsAtlases } from './genItemsAtlas' +import { versionToNumber } from './utils' const publicPath = path.resolve(__dirname, '../../public') @@ -23,6 +24,10 @@ Promise.resolve().then(async () => { if (!mcAssets.versions.includes(version)) { throw new Error(`Version ${version} is not supported by minecraft-assets`) } + if (versionToNumber(version) < versionToNumber('1.13')) { + // we normalize data to 1.13 for pre 1.13 versions + continue + } const assets = mcAssets(version) const { warnings: _warnings } = await prepareMoreGeneratedBlocks(assets) _warnings.forEach(x => warnings.add(x)) diff --git a/scripts/esbuildPlugins.mjs b/scripts/esbuildPlugins.mjs index 999f9dc7..49547ea1 100644 --- a/scripts/esbuildPlugins.mjs +++ b/scripts/esbuildPlugins.mjs @@ -8,6 +8,7 @@ import MCProtocol from 'minecraft-protocol' import MCData from 'minecraft-data' import { throttle } from 'lodash-es' +const __dirname = dirname(new URL(import.meta.url).pathname) const { supportedVersions } = MCProtocol const prod = process.argv.includes('--prod') @@ -26,7 +27,7 @@ export const startWatchingHmr = () => { // 'dist/webglRendererWorker.js': 'webglRendererWorker', } for (const name of Object.keys(eventsPerFile)) { - const file = join('dist', name); + const file = join('dist', name) if (!fs.existsSync(file)) console.warn(`[missing worker] File ${name} does not exist`) fs.watchFile(file, () => { writeToClients({ replace: { type: eventsPerFile[name] } }) @@ -34,8 +35,27 @@ export const startWatchingHmr = () => { } } +/** @type {import('esbuild').Plugin[]} */ +const mesherSharedPlugins = [ + { + name: 'minecraft-data', + setup (build) { + build.onLoad({ + filter: /data[\/\\]pc[\/\\]common[\/\\]legacy.json$/, + }, async (args) => { + const data = fs.readFileSync(join(__dirname, '../src/preflatMap.json'), 'utf8') + return { + contents: `module.exports = ${data}`, + loader: 'js', + } + }) + } + } +] + /** @type {import('esbuild').Plugin[]} */ const plugins = [ + ...mesherSharedPlugins, { name: 'strict-aliases', setup (build) { @@ -339,4 +359,4 @@ const plugins = [ }) ] -export { plugins, connectedClients as clients } +export { plugins, connectedClients as clients, mesherSharedPlugins } diff --git a/src/preflatMap.json b/src/preflatMap.json new file mode 100644 index 00000000..fdf2640f --- /dev/null +++ b/src/preflatMap.json @@ -0,0 +1,1741 @@ +{ + "blocks": { + "0:0": "air", + "1:0": "stone", + "1:1": "granite", + "1:2": "polished_granite", + "1:3": "diorite", + "1:4": "polished_diorite", + "1:5": "andesite", + "1:6": "polished_andesite", + "2:0": "grass_block[snowy=false]", + "3:0": "dirt", + "3:1": "coarse_dirt", + "3:2": "podzol[snowy=false]", + "4:0": "cobblestone", + "5:0": "oak_planks", + "5:1": "spruce_planks", + "5:2": "birch_planks", + "5:3": "jungle_planks", + "5:4": "acacia_planks", + "5:5": "dark_oak_planks", + "6:0": "oak_sapling[stage=0]", + "6:1": "spruce_sapling[stage=0]", + "6:2": "birch_sapling[stage=0]", + "6:3": "jungle_sapling[stage=0]", + "6:4": "acacia_sapling[stage=0]", + "6:5": "dark_oak_sapling[stage=0]", + "6:8": "oak_sapling[stage=1]", + "6:9": "spruce_sapling[stage=1]", + "6:10": "birch_sapling[stage=1]", + "6:11": "jungle_sapling[stage=1]", + "6:12": "acacia_sapling[stage=1]", + "6:13": "dark_oak_sapling[stage=1]", + "7:0": "bedrock", + "8:0": "water[level=0]", + "8:1": "water[level=1]", + "8:2": "water[level=2]", + "8:3": "water[level=3]", + "8:4": "water[level=4]", + "8:5": "water[level=5]", + "8:6": "water[level=6]", + "8:7": "water[level=7]", + "8:8": "water[level=8]", + "8:9": "water[level=9]", + "8:10": "water[level=10]", + "8:11": "water[level=11]", + "8:12": "water[level=12]", + "8:13": "water[level=13]", + "8:14": "water[level=14]", + "8:15": "water[level=15]", + "9:0": "water[level=0]", + "9:1": "water[level=1]", + "9:2": "water[level=2]", + "9:3": "water[level=3]", + "9:4": "water[level=4]", + "9:5": "water[level=5]", + "9:6": "water[level=6]", + "9:7": "water[level=7]", + "9:8": "water[level=8]", + "9:9": "water[level=9]", + "9:10": "water[level=10]", + "9:11": "water[level=11]", + "9:12": "water[level=12]", + "9:13": "water[level=13]", + "9:14": "water[level=14]", + "9:15": "water[level=15]", + "10:0": "lava[level=0]", + "10:1": "lava[level=1]", + "10:2": "lava[level=2]", + "10:3": "lava[level=3]", + "10:4": "lava[level=4]", + "10:5": "lava[level=5]", + "10:6": "lava[level=6]", + "10:7": "lava[level=7]", + "10:8": "lava[level=8]", + "10:9": "lava[level=9]", + "10:10": "lava[level=10]", + "10:11": "lava[level=11]", + "10:12": "lava[level=12]", + "10:13": "lava[level=13]", + "10:14": "lava[level=14]", + "10:15": "lava[level=15]", + "11:0": "lava[level=0]", + "11:1": "lava[level=1]", + "11:2": "lava[level=2]", + "11:3": "lava[level=3]", + "11:4": "lava[level=4]", + "11:5": "lava[level=5]", + "11:6": "lava[level=6]", + "11:7": "lava[level=7]", + "11:8": "lava[level=8]", + "11:9": "lava[level=9]", + "11:10": "lava[level=10]", + "11:11": "lava[level=11]", + "11:12": "lava[level=12]", + "11:13": "lava[level=13]", + "11:14": "lava[level=14]", + "11:15": "lava[level=15]", + "12:0": "sand", + "12:1": "red_sand", + "13:0": "gravel", + "14:0": "gold_ore", + "15:0": "iron_ore", + "16:0": "coal_ore", + "17:0": "oak_log[axis=y]", + "17:1": "spruce_log[axis=y]", + "17:2": "birch_log[axis=y]", + "17:3": "jungle_log[axis=y]", + "17:4": "oak_log[axis=x]", + "17:5": "spruce_log[axis=x]", + "17:6": "birch_log[axis=x]", + "17:7": "jungle_log[axis=x]", + "17:8": "oak_log[axis=z]", + "17:9": "spruce_log[axis=z]", + "17:10": "birch_log[axis=z]", + "17:11": "jungle_log[axis=z]", + "17:12": "oak_bark", + "17:13": "spruce_bark", + "17:14": "birch_bark", + "17:15": "jungle_bark", + "18:0": "oak_leaves[check_decay=false,decayable=true]", + "18:1": "spruce_leaves[check_decay=false,decayable=true]", + "18:2": "birch_leaves[check_decay=false,decayable=true]", + "18:3": "jungle_leaves[check_decay=false,decayable=true]", + "18:4": "oak_leaves[check_decay=false,decayable=false]", + "18:5": "spruce_leaves[check_decay=false,decayable=false]", + "18:6": "birch_leaves[check_decay=false,decayable=false]", + "18:7": "jungle_leaves[check_decay=false,decayable=false]", + "18:8": "oak_leaves[check_decay=true,decayable=true]", + "18:9": "spruce_leaves[check_decay=true,decayable=true]", + "18:10": "birch_leaves[check_decay=true,decayable=true]", + "18:11": "jungle_leaves[check_decay=true,decayable=true]", + "18:12": "oak_leaves[check_decay=true,decayable=false]", + "18:13": "spruce_leaves[check_decay=true,decayable=false]", + "18:14": "birch_leaves[check_decay=true,decayable=false]", + "18:15": "jungle_leaves[check_decay=true,decayable=false]", + "19:0": "sponge", + "19:1": "wet_sponge", + "20:0": "glass", + "21:0": "lapis_ore", + "22:0": "lapis_block", + "23:0": "dispenser[facing=down,triggered=false]", + "23:1": "dispenser[facing=up,triggered=false]", + "23:2": "dispenser[facing=north,triggered=false]", + "23:3": "dispenser[facing=south,triggered=false]", + "23:4": "dispenser[facing=west,triggered=false]", + "23:5": "dispenser[facing=east,triggered=false]", + "23:8": "dispenser[facing=down,triggered=true]", + "23:9": "dispenser[facing=up,triggered=true]", + "23:10": "dispenser[facing=north,triggered=true]", + "23:11": "dispenser[facing=south,triggered=true]", + "23:12": "dispenser[facing=west,triggered=true]", + "23:13": "dispenser[facing=east,triggered=true]", + "24:0": "sandstone", + "24:1": "chiseled_sandstone", + "24:2": "cut_sandstone", + "25:0": "note_block", + "26:0": "red_bed[facing=south,occupied=false,part=foot]", + "26:1": "red_bed[facing=west,occupied=false,part=foot]", + "26:2": "red_bed[facing=north,occupied=false,part=foot]", + "26:3": "red_bed[facing=east,occupied=false,part=foot]", + "26:8": "red_bed[facing=south,occupied=false,part=head]", + "26:9": "red_bed[facing=west,occupied=false,part=head]", + "26:10": "red_bed[facing=north,occupied=false,part=head]", + "26:11": "red_bed[facing=east,occupied=false,part=head]", + "26:12": "red_bed[facing=south,occupied=true,part=head]", + "26:13": "red_bed[facing=west,occupied=true,part=head]", + "26:14": "red_bed[facing=north,occupied=true,part=head]", + "26:15": "red_bed[facing=east,occupied=true,part=head]", + "27:0": "powered_rail[powered=false,shape=north_south]", + "27:1": "powered_rail[powered=false,shape=east_west]", + "27:2": "powered_rail[powered=false,shape=ascending_east]", + "27:3": "powered_rail[powered=false,shape=ascending_west]", + "27:4": "powered_rail[powered=false,shape=ascending_north]", + "27:5": "powered_rail[powered=false,shape=ascending_south]", + "27:8": "powered_rail[powered=true,shape=north_south]", + "27:9": "powered_rail[powered=true,shape=east_west]", + "27:10": "powered_rail[powered=true,shape=ascending_east]", + "27:11": "powered_rail[powered=true,shape=ascending_west]", + "27:12": "powered_rail[powered=true,shape=ascending_north]", + "27:13": "powered_rail[powered=true,shape=ascending_south]", + "28:0": "detector_rail[powered=false,shape=north_south]", + "28:1": "detector_rail[powered=false,shape=east_west]", + "28:2": "detector_rail[powered=false,shape=ascending_east]", + "28:3": "detector_rail[powered=false,shape=ascending_west]", + "28:4": "detector_rail[powered=false,shape=ascending_north]", + "28:5": "detector_rail[powered=false,shape=ascending_south]", + "28:8": "detector_rail[powered=true,shape=north_south]", + "28:9": "detector_rail[powered=true,shape=east_west]", + "28:10": "detector_rail[powered=true,shape=ascending_east]", + "28:11": "detector_rail[powered=true,shape=ascending_west]", + "28:12": "detector_rail[powered=true,shape=ascending_north]", + "28:13": "detector_rail[powered=true,shape=ascending_south]", + "29:0": "sticky_piston[extended=false,facing=down]", + "29:1": "sticky_piston[extended=false,facing=up]", + "29:2": "sticky_piston[extended=false,facing=north]", + "29:3": "sticky_piston[extended=false,facing=south]", + "29:4": "sticky_piston[extended=false,facing=west]", + "29:5": "sticky_piston[extended=false,facing=east]", + "29:8": "sticky_piston[extended=true,facing=down]", + "29:9": "sticky_piston[extended=true,facing=up]", + "29:10": "sticky_piston[extended=true,facing=north]", + "29:11": "sticky_piston[extended=true,facing=south]", + "29:12": "sticky_piston[extended=true,facing=west]", + "29:13": "sticky_piston[extended=true,facing=east]", + "30:0": "cobweb", + "31:0": "dead_bush", + "31:1": "grass", + "31:2": "fern", + "32:0": "dead_bush", + "33:0": "piston[extended=false,facing=down]", + "33:1": "piston[extended=false,facing=up]", + "33:2": "piston[extended=false,facing=north]", + "33:3": "piston[extended=false,facing=south]", + "33:4": "piston[extended=false,facing=west]", + "33:5": "piston[extended=false,facing=east]", + "33:8": "piston[extended=true,facing=down]", + "33:9": "piston[extended=true,facing=up]", + "33:10": "piston[extended=true,facing=north]", + "33:11": "piston[extended=true,facing=south]", + "33:12": "piston[extended=true,facing=west]", + "33:13": "piston[extended=true,facing=east]", + "34:0": "piston_head[facing=down,short=false,type=normal]", + "34:1": "piston_head[facing=up,short=false,type=normal]", + "34:2": "piston_head[facing=north,short=false,type=normal]", + "34:3": "piston_head[facing=south,short=false,type=normal]", + "34:4": "piston_head[facing=west,short=false,type=normal]", + "34:5": "piston_head[facing=east,short=false,type=normal]", + "34:8": "piston_head[facing=down,short=false,type=sticky]", + "34:9": "piston_head[facing=up,short=false,type=sticky]", + "34:10": "piston_head[facing=north,short=false,type=sticky]", + "34:11": "piston_head[facing=south,short=false,type=sticky]", + "34:12": "piston_head[facing=west,short=false,type=sticky]", + "34:13": "piston_head[facing=east,short=false,type=sticky]", + "35:0": "white_wool", + "35:1": "orange_wool", + "35:2": "magenta_wool", + "35:3": "light_blue_wool", + "35:4": "yellow_wool", + "35:5": "lime_wool", + "35:6": "pink_wool", + "35:7": "gray_wool", + "35:8": "light_gray_wool", + "35:9": "cyan_wool", + "35:10": "purple_wool", + "35:11": "blue_wool", + "35:12": "brown_wool", + "35:13": "green_wool", + "35:14": "red_wool", + "35:15": "black_wool", + "36:0": "moving_piston[facing=down,type=normal]", + "36:1": "moving_piston[facing=up,type=normal]", + "36:2": "moving_piston[facing=north,type=normal]", + "36:3": "moving_piston[facing=south,type=normal]", + "36:4": "moving_piston[facing=west,type=normal]", + "36:5": "moving_piston[facing=east,type=normal]", + "36:8": "moving_piston[facing=down,type=sticky]", + "36:9": "moving_piston[facing=up,type=sticky]", + "36:10": "moving_piston[facing=north,type=sticky]", + "36:11": "moving_piston[facing=south,type=sticky]", + "36:12": "moving_piston[facing=west,type=sticky]", + "36:13": "moving_piston[facing=east,type=sticky]", + "37:0": "dandelion", + "38:0": "poppy", + "38:1": "blue_orchid", + "38:2": "allium", + "38:3": "azure_bluet", + "38:4": "red_tulip", + "38:5": "orange_tulip", + "38:6": "white_tulip", + "38:7": "pink_tulip", + "38:8": "oxeye_daisy", + "39:0": "brown_mushroom", + "40:0": "red_mushroom", + "41:0": "gold_block", + "42:0": "iron_block", + "43:0": "stone_slab[type=double]", + "43:1": "sandstone_slab[type=double]", + "43:2": "petrified_oak_slab[type=double]", + "43:3": "cobblestone_slab[type=double]", + "43:4": "brick_slab[type=double]", + "43:5": "stone_brick_slab[type=double]", + "43:6": "nether_brick_slab[type=double]", + "43:7": "quartz_slab[type=double]", + "43:8": "smooth_stone", + "43:9": "smooth_sandstone", + "43:10": "petrified_oak_slab[type=double]", + "43:11": "cobblestone_slab[type=double]", + "43:12": "brick_slab[type=double]", + "43:13": "stone_brick_slab[type=double]", + "43:14": "nether_brick_slab[type=double]", + "43:15": "smooth_quartz", + "44:0": "stone_slab[type=bottom]", + "44:1": "sandstone_slab[type=bottom]", + "44:2": "petrified_oak_slab[type=bottom]", + "44:3": "cobblestone_slab[type=bottom]", + "44:4": "brick_slab[type=bottom]", + "44:5": "stone_brick_slab[type=bottom]", + "44:6": "nether_brick_slab[type=bottom]", + "44:7": "quartz_slab[type=bottom]", + "44:8": "stone_slab[type=top]", + "44:9": "sandstone_slab[type=top]", + "44:10": "petrified_oak_slab[type=top]", + "44:11": "cobblestone_slab[type=top]", + "44:12": "brick_slab[type=top]", + "44:13": "stone_brick_slab[type=top]", + "44:14": "nether_brick_slab[type=top]", + "44:15": "quartz_slab[type=top]", + "45:0": "bricks", + "46:0": "tnt[unstable=false]", + "46:1": "tnt[unstable=true]", + "47:0": "bookshelf", + "48:0": "mossy_cobblestone", + "49:0": "obsidian", + "50:1": "wall_torch[facing=east]", + "50:2": "wall_torch[facing=west]", + "50:3": "wall_torch[facing=south]", + "50:4": "wall_torch[facing=north]", + "50:5": "torch", + "51:0": "fire[age=0,east=false,north=false,south=false,up=false,west=false]", + "51:1": "fire[age=1,east=false,north=false,south=false,up=false,west=false]", + "51:2": "fire[age=2,east=false,north=false,south=false,up=false,west=false]", + "51:3": "fire[age=3,east=false,north=false,south=false,up=false,west=false]", + "51:4": "fire[age=4,east=false,north=false,south=false,up=false,west=false]", + "51:5": "fire[age=5,east=false,north=false,south=false,up=false,west=false]", + "51:6": "fire[age=6,east=false,north=false,south=false,up=false,west=false]", + "51:7": "fire[age=7,east=false,north=false,south=false,up=false,west=false]", + "51:8": "fire[age=8,east=false,north=false,south=false,up=false,west=false]", + "51:9": "fire[age=9,east=false,north=false,south=false,up=false,west=false]", + "51:10": "fire[age=10,east=false,north=false,south=false,up=false,west=false]", + "51:11": "fire[age=11,east=false,north=false,south=false,up=false,west=false]", + "51:12": "fire[age=12,east=false,north=false,south=false,up=false,west=false]", + "51:13": "fire[age=13,east=false,north=false,south=false,up=false,west=false]", + "51:14": "fire[age=14,east=false,north=false,south=false,up=false,west=false]", + "51:15": "fire[age=15,east=false,north=false,south=false,up=false,west=false]", + "52:0": "mob_spawner", + "53:0": "oak_stairs[facing=east,half=bottom,shape=straight]", + "53:1": "oak_stairs[facing=west,half=bottom,shape=straight]", + "53:2": "oak_stairs[facing=south,half=bottom,shape=straight]", + "53:3": "oak_stairs[facing=north,half=bottom,shape=straight]", + "53:4": "oak_stairs[facing=east,half=top,shape=straight]", + "53:5": "oak_stairs[facing=west,half=top,shape=straight]", + "53:6": "oak_stairs[facing=south,half=top,shape=straight]", + "53:7": "oak_stairs[facing=north,half=top,shape=straight]", + "54:2": "chest[facing=north,type=single]", + "54:3": "chest[facing=south,type=single]", + "54:4": "chest[facing=west,type=single]", + "54:5": "chest[facing=east,type=single]", + "55:0": "redstone_wire[east=none,north=none,power=0,south=none,west=none]", + "55:1": "redstone_wire[east=none,north=none,power=1,south=none,west=none]", + "55:2": "redstone_wire[east=none,north=none,power=2,south=none,west=none]", + "55:3": "redstone_wire[east=none,north=none,power=3,south=none,west=none]", + "55:4": "redstone_wire[east=none,north=none,power=4,south=none,west=none]", + "55:5": "redstone_wire[east=none,north=none,power=5,south=none,west=none]", + "55:6": "redstone_wire[east=none,north=none,power=6,south=none,west=none]", + "55:7": "redstone_wire[east=none,north=none,power=7,south=none,west=none]", + "55:8": "redstone_wire[east=none,north=none,power=8,south=none,west=none]", + "55:9": "redstone_wire[east=none,north=none,power=9,south=none,west=none]", + "55:10": "redstone_wire[east=none,north=none,power=10,south=none,west=none]", + "55:11": "redstone_wire[east=none,north=none,power=11,south=none,west=none]", + "55:12": "redstone_wire[east=none,north=none,power=12,south=none,west=none]", + "55:13": "redstone_wire[east=none,north=none,power=13,south=none,west=none]", + "55:14": "redstone_wire[east=none,north=none,power=14,south=none,west=none]", + "55:15": "redstone_wire[east=none,north=none,power=15,south=none,west=none]", + "56:0": "diamond_ore", + "57:0": "diamond_block", + "58:0": "crafting_table", + "59:0": "wheat[age=0]", + "59:1": "wheat[age=1]", + "59:2": "wheat[age=2]", + "59:3": "wheat[age=3]", + "59:4": "wheat[age=4]", + "59:5": "wheat[age=5]", + "59:6": "wheat[age=6]", + "59:7": "wheat[age=7]", + "60:0": "farmland[moisture=0]", + "60:1": "farmland[moisture=1]", + "60:2": "farmland[moisture=2]", + "60:3": "farmland[moisture=3]", + "60:4": "farmland[moisture=4]", + "60:5": "farmland[moisture=5]", + "60:6": "farmland[moisture=6]", + "60:7": "farmland[moisture=7]", + "61:2": "furnace[facing=north,lit=false]", + "61:3": "furnace[facing=south,lit=false]", + "61:4": "furnace[facing=west,lit=false]", + "61:5": "furnace[facing=east,lit=false]", + "62:2": "furnace[facing=north,lit=true]", + "62:3": "furnace[facing=south,lit=true]", + "62:4": "furnace[facing=west,lit=true]", + "62:5": "furnace[facing=east,lit=true]", + "63:0": "sign[rotation=0]", + "63:1": "sign[rotation=1]", + "63:2": "sign[rotation=2]", + "63:3": "sign[rotation=3]", + "63:4": "sign[rotation=4]", + "63:5": "sign[rotation=5]", + "63:6": "sign[rotation=6]", + "63:7": "sign[rotation=7]", + "63:8": "sign[rotation=8]", + "63:9": "sign[rotation=9]", + "63:10": "sign[rotation=10]", + "63:11": "sign[rotation=11]", + "63:12": "sign[rotation=12]", + "63:13": "sign[rotation=13]", + "63:14": "sign[rotation=14]", + "63:15": "sign[rotation=15]", + "64:0": "oak_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "64:1": "oak_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "64:2": "oak_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "64:3": "oak_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "64:4": "oak_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "64:5": "oak_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "64:6": "oak_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "64:7": "oak_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "64:8": "oak_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "64:9": "oak_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "64:10": "oak_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "64:11": "oak_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "65:2": "ladder[facing=north]", + "65:3": "ladder[facing=south]", + "65:4": "ladder[facing=west]", + "65:5": "ladder[facing=east]", + "66:0": "rail[shape=north_south]", + "66:1": "rail[shape=east_west]", + "66:2": "rail[shape=ascending_east]", + "66:3": "rail[shape=ascending_west]", + "66:4": "rail[shape=ascending_north]", + "66:5": "rail[shape=ascending_south]", + "66:6": "rail[shape=south_east]", + "66:7": "rail[shape=south_west]", + "66:8": "rail[shape=north_west]", + "66:9": "rail[shape=north_east]", + "67:0": "cobblestone_stairs[facing=east,half=bottom,shape=straight]", + "67:1": "cobblestone_stairs[facing=west,half=bottom,shape=straight]", + "67:2": "cobblestone_stairs[facing=south,half=bottom,shape=straight]", + "67:3": "cobblestone_stairs[facing=north,half=bottom,shape=straight]", + "67:4": "cobblestone_stairs[facing=east,half=top,shape=straight]", + "67:5": "cobblestone_stairs[facing=west,half=top,shape=straight]", + "67:6": "cobblestone_stairs[facing=south,half=top,shape=straight]", + "67:7": "cobblestone_stairs[facing=north,half=top,shape=straight]", + "68:2": "wall_sign[facing=north]", + "68:3": "wall_sign[facing=south]", + "68:4": "wall_sign[facing=west]", + "68:5": "wall_sign[facing=east]", + "69:0": "lever[face=ceiling,facing=west,powered=false]", + "69:1": "lever[face=wall,facing=east,powered=false]", + "69:2": "lever[face=wall,facing=west,powered=false]", + "69:3": "lever[face=wall,facing=south,powered=false]", + "69:4": "lever[face=wall,facing=north,powered=false]", + "69:5": "lever[face=floor,facing=north,powered=false]", + "69:6": "lever[face=floor,facing=west,powered=false]", + "69:7": "lever[face=ceiling,facing=north,powered=false]", + "69:8": "lever[face=ceiling,facing=west,powered=true]", + "69:9": "lever[face=wall,facing=east,powered=true]", + "69:10": "lever[face=wall,facing=west,powered=true]", + "69:11": "lever[face=wall,facing=south,powered=true]", + "69:12": "lever[face=wall,facing=north,powered=true]", + "69:13": "lever[face=floor,facing=north,powered=true]", + "69:14": "lever[face=floor,facing=west,powered=true]", + "69:15": "lever[face=ceiling,facing=north,powered=true]", + "70:0": "stone_pressure_plate[powered=false]", + "70:1": "stone_pressure_plate[powered=true]", + "71:0": "iron_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "71:1": "iron_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "71:2": "iron_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "71:3": "iron_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "71:4": "iron_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "71:5": "iron_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "71:6": "iron_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "71:7": "iron_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "71:8": "iron_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "71:9": "iron_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "71:10": "iron_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "71:11": "iron_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "72:0": "oak_pressure_plate[powered=false]", + "72:1": "oak_pressure_plate[powered=true]", + "73:0": "redstone_ore[lit=false]", + "74:0": "redstone_ore[lit=true]", + "75:1": "redstone_wall_torch[facing=east,lit=false]", + "75:2": "redstone_wall_torch[facing=west,lit=false]", + "75:3": "redstone_wall_torch[facing=south,lit=false]", + "75:4": "redstone_wall_torch[facing=north,lit=false]", + "75:5": "redstone_torch[lit=false]", + "76:1": "redstone_wall_torch[facing=east,lit=true]", + "76:2": "redstone_wall_torch[facing=west,lit=true]", + "76:3": "redstone_wall_torch[facing=south,lit=true]", + "76:4": "redstone_wall_torch[facing=north,lit=true]", + "76:5": "redstone_torch[lit=true]", + "77:0": "stone_button[face=ceiling,facing=north,powered=false]", + "77:1": "stone_button[face=wall,facing=east,powered=false]", + "77:2": "stone_button[face=wall,facing=west,powered=false]", + "77:3": "stone_button[face=wall,facing=south,powered=false]", + "77:4": "stone_button[face=wall,facing=north,powered=false]", + "77:5": "stone_button[face=floor,facing=north,powered=false]", + "77:8": "stone_button[face=ceiling,facing=north,powered=true]", + "77:9": "stone_button[face=wall,facing=east,powered=true]", + "77:10": "stone_button[face=wall,facing=west,powered=true]", + "77:11": "stone_button[face=wall,facing=south,powered=true]", + "77:12": "stone_button[face=wall,facing=north,powered=true]", + "77:13": "stone_button[face=floor,facing=north,powered=true]", + "78:0": "snow[layers=1]", + "78:1": "snow[layers=2]", + "78:2": "snow[layers=3]", + "78:3": "snow[layers=4]", + "78:4": "snow[layers=5]", + "78:5": "snow[layers=6]", + "78:6": "snow[layers=7]", + "78:7": "snow[layers=8]", + "79:0": "ice", + "80:0": "snow_block", + "81:0": "cactus[age=0]", + "81:1": "cactus[age=1]", + "81:2": "cactus[age=2]", + "81:3": "cactus[age=3]", + "81:4": "cactus[age=4]", + "81:5": "cactus[age=5]", + "81:6": "cactus[age=6]", + "81:7": "cactus[age=7]", + "81:8": "cactus[age=8]", + "81:9": "cactus[age=9]", + "81:10": "cactus[age=10]", + "81:11": "cactus[age=11]", + "81:12": "cactus[age=12]", + "81:13": "cactus[age=13]", + "81:14": "cactus[age=14]", + "81:15": "cactus[age=15]", + "82:0": "clay", + "83:0": "sugar_cane[age=0]", + "83:1": "sugar_cane[age=1]", + "83:2": "sugar_cane[age=2]", + "83:3": "sugar_cane[age=3]", + "83:4": "sugar_cane[age=4]", + "83:5": "sugar_cane[age=5]", + "83:6": "sugar_cane[age=6]", + "83:7": "sugar_cane[age=7]", + "83:8": "sugar_cane[age=8]", + "83:9": "sugar_cane[age=9]", + "83:10": "sugar_cane[age=10]", + "83:11": "sugar_cane[age=11]", + "83:12": "sugar_cane[age=12]", + "83:13": "sugar_cane[age=13]", + "83:14": "sugar_cane[age=14]", + "83:15": "sugar_cane[age=15]", + "84:0": "jukebox[has_record=false]", + "84:1": "jukebox[has_record=true]", + "85:0": "oak_fence[east=false,north=false,south=false,west=false]", + "86:0": "carved_pumpkin[facing=south]", + "86:1": "carved_pumpkin[facing=west]", + "86:2": "carved_pumpkin[facing=north]", + "86:3": "carved_pumpkin[facing=east]", + "87:0": "netherrack", + "88:0": "soul_sand", + "89:0": "glowstone", + "90:1": "portal[axis=x]", + "90:2": "portal[axis=z]", + "91:0": "jack_o_lantern[facing=south]", + "91:1": "jack_o_lantern[facing=west]", + "91:2": "jack_o_lantern[facing=north]", + "91:3": "jack_o_lantern[facing=east]", + "92:0": "cake[bites=0]", + "92:1": "cake[bites=1]", + "92:2": "cake[bites=2]", + "92:3": "cake[bites=3]", + "92:4": "cake[bites=4]", + "92:5": "cake[bites=5]", + "92:6": "cake[bites=6]", + "93:0": "repeater[delay=1,facing=south,locked=false,powered=false]", + "93:1": "repeater[delay=1,facing=west,locked=false,powered=false]", + "93:2": "repeater[delay=1,facing=north,locked=false,powered=false]", + "93:3": "repeater[delay=1,facing=east,locked=false,powered=false]", + "93:4": "repeater[delay=2,facing=south,locked=false,powered=false]", + "93:5": "repeater[delay=2,facing=west,locked=false,powered=false]", + "93:6": "repeater[delay=2,facing=north,locked=false,powered=false]", + "93:7": "repeater[delay=2,facing=east,locked=false,powered=false]", + "93:8": "repeater[delay=3,facing=south,locked=false,powered=false]", + "93:9": "repeater[delay=3,facing=west,locked=false,powered=false]", + "93:10": "repeater[delay=3,facing=north,locked=false,powered=false]", + "93:11": "repeater[delay=3,facing=east,locked=false,powered=false]", + "93:12": "repeater[delay=4,facing=south,locked=false,powered=false]", + "93:13": "repeater[delay=4,facing=west,locked=false,powered=false]", + "93:14": "repeater[delay=4,facing=north,locked=false,powered=false]", + "93:15": "repeater[delay=4,facing=east,locked=false,powered=false]", + "94:0": "repeater[delay=1,facing=south,locked=false,powered=true]", + "94:1": "repeater[delay=1,facing=west,locked=false,powered=true]", + "94:2": "repeater[delay=1,facing=north,locked=false,powered=true]", + "94:3": "repeater[delay=1,facing=east,locked=false,powered=true]", + "94:4": "repeater[delay=2,facing=south,locked=false,powered=true]", + "94:5": "repeater[delay=2,facing=west,locked=false,powered=true]", + "94:6": "repeater[delay=2,facing=north,locked=false,powered=true]", + "94:7": "repeater[delay=2,facing=east,locked=false,powered=true]", + "94:8": "repeater[delay=3,facing=south,locked=false,powered=true]", + "94:9": "repeater[delay=3,facing=west,locked=false,powered=true]", + "94:10": "repeater[delay=3,facing=north,locked=false,powered=true]", + "94:11": "repeater[delay=3,facing=east,locked=false,powered=true]", + "94:12": "repeater[delay=4,facing=south,locked=false,powered=true]", + "94:13": "repeater[delay=4,facing=west,locked=false,powered=true]", + "94:14": "repeater[delay=4,facing=north,locked=false,powered=true]", + "94:15": "repeater[delay=4,facing=east,locked=false,powered=true]", + "95:0": "white_stained_glass", + "95:1": "orange_stained_glass", + "95:2": "magenta_stained_glass", + "95:3": "light_blue_stained_glass", + "95:4": "yellow_stained_glass", + "95:5": "lime_stained_glass", + "95:6": "pink_stained_glass", + "95:7": "gray_stained_glass", + "95:8": "light_gray_stained_glass", + "95:9": "cyan_stained_glass", + "95:10": "purple_stained_glass", + "95:11": "blue_stained_glass", + "95:12": "brown_stained_glass", + "95:13": "green_stained_glass", + "95:14": "red_stained_glass", + "95:15": "black_stained_glass", + "96:0": "oak_trapdoor[facing=north,half=bottom,open=false]", + "96:1": "oak_trapdoor[facing=south,half=bottom,open=false]", + "96:2": "oak_trapdoor[facing=west,half=bottom,open=false]", + "96:3": "oak_trapdoor[facing=east,half=bottom,open=false]", + "96:4": "oak_trapdoor[facing=north,half=bottom,open=true]", + "96:5": "oak_trapdoor[facing=south,half=bottom,open=true]", + "96:6": "oak_trapdoor[facing=west,half=bottom,open=true]", + "96:7": "oak_trapdoor[facing=east,half=bottom,open=true]", + "96:8": "oak_trapdoor[facing=north,half=top,open=false]", + "96:9": "oak_trapdoor[facing=south,half=top,open=false]", + "96:10": "oak_trapdoor[facing=west,half=top,open=false]", + "96:11": "oak_trapdoor[facing=east,half=top,open=false]", + "96:12": "oak_trapdoor[facing=north,half=top,open=true]", + "96:13": "oak_trapdoor[facing=south,half=top,open=true]", + "96:14": "oak_trapdoor[facing=west,half=top,open=true]", + "96:15": "oak_trapdoor[facing=east,half=top,open=true]", + "97:0": "infested_stone", + "97:1": "infested_cobblestone", + "97:2": "infested_stone_bricks", + "97:3": "infested_mossy_stone_bricks", + "97:4": "infested_cracked_stone_bricks", + "97:5": "infested_chiseled_stone_bricks", + "98:0": "stone_bricks", + "98:1": "mossy_stone_bricks", + "98:2": "cracked_stone_bricks", + "98:3": "chiseled_stone_bricks", + "99:0": "brown_mushroom_block[north=false,east=false,south=false,west=false,up=false,down=false]", + "99:1": "brown_mushroom_block[north=true,east=false,south=false,west=true,up=true,down=false]", + "99:2": "brown_mushroom_block[north=true,east=false,south=false,west=false,up=true,down=false]", + "99:3": "brown_mushroom_block[north=true,east=true,south=false,west=false,up=true,down=false]", + "99:4": "brown_mushroom_block[north=false,east=false,south=false,west=true,up=true,down=false]", + "99:5": "brown_mushroom_block[north=false,east=false,south=false,west=false,up=true,down=false]", + "99:6": "brown_mushroom_block[north=false,east=true,south=false,west=false,up=true,down=false]", + "99:7": "brown_mushroom_block[north=false,east=false,south=true,west=true,up=true,down=false]", + "99:8": "brown_mushroom_block[north=false,east=false,south=true,west=false,up=true,down=false]", + "99:9": "brown_mushroom_block[north=false,east=true,south=true,west=false,up=true,down=false]", + "99:10": "mushroom_stem[north=true,east=true,south=true,west=true,up=false,down=false]", + "99:14": "brown_mushroom_block[north=true,east=true,south=true,west=true,up=true,down=true]", + "99:15": "mushroom_stem[north=true,east=true,south=true,west=true,up=true,down=true]", + "100:0": "red_mushroom_block[north=false,east=false,south=false,west=false,up=false,down=false]", + "100:1": "red_mushroom_block[north=true,east=false,south=false,west=true,up=true,down=false]", + "100:2": "red_mushroom_block[north=true,east=false,south=false,west=false,up=true,down=false]", + "100:3": "red_mushroom_block[north=true,east=true,south=false,west=false,up=true,down=false]", + "100:4": "red_mushroom_block[north=false,east=false,south=false,west=true,up=true,down=false]", + "100:5": "red_mushroom_block[north=false,east=false,south=false,west=false,up=true,down=false]", + "100:6": "red_mushroom_block[north=false,east=true,south=false,west=false,up=true,down=false]", + "100:7": "red_mushroom_block[north=false,east=false,south=true,west=true,up=true,down=false]", + "100:8": "red_mushroom_block[north=false,east=false,south=true,west=false,up=true,down=false]", + "100:9": "red_mushroom_block[north=false,east=true,south=true,west=false,up=true,down=false]", + "100:10": "mushroom_stem[north=true,east=true,south=true,west=true,up=false,down=false]", + "100:14": "red_mushroom_block[north=true,east=true,south=true,west=true,up=true,down=true]", + "100:15": "mushroom_stem[north=true,east=true,south=true,west=true,up=true,down=true]", + "101:0": "iron_bars[east=false,north=false,south=false,west=false]", + "102:0": "glass_pane[east=false,north=false,south=false,west=false]", + "103:0": "melon_block", + "104:0": "pumpkin_stem[age=0]", + "104:1": "pumpkin_stem[age=1]", + "104:2": "pumpkin_stem[age=2]", + "104:3": "pumpkin_stem[age=3]", + "104:4": "pumpkin_stem[age=4]", + "104:5": "pumpkin_stem[age=5]", + "104:6": "pumpkin_stem[age=6]", + "104:7": "pumpkin_stem[age=7]", + "105:0": "melon_stem[age=0]", + "105:1": "melon_stem[age=1]", + "105:2": "melon_stem[age=2]", + "105:3": "melon_stem[age=3]", + "105:4": "melon_stem[age=4]", + "105:5": "melon_stem[age=5]", + "105:6": "melon_stem[age=6]", + "105:7": "melon_stem[age=7]", + "106:0": "vine[east=false,north=false,south=false,up=true,west=false]", + "106:1": "vine[east=false,north=false,south=true,up=true,west=false]", + "106:2": "vine[east=false,north=false,south=false,up=true,west=true]", + "106:3": "vine[east=false,north=false,south=true,up=true,west=true]", + "106:4": "vine[east=false,north=true,south=false,up=true,west=false]", + "106:5": "vine[east=false,north=true,south=true,up=true,west=false]", + "106:6": "vine[east=false,north=true,south=false,up=true,west=true]", + "106:7": "vine[east=false,north=true,south=true,up=true,west=true]", + "106:8": "vine[east=true,north=false,south=false,up=true,west=false]", + "106:9": "vine[east=true,north=false,south=true,up=true,west=false]", + "106:10": "vine[east=true,north=false,south=false,up=true,west=true]", + "106:11": "vine[east=true,north=false,south=true,up=true,west=true]", + "106:12": "vine[east=true,north=true,south=false,up=true,west=false]", + "106:13": "vine[east=true,north=true,south=true,up=true,west=false]", + "106:14": "vine[east=true,north=true,south=false,up=true,west=true]", + "106:15": "vine[east=true,north=true,south=true,up=true,west=true]", + "107:0": "oak_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "107:1": "oak_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "107:2": "oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "107:3": "oak_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "107:4": "oak_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "107:5": "oak_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "107:6": "oak_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "107:7": "oak_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "107:8": "oak_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "107:9": "oak_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "107:10": "oak_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "107:11": "oak_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "107:12": "oak_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "107:13": "oak_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "107:14": "oak_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "107:15": "oak_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "108:0": "brick_stairs[facing=east,half=bottom,shape=straight]", + "108:1": "brick_stairs[facing=west,half=bottom,shape=straight]", + "108:2": "brick_stairs[facing=south,half=bottom,shape=straight]", + "108:3": "brick_stairs[facing=north,half=bottom,shape=straight]", + "108:4": "brick_stairs[facing=east,half=top,shape=straight]", + "108:5": "brick_stairs[facing=west,half=top,shape=straight]", + "108:6": "brick_stairs[facing=south,half=top,shape=straight]", + "108:7": "brick_stairs[facing=north,half=top,shape=straight]", + "109:0": "stone_brick_stairs[facing=east,half=bottom,shape=straight]", + "109:1": "stone_brick_stairs[facing=west,half=bottom,shape=straight]", + "109:2": "stone_brick_stairs[facing=south,half=bottom,shape=straight]", + "109:3": "stone_brick_stairs[facing=north,half=bottom,shape=straight]", + "109:4": "stone_brick_stairs[facing=east,half=top,shape=straight]", + "109:5": "stone_brick_stairs[facing=west,half=top,shape=straight]", + "109:6": "stone_brick_stairs[facing=south,half=top,shape=straight]", + "109:7": "stone_brick_stairs[facing=north,half=top,shape=straight]", + "110:0": "mycelium[snowy=false]", + "111:0": "lily_pad", + "112:0": "nether_bricks", + "113:0": "nether_brick_fence[east=false,north=false,south=false,west=false]", + "114:0": "nether_brick_stairs[facing=east,half=bottom,shape=straight]", + "114:1": "nether_brick_stairs[facing=west,half=bottom,shape=straight]", + "114:2": "nether_brick_stairs[facing=south,half=bottom,shape=straight]", + "114:3": "nether_brick_stairs[facing=north,half=bottom,shape=straight]", + "114:4": "nether_brick_stairs[facing=east,half=top,shape=straight]", + "114:5": "nether_brick_stairs[facing=west,half=top,shape=straight]", + "114:6": "nether_brick_stairs[facing=south,half=top,shape=straight]", + "114:7": "nether_brick_stairs[facing=north,half=top,shape=straight]", + "115:0": "nether_wart[age=0]", + "115:1": "nether_wart[age=1]", + "115:2": "nether_wart[age=2]", + "115:3": "nether_wart[age=3]", + "116:0": "enchanting_table", + "117:0": "brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]", + "117:1": "brewing_stand[has_bottle_0=true,has_bottle_1=false,has_bottle_2=false]", + "117:2": "brewing_stand[has_bottle_0=false,has_bottle_1=true,has_bottle_2=false]", + "117:3": "brewing_stand[has_bottle_0=true,has_bottle_1=true,has_bottle_2=false]", + "117:4": "brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=true]", + "117:5": "brewing_stand[has_bottle_0=true,has_bottle_1=false,has_bottle_2=true]", + "117:6": "brewing_stand[has_bottle_0=false,has_bottle_1=true,has_bottle_2=true]", + "117:7": "brewing_stand[has_bottle_0=true,has_bottle_1=true,has_bottle_2=true]", + "118:0": "cauldron[level=0]", + "118:1": "cauldron[level=1]", + "118:2": "cauldron[level=2]", + "118:3": "cauldron[level=3]", + "119:0": "end_portal", + "120:0": "end_portal_frame[eye=false,facing=south]", + "120:1": "end_portal_frame[eye=false,facing=west]", + "120:2": "end_portal_frame[eye=false,facing=north]", + "120:3": "end_portal_frame[eye=false,facing=east]", + "120:4": "end_portal_frame[eye=true,facing=south]", + "120:5": "end_portal_frame[eye=true,facing=west]", + "120:6": "end_portal_frame[eye=true,facing=north]", + "120:7": "end_portal_frame[eye=true,facing=east]", + "121:0": "end_stone", + "122:0": "dragon_egg", + "123:0": "redstone_lamp[lit=false]", + "124:0": "redstone_lamp[lit=true]", + "125:0": "oak_slab[type=double]", + "125:1": "spruce_slab[type=double]", + "125:2": "birch_slab[type=double]", + "125:3": "jungle_slab[type=double]", + "125:4": "acacia_slab[type=double]", + "125:5": "dark_oak_slab[type=double]", + "126:0": "oak_slab[type=bottom]", + "126:1": "spruce_slab[type=bottom]", + "126:2": "birch_slab[type=bottom]", + "126:3": "jungle_slab[type=bottom]", + "126:4": "acacia_slab[type=bottom]", + "126:5": "dark_oak_slab[type=bottom]", + "126:8": "oak_slab[type=top]", + "126:9": "spruce_slab[type=top]", + "126:10": "birch_slab[type=top]", + "126:11": "jungle_slab[type=top]", + "126:12": "acacia_slab[type=top]", + "126:13": "dark_oak_slab[type=top]", + "127:0": "cocoa[age=0,facing=south]", + "127:1": "cocoa[age=0,facing=west]", + "127:2": "cocoa[age=0,facing=north]", + "127:3": "cocoa[age=0,facing=east]", + "127:4": "cocoa[age=1,facing=south]", + "127:5": "cocoa[age=1,facing=west]", + "127:6": "cocoa[age=1,facing=north]", + "127:7": "cocoa[age=1,facing=east]", + "127:8": "cocoa[age=2,facing=south]", + "127:9": "cocoa[age=2,facing=west]", + "127:10": "cocoa[age=2,facing=north]", + "127:11": "cocoa[age=2,facing=east]", + "128:0": "sandstone_stairs[facing=east,half=bottom,shape=straight]", + "128:1": "sandstone_stairs[facing=west,half=bottom,shape=straight]", + "128:2": "sandstone_stairs[facing=south,half=bottom,shape=straight]", + "128:3": "sandstone_stairs[facing=north,half=bottom,shape=straight]", + "128:4": "sandstone_stairs[facing=east,half=top,shape=straight]", + "128:5": "sandstone_stairs[facing=west,half=top,shape=straight]", + "128:6": "sandstone_stairs[facing=south,half=top,shape=straight]", + "128:7": "sandstone_stairs[facing=north,half=top,shape=straight]", + "129:0": "emerald_ore", + "130:2": "ender_chest[facing=north]", + "130:3": "ender_chest[facing=south]", + "130:4": "ender_chest[facing=west]", + "130:5": "ender_chest[facing=east]", + "131:0": "tripwire_hook[attached=false,facing=south,powered=false]", + "131:1": "tripwire_hook[attached=false,facing=west,powered=false]", + "131:2": "tripwire_hook[attached=false,facing=north,powered=false]", + "131:3": "tripwire_hook[attached=false,facing=east,powered=false]", + "131:4": "tripwire_hook[attached=true,facing=south,powered=false]", + "131:5": "tripwire_hook[attached=true,facing=west,powered=false]", + "131:6": "tripwire_hook[attached=true,facing=north,powered=false]", + "131:7": "tripwire_hook[attached=true,facing=east,powered=false]", + "131:8": "tripwire_hook[attached=false,facing=south,powered=true]", + "131:9": "tripwire_hook[attached=false,facing=west,powered=true]", + "131:10": "tripwire_hook[attached=false,facing=north,powered=true]", + "131:11": "tripwire_hook[attached=false,facing=east,powered=true]", + "131:12": "tripwire_hook[attached=true,facing=south,powered=true]", + "131:13": "tripwire_hook[attached=true,facing=west,powered=true]", + "131:14": "tripwire_hook[attached=true,facing=north,powered=true]", + "131:15": "tripwire_hook[attached=true,facing=east,powered=true]", + "132:0": "tripwire[attached=false,disarmed=false,east=false,north=false,powered=false,south=false,west=false]", + "132:1": "tripwire[attached=false,disarmed=false,east=false,north=false,powered=true,south=false,west=false]", + "132:4": "tripwire[attached=true,disarmed=false,east=false,north=false,powered=false,south=false,west=false]", + "132:5": "tripwire[attached=true,disarmed=false,east=false,north=false,powered=true,south=false,west=false]", + "132:8": "tripwire[attached=false,disarmed=true,east=false,north=false,powered=false,south=false,west=false]", + "132:9": "tripwire[attached=false,disarmed=true,east=false,north=false,powered=true,south=false,west=false]", + "132:12": "tripwire[attached=true,disarmed=true,east=false,north=false,powered=false,south=false,west=false]", + "132:13": "tripwire[attached=true,disarmed=true,east=false,north=false,powered=true,south=false,west=false]", + "133:0": "emerald_block", + "134:0": "spruce_stairs[facing=east,half=bottom,shape=straight]", + "134:1": "spruce_stairs[facing=west,half=bottom,shape=straight]", + "134:2": "spruce_stairs[facing=south,half=bottom,shape=straight]", + "134:3": "spruce_stairs[facing=north,half=bottom,shape=straight]", + "134:4": "spruce_stairs[facing=east,half=top,shape=straight]", + "134:5": "spruce_stairs[facing=west,half=top,shape=straight]", + "134:6": "spruce_stairs[facing=south,half=top,shape=straight]", + "134:7": "spruce_stairs[facing=north,half=top,shape=straight]", + "135:0": "birch_stairs[facing=east,half=bottom,shape=straight]", + "135:1": "birch_stairs[facing=west,half=bottom,shape=straight]", + "135:2": "birch_stairs[facing=south,half=bottom,shape=straight]", + "135:3": "birch_stairs[facing=north,half=bottom,shape=straight]", + "135:4": "birch_stairs[facing=east,half=top,shape=straight]", + "135:5": "birch_stairs[facing=west,half=top,shape=straight]", + "135:6": "birch_stairs[facing=south,half=top,shape=straight]", + "135:7": "birch_stairs[facing=north,half=top,shape=straight]", + "136:0": "jungle_stairs[facing=east,half=bottom,shape=straight]", + "136:1": "jungle_stairs[facing=west,half=bottom,shape=straight]", + "136:2": "jungle_stairs[facing=south,half=bottom,shape=straight]", + "136:3": "jungle_stairs[facing=north,half=bottom,shape=straight]", + "136:4": "jungle_stairs[facing=east,half=top,shape=straight]", + "136:5": "jungle_stairs[facing=west,half=top,shape=straight]", + "136:6": "jungle_stairs[facing=south,half=top,shape=straight]", + "136:7": "jungle_stairs[facing=north,half=top,shape=straight]", + "137:0": "command_block[conditional=false,facing=down]", + "137:1": "command_block[conditional=false,facing=up]", + "137:2": "command_block[conditional=false,facing=north]", + "137:3": "command_block[conditional=false,facing=south]", + "137:4": "command_block[conditional=false,facing=west]", + "137:5": "command_block[conditional=false,facing=east]", + "137:8": "command_block[conditional=true,facing=down]", + "137:9": "command_block[conditional=true,facing=up]", + "137:10": "command_block[conditional=true,facing=north]", + "137:11": "command_block[conditional=true,facing=south]", + "137:12": "command_block[conditional=true,facing=west]", + "137:13": "command_block[conditional=true,facing=east]", + "138:0": "beacon", + "139:0": "cobblestone_wall[east=false,north=false,south=false,up=false,west=false]", + "139:1": "mossy_cobblestone_wall[east=false,north=false,south=false,up=false,west=false]", + "140:0": "potted_cactus", + "140:1": "potted_cactus", + "140:2": "potted_cactus", + "140:3": "potted_cactus", + "140:4": "potted_cactus", + "140:5": "potted_cactus", + "140:6": "potted_cactus", + "140:7": "potted_cactus", + "140:8": "potted_cactus", + "140:9": "potted_cactus", + "140:10": "potted_cactus", + "140:11": "potted_cactus", + "140:12": "potted_cactus", + "140:13": "potted_cactus", + "140:14": "potted_cactus", + "140:15": "potted_cactus", + "141:0": "carrots[age=0]", + "141:1": "carrots[age=1]", + "141:2": "carrots[age=2]", + "141:3": "carrots[age=3]", + "141:4": "carrots[age=4]", + "141:5": "carrots[age=5]", + "141:6": "carrots[age=6]", + "141:7": "carrots[age=7]", + "142:0": "potatoes[age=0]", + "142:1": "potatoes[age=1]", + "142:2": "potatoes[age=2]", + "142:3": "potatoes[age=3]", + "142:4": "potatoes[age=4]", + "142:5": "potatoes[age=5]", + "142:6": "potatoes[age=6]", + "142:7": "potatoes[age=7]", + "143:0": "oak_button[face=ceiling,facing=north,powered=false]", + "143:1": "oak_button[face=wall,facing=east,powered=false]", + "143:2": "oak_button[face=wall,facing=west,powered=false]", + "143:3": "oak_button[face=wall,facing=south,powered=false]", + "143:4": "oak_button[face=wall,facing=north,powered=false]", + "143:5": "oak_button[face=floor,facing=north,powered=false]", + "143:8": "oak_button[face=ceiling,facing=north,powered=true]", + "143:9": "oak_button[face=wall,facing=east,powered=true]", + "143:10": "oak_button[face=wall,facing=west,powered=true]", + "143:11": "oak_button[face=wall,facing=south,powered=true]", + "143:12": "oak_button[face=wall,facing=north,powered=true]", + "143:13": "oak_button[face=floor,facing=north,powered=true]", + "144:0": "undefined[facing=down,nodrop=false]", + "144:1": "undefined[facing=up,nodrop=false]", + "144:2": "undefined[facing=north,nodrop=false]", + "144:3": "undefined[facing=south,nodrop=false]", + "144:4": "undefined[facing=west,nodrop=false]", + "144:5": "undefined[facing=east,nodrop=false]", + "144:8": "undefined[facing=down,nodrop=true]", + "144:9": "undefined[facing=up,nodrop=true]", + "144:10": "undefined[facing=north,nodrop=true]", + "144:11": "undefined[facing=south,nodrop=true]", + "144:12": "undefined[facing=west,nodrop=true]", + "144:13": "undefined[facing=east,nodrop=true]", + "145:0": "anvil[facing=south]", + "145:1": "anvil[facing=west]", + "145:2": "anvil[facing=north]", + "145:3": "anvil[facing=east]", + "145:4": "chipped_anvil[facing=south]", + "145:5": "chipped_anvil[facing=west]", + "145:6": "chipped_anvil[facing=north]", + "145:7": "chipped_anvil[facing=east]", + "145:8": "damaged_anvil[facing=south]", + "145:9": "damaged_anvil[facing=west]", + "145:10": "damaged_anvil[facing=north]", + "145:11": "damaged_anvil[facing=east]", + "146:2": "trapped_chest[facing=north,type=single]", + "146:3": "trapped_chest[facing=south,type=single]", + "146:4": "trapped_chest[facing=west,type=single]", + "146:5": "trapped_chest[facing=east,type=single]", + "147:0": "light_weighted_pressure_plate[power=0]", + "147:1": "light_weighted_pressure_plate[power=1]", + "147:2": "light_weighted_pressure_plate[power=2]", + "147:3": "light_weighted_pressure_plate[power=3]", + "147:4": "light_weighted_pressure_plate[power=4]", + "147:5": "light_weighted_pressure_plate[power=5]", + "147:6": "light_weighted_pressure_plate[power=6]", + "147:7": "light_weighted_pressure_plate[power=7]", + "147:8": "light_weighted_pressure_plate[power=8]", + "147:9": "light_weighted_pressure_plate[power=9]", + "147:10": "light_weighted_pressure_plate[power=10]", + "147:11": "light_weighted_pressure_plate[power=11]", + "147:12": "light_weighted_pressure_plate[power=12]", + "147:13": "light_weighted_pressure_plate[power=13]", + "147:14": "light_weighted_pressure_plate[power=14]", + "147:15": "light_weighted_pressure_plate[power=15]", + "148:0": "heavy_weighted_pressure_plate[power=0]", + "148:1": "heavy_weighted_pressure_plate[power=1]", + "148:2": "heavy_weighted_pressure_plate[power=2]", + "148:3": "heavy_weighted_pressure_plate[power=3]", + "148:4": "heavy_weighted_pressure_plate[power=4]", + "148:5": "heavy_weighted_pressure_plate[power=5]", + "148:6": "heavy_weighted_pressure_plate[power=6]", + "148:7": "heavy_weighted_pressure_plate[power=7]", + "148:8": "heavy_weighted_pressure_plate[power=8]", + "148:9": "heavy_weighted_pressure_plate[power=9]", + "148:10": "heavy_weighted_pressure_plate[power=10]", + "148:11": "heavy_weighted_pressure_plate[power=11]", + "148:12": "heavy_weighted_pressure_plate[power=12]", + "148:13": "heavy_weighted_pressure_plate[power=13]", + "148:14": "heavy_weighted_pressure_plate[power=14]", + "148:15": "heavy_weighted_pressure_plate[power=15]", + "149:0": "comparator[facing=south,mode=compare,powered=false]", + "149:1": "comparator[facing=west,mode=compare,powered=false]", + "149:2": "comparator[facing=north,mode=compare,powered=false]", + "149:3": "comparator[facing=east,mode=compare,powered=false]", + "149:4": "comparator[facing=south,mode=subtract,powered=false]", + "149:5": "comparator[facing=west,mode=subtract,powered=false]", + "149:6": "comparator[facing=north,mode=subtract,powered=false]", + "149:7": "comparator[facing=east,mode=subtract,powered=false]", + "149:8": "comparator[facing=south,mode=compare,powered=true]", + "149:9": "comparator[facing=west,mode=compare,powered=true]", + "149:10": "comparator[facing=north,mode=compare,powered=true]", + "149:11": "comparator[facing=east,mode=compare,powered=true]", + "149:12": "comparator[facing=south,mode=subtract,powered=true]", + "149:13": "comparator[facing=west,mode=subtract,powered=true]", + "149:14": "comparator[facing=north,mode=subtract,powered=true]", + "149:15": "comparator[facing=east,mode=subtract,powered=true]", + "150:0": "comparator[facing=south,mode=compare,powered=false]", + "150:1": "comparator[facing=west,mode=compare,powered=false]", + "150:2": "comparator[facing=north,mode=compare,powered=false]", + "150:3": "comparator[facing=east,mode=compare,powered=false]", + "150:4": "comparator[facing=south,mode=subtract,powered=false]", + "150:5": "comparator[facing=west,mode=subtract,powered=false]", + "150:6": "comparator[facing=north,mode=subtract,powered=false]", + "150:7": "comparator[facing=east,mode=subtract,powered=false]", + "150:8": "comparator[facing=south,mode=compare,powered=true]", + "150:9": "comparator[facing=west,mode=compare,powered=true]", + "150:10": "comparator[facing=north,mode=compare,powered=true]", + "150:11": "comparator[facing=east,mode=compare,powered=true]", + "150:12": "comparator[facing=south,mode=subtract,powered=true]", + "150:13": "comparator[facing=west,mode=subtract,powered=true]", + "150:14": "comparator[facing=north,mode=subtract,powered=true]", + "150:15": "comparator[facing=east,mode=subtract,powered=true]", + "151:0": "daylight_detector[inverted=false,power=0]", + "151:1": "daylight_detector[inverted=false,power=1]", + "151:2": "daylight_detector[inverted=false,power=2]", + "151:3": "daylight_detector[inverted=false,power=3]", + "151:4": "daylight_detector[inverted=false,power=4]", + "151:5": "daylight_detector[inverted=false,power=5]", + "151:6": "daylight_detector[inverted=false,power=6]", + "151:7": "daylight_detector[inverted=false,power=7]", + "151:8": "daylight_detector[inverted=false,power=8]", + "151:9": "daylight_detector[inverted=false,power=9]", + "151:10": "daylight_detector[inverted=false,power=10]", + "151:11": "daylight_detector[inverted=false,power=11]", + "151:12": "daylight_detector[inverted=false,power=12]", + "151:13": "daylight_detector[inverted=false,power=13]", + "151:14": "daylight_detector[inverted=false,power=14]", + "151:15": "daylight_detector[inverted=false,power=15]", + "152:0": "redstone_block", + "153:0": "nether_quartz_ore", + "154:0": "hopper[enabled=true,facing=down]", + "154:2": "hopper[enabled=true,facing=north]", + "154:3": "hopper[enabled=true,facing=south]", + "154:4": "hopper[enabled=true,facing=west]", + "154:5": "hopper[enabled=true,facing=east]", + "154:8": "hopper[enabled=false,facing=down]", + "154:10": "hopper[enabled=false,facing=north]", + "154:11": "hopper[enabled=false,facing=south]", + "154:12": "hopper[enabled=false,facing=west]", + "154:13": "hopper[enabled=false,facing=east]", + "155:0": "quartz_block", + "155:1": "chiseled_quartz_block", + "155:2": "quartz_pillar[axis=y]", + "155:3": "quartz_pillar[axis=x]", + "155:4": "quartz_pillar[axis=z]", + "156:0": "quartz_stairs[facing=east,half=bottom,shape=straight]", + "156:1": "quartz_stairs[facing=west,half=bottom,shape=straight]", + "156:2": "quartz_stairs[facing=south,half=bottom,shape=straight]", + "156:3": "quartz_stairs[facing=north,half=bottom,shape=straight]", + "156:4": "quartz_stairs[facing=east,half=top,shape=straight]", + "156:5": "quartz_stairs[facing=west,half=top,shape=straight]", + "156:6": "quartz_stairs[facing=south,half=top,shape=straight]", + "156:7": "quartz_stairs[facing=north,half=top,shape=straight]", + "157:0": "activator_rail[powered=false,shape=north_south]", + "157:1": "activator_rail[powered=false,shape=east_west]", + "157:2": "activator_rail[powered=false,shape=ascending_east]", + "157:3": "activator_rail[powered=false,shape=ascending_west]", + "157:4": "activator_rail[powered=false,shape=ascending_north]", + "157:5": "activator_rail[powered=false,shape=ascending_south]", + "157:8": "activator_rail[powered=true,shape=north_south]", + "157:9": "activator_rail[powered=true,shape=east_west]", + "157:10": "activator_rail[powered=true,shape=ascending_east]", + "157:11": "activator_rail[powered=true,shape=ascending_west]", + "157:12": "activator_rail[powered=true,shape=ascending_north]", + "157:13": "activator_rail[powered=true,shape=ascending_south]", + "158:0": "dropper[facing=down,triggered=false]", + "158:1": "dropper[facing=up,triggered=false]", + "158:2": "dropper[facing=north,triggered=false]", + "158:3": "dropper[facing=south,triggered=false]", + "158:4": "dropper[facing=west,triggered=false]", + "158:5": "dropper[facing=east,triggered=false]", + "158:8": "dropper[facing=down,triggered=true]", + "158:9": "dropper[facing=up,triggered=true]", + "158:10": "dropper[facing=north,triggered=true]", + "158:11": "dropper[facing=south,triggered=true]", + "158:12": "dropper[facing=west,triggered=true]", + "158:13": "dropper[facing=east,triggered=true]", + "159:0": "white_terracotta", + "159:1": "orange_terracotta", + "159:2": "magenta_terracotta", + "159:3": "light_blue_terracotta", + "159:4": "yellow_terracotta", + "159:5": "lime_terracotta", + "159:6": "pink_terracotta", + "159:7": "gray_terracotta", + "159:8": "light_gray_terracotta", + "159:9": "cyan_terracotta", + "159:10": "purple_terracotta", + "159:11": "blue_terracotta", + "159:12": "brown_terracotta", + "159:13": "green_terracotta", + "159:14": "red_terracotta", + "159:15": "black_terracotta", + "160:0": "white_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:1": "orange_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:2": "magenta_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:3": "light_blue_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:4": "yellow_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:5": "lime_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:6": "pink_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:7": "gray_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:8": "light_gray_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:9": "cyan_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:10": "purple_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:11": "blue_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:12": "brown_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:13": "green_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:14": "red_stained_glass_pane[east=false,north=false,south=false,west=false]", + "160:15": "black_stained_glass_pane[east=false,north=false,south=false,west=false]", + "161:0": "acacia_leaves[check_decay=false,decayable=true]", + "161:1": "dark_oak_leaves[check_decay=false,decayable=true]", + "161:4": "acacia_leaves[check_decay=false,decayable=false]", + "161:5": "dark_oak_leaves[check_decay=false,decayable=false]", + "161:8": "acacia_leaves[check_decay=true,decayable=true]", + "161:9": "dark_oak_leaves[check_decay=true,decayable=true]", + "161:12": "acacia_leaves[check_decay=true,decayable=false]", + "161:13": "dark_oak_leaves[check_decay=true,decayable=false]", + "162:0": "acacia_log[axis=y]", + "162:1": "dark_oak_log[axis=y]", + "162:4": "acacia_log[axis=x]", + "162:5": "dark_oak_log[axis=x]", + "162:8": "acacia_log[axis=z]", + "162:9": "dark_oak_log[axis=z]", + "162:12": "acacia_bark", + "162:13": "dark_oak_bark", + "163:0": "acacia_stairs[facing=east,half=bottom,shape=straight]", + "163:1": "acacia_stairs[facing=west,half=bottom,shape=straight]", + "163:2": "acacia_stairs[facing=south,half=bottom,shape=straight]", + "163:3": "acacia_stairs[facing=north,half=bottom,shape=straight]", + "163:4": "acacia_stairs[facing=east,half=top,shape=straight]", + "163:5": "acacia_stairs[facing=west,half=top,shape=straight]", + "163:6": "acacia_stairs[facing=south,half=top,shape=straight]", + "163:7": "acacia_stairs[facing=north,half=top,shape=straight]", + "164:0": "dark_oak_stairs[facing=east,half=bottom,shape=straight]", + "164:1": "dark_oak_stairs[facing=west,half=bottom,shape=straight]", + "164:2": "dark_oak_stairs[facing=south,half=bottom,shape=straight]", + "164:3": "dark_oak_stairs[facing=north,half=bottom,shape=straight]", + "164:4": "dark_oak_stairs[facing=east,half=top,shape=straight]", + "164:5": "dark_oak_stairs[facing=west,half=top,shape=straight]", + "164:6": "dark_oak_stairs[facing=south,half=top,shape=straight]", + "164:7": "dark_oak_stairs[facing=north,half=top,shape=straight]", + "165:0": "slime_block", + "166:0": "barrier", + "167:0": "iron_trapdoor[facing=north,half=bottom,open=false]", + "167:1": "iron_trapdoor[facing=south,half=bottom,open=false]", + "167:2": "iron_trapdoor[facing=west,half=bottom,open=false]", + "167:3": "iron_trapdoor[facing=east,half=bottom,open=false]", + "167:4": "iron_trapdoor[facing=north,half=bottom,open=true]", + "167:5": "iron_trapdoor[facing=south,half=bottom,open=true]", + "167:6": "iron_trapdoor[facing=west,half=bottom,open=true]", + "167:7": "iron_trapdoor[facing=east,half=bottom,open=true]", + "167:8": "iron_trapdoor[facing=north,half=top,open=false]", + "167:9": "iron_trapdoor[facing=south,half=top,open=false]", + "167:10": "iron_trapdoor[facing=west,half=top,open=false]", + "167:11": "iron_trapdoor[facing=east,half=top,open=false]", + "167:12": "iron_trapdoor[facing=north,half=top,open=true]", + "167:13": "iron_trapdoor[facing=south,half=top,open=true]", + "167:14": "iron_trapdoor[facing=west,half=top,open=true]", + "167:15": "iron_trapdoor[facing=east,half=top,open=true]", + "168:0": "prismarine", + "168:1": "prismarine_bricks", + "168:2": "dark_prismarine", + "169:0": "sea_lantern", + "170:0": "hay_block[axis=y]", + "170:4": "hay_block[axis=x]", + "170:8": "hay_block[axis=z]", + "171:0": "white_carpet", + "171:1": "orange_carpet", + "171:2": "magenta_carpet", + "171:3": "light_blue_carpet", + "171:4": "yellow_carpet", + "171:5": "lime_carpet", + "171:6": "pink_carpet", + "171:7": "gray_carpet", + "171:8": "light_gray_carpet", + "171:9": "cyan_carpet", + "171:10": "purple_carpet", + "171:11": "blue_carpet", + "171:12": "brown_carpet", + "171:13": "green_carpet", + "171:14": "red_carpet", + "171:15": "black_carpet", + "172:0": "terracotta", + "173:0": "coal_block", + "174:0": "packed_ice", + "175:0": "sunflower[half=lower]", + "175:1": "lilac[half=lower]", + "175:2": "tall_grass[half=lower]", + "175:3": "large_fern[half=lower]", + "175:4": "rose_bush[half=lower]", + "175:5": "peony[half=lower]", + "175:8": "peony[half=upper]", + "175:9": "peony[half=upper]", + "175:10": "peony[half=upper]", + "175:11": "peony[half=upper]", + "176:0": "white_banner[rotation=0]", + "176:1": "white_banner[rotation=1]", + "176:2": "white_banner[rotation=2]", + "176:3": "white_banner[rotation=3]", + "176:4": "white_banner[rotation=4]", + "176:5": "white_banner[rotation=5]", + "176:6": "white_banner[rotation=6]", + "176:7": "white_banner[rotation=7]", + "176:8": "white_banner[rotation=8]", + "176:9": "white_banner[rotation=9]", + "176:10": "white_banner[rotation=10]", + "176:11": "white_banner[rotation=11]", + "176:12": "white_banner[rotation=12]", + "176:13": "white_banner[rotation=13]", + "176:14": "white_banner[rotation=14]", + "176:15": "white_banner[rotation=15]", + "177:2": "white_wall_banner[facing=north]", + "177:3": "white_wall_banner[facing=south]", + "177:4": "white_wall_banner[facing=west]", + "177:5": "white_wall_banner[facing=east]", + "178:0": "daylight_detector[inverted=true,power=0]", + "178:1": "daylight_detector[inverted=true,power=1]", + "178:2": "daylight_detector[inverted=true,power=2]", + "178:3": "daylight_detector[inverted=true,power=3]", + "178:4": "daylight_detector[inverted=true,power=4]", + "178:5": "daylight_detector[inverted=true,power=5]", + "178:6": "daylight_detector[inverted=true,power=6]", + "178:7": "daylight_detector[inverted=true,power=7]", + "178:8": "daylight_detector[inverted=true,power=8]", + "178:9": "daylight_detector[inverted=true,power=9]", + "178:10": "daylight_detector[inverted=true,power=10]", + "178:11": "daylight_detector[inverted=true,power=11]", + "178:12": "daylight_detector[inverted=true,power=12]", + "178:13": "daylight_detector[inverted=true,power=13]", + "178:14": "daylight_detector[inverted=true,power=14]", + "178:15": "daylight_detector[inverted=true,power=15]", + "179:0": "red_sandstone", + "179:1": "chiseled_red_sandstone", + "179:2": "cut_red_sandstone", + "180:0": "red_sandstone_stairs[facing=east,half=bottom,shape=straight]", + "180:1": "red_sandstone_stairs[facing=west,half=bottom,shape=straight]", + "180:2": "red_sandstone_stairs[facing=south,half=bottom,shape=straight]", + "180:3": "red_sandstone_stairs[facing=north,half=bottom,shape=straight]", + "180:4": "red_sandstone_stairs[facing=east,half=top,shape=straight]", + "180:5": "red_sandstone_stairs[facing=west,half=top,shape=straight]", + "180:6": "red_sandstone_stairs[facing=south,half=top,shape=straight]", + "180:7": "red_sandstone_stairs[facing=north,half=top,shape=straight]", + "181:0": "red_sandstone_slab[type=double]", + "181:8": "smooth_red_sandstone", + "182:0": "red_sandstone_slab[type=bottom]", + "182:8": "red_sandstone_slab[type=top]", + "183:0": "spruce_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "183:1": "spruce_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "183:2": "spruce_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "183:3": "spruce_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "183:4": "spruce_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "183:5": "spruce_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "183:6": "spruce_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "183:7": "spruce_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "183:8": "spruce_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "183:9": "spruce_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "183:10": "spruce_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "183:11": "spruce_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "183:12": "spruce_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "183:13": "spruce_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "183:14": "spruce_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "183:15": "spruce_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "184:0": "birch_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "184:1": "birch_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "184:2": "birch_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "184:3": "birch_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "184:4": "birch_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "184:5": "birch_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "184:6": "birch_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "184:7": "birch_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "184:8": "birch_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "184:9": "birch_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "184:10": "birch_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "184:11": "birch_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "184:12": "birch_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "184:13": "birch_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "184:14": "birch_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "184:15": "birch_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "185:0": "jungle_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "185:1": "jungle_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "185:2": "jungle_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "185:3": "jungle_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "185:4": "jungle_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "185:5": "jungle_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "185:6": "jungle_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "185:7": "jungle_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "185:8": "jungle_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "185:9": "jungle_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "185:10": "jungle_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "185:11": "jungle_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "185:12": "jungle_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "185:13": "jungle_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "185:14": "jungle_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "185:15": "jungle_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "186:0": "dark_oak_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "186:1": "dark_oak_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "186:2": "dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "186:3": "dark_oak_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "186:4": "dark_oak_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "186:5": "dark_oak_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "186:6": "dark_oak_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "186:7": "dark_oak_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "186:8": "dark_oak_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "186:9": "dark_oak_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "186:10": "dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "186:11": "dark_oak_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "186:12": "dark_oak_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "186:13": "dark_oak_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "186:14": "dark_oak_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "186:15": "dark_oak_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "187:0": "acacia_fence_gate[facing=south,in_wall=false,open=false,powered=false]", + "187:1": "acacia_fence_gate[facing=west,in_wall=false,open=false,powered=false]", + "187:2": "acacia_fence_gate[facing=north,in_wall=false,open=false,powered=false]", + "187:3": "acacia_fence_gate[facing=east,in_wall=false,open=false,powered=false]", + "187:4": "acacia_fence_gate[facing=south,in_wall=false,open=true,powered=false]", + "187:5": "acacia_fence_gate[facing=west,in_wall=false,open=true,powered=false]", + "187:6": "acacia_fence_gate[facing=north,in_wall=false,open=true,powered=false]", + "187:7": "acacia_fence_gate[facing=east,in_wall=false,open=true,powered=false]", + "187:8": "acacia_fence_gate[facing=south,in_wall=false,open=false,powered=true]", + "187:9": "acacia_fence_gate[facing=west,in_wall=false,open=false,powered=true]", + "187:10": "acacia_fence_gate[facing=north,in_wall=false,open=false,powered=true]", + "187:11": "acacia_fence_gate[facing=east,in_wall=false,open=false,powered=true]", + "187:12": "acacia_fence_gate[facing=south,in_wall=false,open=true,powered=true]", + "187:13": "acacia_fence_gate[facing=west,in_wall=false,open=true,powered=true]", + "187:14": "acacia_fence_gate[facing=north,in_wall=false,open=true,powered=true]", + "187:15": "acacia_fence_gate[facing=east,in_wall=false,open=true,powered=true]", + "188:0": "spruce_fence[east=false,north=false,south=false,west=false]", + "189:0": "birch_fence[east=false,north=false,south=false,west=false]", + "190:0": "jungle_fence[east=false,north=false,south=false,west=false]", + "191:0": "dark_oak_fence[east=false,north=false,south=false,west=false]", + "192:0": "acacia_fence[east=false,north=false,south=false,west=false]", + "193:0": "spruce_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "193:1": "spruce_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "193:2": "spruce_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "193:3": "spruce_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "193:4": "spruce_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "193:5": "spruce_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "193:6": "spruce_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "193:7": "spruce_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "193:8": "spruce_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "193:9": "spruce_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "193:10": "spruce_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "193:11": "spruce_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "194:0": "birch_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "194:1": "birch_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "194:2": "birch_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "194:3": "birch_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "194:4": "birch_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "194:5": "birch_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "194:6": "birch_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "194:7": "birch_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "194:8": "birch_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "194:9": "birch_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "194:10": "birch_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "194:11": "birch_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "195:0": "jungle_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "195:1": "jungle_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "195:2": "jungle_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "195:3": "jungle_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "195:4": "jungle_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "195:5": "jungle_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "195:6": "jungle_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "195:7": "jungle_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "195:8": "jungle_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "195:9": "jungle_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "195:10": "jungle_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "195:11": "jungle_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "196:0": "acacia_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "196:1": "acacia_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "196:2": "acacia_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "196:3": "acacia_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "196:4": "acacia_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "196:5": "acacia_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "196:6": "acacia_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "196:7": "acacia_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "196:8": "acacia_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "196:9": "acacia_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "196:10": "acacia_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "196:11": "acacia_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "197:0": "dark_oak_door[facing=east,half=lower,hinge=right,open=false,powered=false]", + "197:1": "dark_oak_door[facing=south,half=lower,hinge=right,open=false,powered=false]", + "197:2": "dark_oak_door[facing=west,half=lower,hinge=right,open=false,powered=false]", + "197:3": "dark_oak_door[facing=north,half=lower,hinge=right,open=false,powered=false]", + "197:4": "dark_oak_door[facing=east,half=lower,hinge=right,open=true,powered=false]", + "197:5": "dark_oak_door[facing=south,half=lower,hinge=right,open=true,powered=false]", + "197:6": "dark_oak_door[facing=west,half=lower,hinge=right,open=true,powered=false]", + "197:7": "dark_oak_door[facing=north,half=lower,hinge=right,open=true,powered=false]", + "197:8": "dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=false]", + "197:9": "dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=false]", + "197:10": "dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=true]", + "197:11": "dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=true]", + "198:0": "end_rod[facing=down]", + "198:1": "end_rod[facing=up]", + "198:2": "end_rod[facing=north]", + "198:3": "end_rod[facing=south]", + "198:4": "end_rod[facing=west]", + "198:5": "end_rod[facing=east]", + "199:0": "chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]", + "200:0": "chorus_flower[age=0]", + "200:1": "chorus_flower[age=1]", + "200:2": "chorus_flower[age=2]", + "200:3": "chorus_flower[age=3]", + "200:4": "chorus_flower[age=4]", + "200:5": "chorus_flower[age=5]", + "201:0": "purpur_block", + "202:0": "purpur_pillar[axis=y]", + "202:4": "purpur_pillar[axis=x]", + "202:8": "purpur_pillar[axis=z]", + "203:0": "purpur_stairs[facing=east,half=bottom,shape=straight]", + "203:1": "purpur_stairs[facing=west,half=bottom,shape=straight]", + "203:2": "purpur_stairs[facing=south,half=bottom,shape=straight]", + "203:3": "purpur_stairs[facing=north,half=bottom,shape=straight]", + "203:4": "purpur_stairs[facing=east,half=top,shape=straight]", + "203:5": "purpur_stairs[facing=west,half=top,shape=straight]", + "203:6": "purpur_stairs[facing=south,half=top,shape=straight]", + "203:7": "purpur_stairs[facing=north,half=top,shape=straight]", + "204:0": "purpur_slab[type=double]", + "205:0": "purpur_slab[type=bottom]", + "205:8": "purpur_slab[type=top]", + "206:0": "end_stone_bricks", + "207:0": "beetroots[age=0]", + "207:1": "beetroots[age=1]", + "207:2": "beetroots[age=2]", + "207:3": "beetroots[age=3]", + "208:0": "grass_path", + "209:0": "end_gateway", + "210:0": "repeating_command_block[conditional=false,facing=down]", + "210:1": "repeating_command_block[conditional=false,facing=up]", + "210:2": "repeating_command_block[conditional=false,facing=north]", + "210:3": "repeating_command_block[conditional=false,facing=south]", + "210:4": "repeating_command_block[conditional=false,facing=west]", + "210:5": "repeating_command_block[conditional=false,facing=east]", + "210:8": "repeating_command_block[conditional=true,facing=down]", + "210:9": "repeating_command_block[conditional=true,facing=up]", + "210:10": "repeating_command_block[conditional=true,facing=north]", + "210:11": "repeating_command_block[conditional=true,facing=south]", + "210:12": "repeating_command_block[conditional=true,facing=west]", + "210:13": "repeating_command_block[conditional=true,facing=east]", + "211:0": "chain_command_block[conditional=false,facing=down]", + "211:1": "chain_command_block[conditional=false,facing=up]", + "211:2": "chain_command_block[conditional=false,facing=north]", + "211:3": "chain_command_block[conditional=false,facing=south]", + "211:4": "chain_command_block[conditional=false,facing=west]", + "211:5": "chain_command_block[conditional=false,facing=east]", + "211:8": "chain_command_block[conditional=true,facing=down]", + "211:9": "chain_command_block[conditional=true,facing=up]", + "211:10": "chain_command_block[conditional=true,facing=north]", + "211:11": "chain_command_block[conditional=true,facing=south]", + "211:12": "chain_command_block[conditional=true,facing=west]", + "211:13": "chain_command_block[conditional=true,facing=east]", + "212:0": "frosted_ice[age=0]", + "212:1": "frosted_ice[age=1]", + "212:2": "frosted_ice[age=2]", + "212:3": "frosted_ice[age=3]", + "213:0": "magma_block", + "214:0": "nether_wart_block", + "215:0": "red_nether_bricks", + "216:0": "bone_block[axis=y]", + "216:4": "bone_block[axis=x]", + "216:8": "bone_block[axis=z]", + "217:0": "structure_void", + "218:0": "observer[facing=down,powered=false]", + "218:1": "observer[facing=up,powered=false]", + "218:2": "observer[facing=north,powered=false]", + "218:3": "observer[facing=south,powered=false]", + "218:4": "observer[facing=west,powered=false]", + "218:5": "observer[facing=east,powered=false]", + "218:8": "observer[facing=down,powered=true]", + "218:9": "observer[facing=up,powered=true]", + "218:10": "observer[facing=north,powered=true]", + "218:11": "observer[facing=south,powered=true]", + "218:12": "observer[facing=west,powered=true]", + "218:13": "observer[facing=east,powered=true]", + "219:0": "white_shulker_box[facing=down]", + "219:1": "white_shulker_box[facing=up]", + "219:2": "white_shulker_box[facing=north]", + "219:3": "white_shulker_box[facing=south]", + "219:4": "white_shulker_box[facing=west]", + "219:5": "white_shulker_box[facing=east]", + "220:0": "orange_shulker_box[facing=down]", + "220:1": "orange_shulker_box[facing=up]", + "220:2": "orange_shulker_box[facing=north]", + "220:3": "orange_shulker_box[facing=south]", + "220:4": "orange_shulker_box[facing=west]", + "220:5": "orange_shulker_box[facing=east]", + "221:0": "magenta_shulker_box[facing=down]", + "221:1": "magenta_shulker_box[facing=up]", + "221:2": "magenta_shulker_box[facing=north]", + "221:3": "magenta_shulker_box[facing=south]", + "221:4": "magenta_shulker_box[facing=west]", + "221:5": "magenta_shulker_box[facing=east]", + "222:0": "light_blue_shulker_box[facing=down]", + "222:1": "light_blue_shulker_box[facing=up]", + "222:2": "light_blue_shulker_box[facing=north]", + "222:3": "light_blue_shulker_box[facing=south]", + "222:4": "light_blue_shulker_box[facing=west]", + "222:5": "light_blue_shulker_box[facing=east]", + "223:0": "yellow_shulker_box[facing=down]", + "223:1": "yellow_shulker_box[facing=up]", + "223:2": "yellow_shulker_box[facing=north]", + "223:3": "yellow_shulker_box[facing=south]", + "223:4": "yellow_shulker_box[facing=west]", + "223:5": "yellow_shulker_box[facing=east]", + "224:0": "lime_shulker_box[facing=down]", + "224:1": "lime_shulker_box[facing=up]", + "224:2": "lime_shulker_box[facing=north]", + "224:3": "lime_shulker_box[facing=south]", + "224:4": "lime_shulker_box[facing=west]", + "224:5": "lime_shulker_box[facing=east]", + "225:0": "pink_shulker_box[facing=down]", + "225:1": "pink_shulker_box[facing=up]", + "225:2": "pink_shulker_box[facing=north]", + "225:3": "pink_shulker_box[facing=south]", + "225:4": "pink_shulker_box[facing=west]", + "225:5": "pink_shulker_box[facing=east]", + "226:0": "gray_shulker_box[facing=down]", + "226:1": "gray_shulker_box[facing=up]", + "226:2": "gray_shulker_box[facing=north]", + "226:3": "gray_shulker_box[facing=south]", + "226:4": "gray_shulker_box[facing=west]", + "226:5": "gray_shulker_box[facing=east]", + "227:0": "light_gray_shulker_box[facing=down]", + "227:1": "light_gray_shulker_box[facing=up]", + "227:2": "light_gray_shulker_box[facing=north]", + "227:3": "light_gray_shulker_box[facing=south]", + "227:4": "light_gray_shulker_box[facing=west]", + "227:5": "light_gray_shulker_box[facing=east]", + "228:0": "cyan_shulker_box[facing=down]", + "228:1": "cyan_shulker_box[facing=up]", + "228:2": "cyan_shulker_box[facing=north]", + "228:3": "cyan_shulker_box[facing=south]", + "228:4": "cyan_shulker_box[facing=west]", + "228:5": "cyan_shulker_box[facing=east]", + "229:0": "purple_shulker_box[facing=down]", + "229:1": "purple_shulker_box[facing=up]", + "229:2": "purple_shulker_box[facing=north]", + "229:3": "purple_shulker_box[facing=south]", + "229:4": "purple_shulker_box[facing=west]", + "229:5": "purple_shulker_box[facing=east]", + "230:0": "blue_shulker_box[facing=down]", + "230:1": "blue_shulker_box[facing=up]", + "230:2": "blue_shulker_box[facing=north]", + "230:3": "blue_shulker_box[facing=south]", + "230:4": "blue_shulker_box[facing=west]", + "230:5": "blue_shulker_box[facing=east]", + "231:0": "brown_shulker_box[facing=down]", + "231:1": "brown_shulker_box[facing=up]", + "231:2": "brown_shulker_box[facing=north]", + "231:3": "brown_shulker_box[facing=south]", + "231:4": "brown_shulker_box[facing=west]", + "231:5": "brown_shulker_box[facing=east]", + "232:0": "green_shulker_box[facing=down]", + "232:1": "green_shulker_box[facing=up]", + "232:2": "green_shulker_box[facing=north]", + "232:3": "green_shulker_box[facing=south]", + "232:4": "green_shulker_box[facing=west]", + "232:5": "green_shulker_box[facing=east]", + "233:0": "red_shulker_box[facing=down]", + "233:1": "red_shulker_box[facing=up]", + "233:2": "red_shulker_box[facing=north]", + "233:3": "red_shulker_box[facing=south]", + "233:4": "red_shulker_box[facing=west]", + "233:5": "red_shulker_box[facing=east]", + "234:0": "black_shulker_box[facing=down]", + "234:1": "black_shulker_box[facing=up]", + "234:2": "black_shulker_box[facing=north]", + "234:3": "black_shulker_box[facing=south]", + "234:4": "black_shulker_box[facing=west]", + "234:5": "black_shulker_box[facing=east]", + "235:0": "white_glazed_terracotta[facing=south]", + "235:1": "white_glazed_terracotta[facing=west]", + "235:2": "white_glazed_terracotta[facing=north]", + "235:3": "white_glazed_terracotta[facing=east]", + "236:0": "orange_glazed_terracotta[facing=south]", + "236:1": "orange_glazed_terracotta[facing=west]", + "236:2": "orange_glazed_terracotta[facing=north]", + "236:3": "orange_glazed_terracotta[facing=east]", + "237:0": "magenta_glazed_terracotta[facing=south]", + "237:1": "magenta_glazed_terracotta[facing=west]", + "237:2": "magenta_glazed_terracotta[facing=north]", + "237:3": "magenta_glazed_terracotta[facing=east]", + "238:0": "light_blue_glazed_terracotta[facing=south]", + "238:1": "light_blue_glazed_terracotta[facing=west]", + "238:2": "light_blue_glazed_terracotta[facing=north]", + "238:3": "light_blue_glazed_terracotta[facing=east]", + "239:0": "yellow_glazed_terracotta[facing=south]", + "239:1": "yellow_glazed_terracotta[facing=west]", + "239:2": "yellow_glazed_terracotta[facing=north]", + "239:3": "yellow_glazed_terracotta[facing=east]", + "240:0": "lime_glazed_terracotta[facing=south]", + "240:1": "lime_glazed_terracotta[facing=west]", + "240:2": "lime_glazed_terracotta[facing=north]", + "240:3": "lime_glazed_terracotta[facing=east]", + "241:0": "pink_glazed_terracotta[facing=south]", + "241:1": "pink_glazed_terracotta[facing=west]", + "241:2": "pink_glazed_terracotta[facing=north]", + "241:3": "pink_glazed_terracotta[facing=east]", + "242:0": "gray_glazed_terracotta[facing=south]", + "242:1": "gray_glazed_terracotta[facing=west]", + "242:2": "gray_glazed_terracotta[facing=north]", + "242:3": "gray_glazed_terracotta[facing=east]", + "243:0": "light_gray_glazed_terracotta[facing=south]", + "243:1": "light_gray_glazed_terracotta[facing=west]", + "243:2": "light_gray_glazed_terracotta[facing=north]", + "243:3": "light_gray_glazed_terracotta[facing=east]", + "244:0": "cyan_glazed_terracotta[facing=south]", + "244:1": "cyan_glazed_terracotta[facing=west]", + "244:2": "cyan_glazed_terracotta[facing=north]", + "244:3": "cyan_glazed_terracotta[facing=east]", + "245:0": "purple_glazed_terracotta[facing=south]", + "245:1": "purple_glazed_terracotta[facing=west]", + "245:2": "purple_glazed_terracotta[facing=north]", + "245:3": "purple_glazed_terracotta[facing=east]", + "246:0": "blue_glazed_terracotta[facing=south]", + "246:1": "blue_glazed_terracotta[facing=west]", + "246:2": "blue_glazed_terracotta[facing=north]", + "246:3": "blue_glazed_terracotta[facing=east]", + "247:0": "brown_glazed_terracotta[facing=south]", + "247:1": "brown_glazed_terracotta[facing=west]", + "247:2": "brown_glazed_terracotta[facing=north]", + "247:3": "brown_glazed_terracotta[facing=east]", + "248:0": "green_glazed_terracotta[facing=south]", + "248:1": "green_glazed_terracotta[facing=west]", + "248:2": "green_glazed_terracotta[facing=north]", + "248:3": "green_glazed_terracotta[facing=east]", + "249:0": "red_glazed_terracotta[facing=south]", + "249:1": "red_glazed_terracotta[facing=west]", + "249:2": "red_glazed_terracotta[facing=north]", + "249:3": "red_glazed_terracotta[facing=east]", + "250:0": "black_glazed_terracotta[facing=south]", + "250:1": "black_glazed_terracotta[facing=west]", + "250:2": "black_glazed_terracotta[facing=north]", + "250:3": "black_glazed_terracotta[facing=east]", + "251:0": "white_concrete", + "251:1": "orange_concrete", + "251:2": "magenta_concrete", + "251:3": "light_blue_concrete", + "251:4": "yellow_concrete", + "251:5": "lime_concrete", + "251:6": "pink_concrete", + "251:7": "gray_concrete", + "251:8": "light_gray_concrete", + "251:9": "cyan_concrete", + "251:10": "purple_concrete", + "251:11": "blue_concrete", + "251:12": "brown_concrete", + "251:13": "green_concrete", + "251:14": "red_concrete", + "251:15": "black_concrete", + "252:0": "white_concrete_powder", + "252:1": "orange_concrete_powder", + "252:2": "magenta_concrete_powder", + "252:3": "light_blue_concrete_powder", + "252:4": "yellow_concrete_powder", + "252:5": "lime_concrete_powder", + "252:6": "pink_concrete_powder", + "252:7": "gray_concrete_powder", + "252:8": "light_gray_concrete_powder", + "252:9": "cyan_concrete_powder", + "252:10": "purple_concrete_powder", + "252:11": "blue_concrete_powder", + "252:12": "brown_concrete_powder", + "252:13": "green_concrete_powder", + "252:14": "red_concrete_powder", + "252:15": "black_concrete_powder", + "255:0": "structure_block[mode=save]", + "255:1": "structure_block[mode=load]", + "255:2": "structure_block[mode=corner]", + "255:3": "structure_block[mode=data]" + }, + "clientCalculatedBlocks": { + "block_snowy": [ + "grass_block", + "dirt", + "coarse_dirt", + "podzol", + "mycelium" + ], + "directional": [ + "fire", + "redstone_wire", + "oak_fence", + "iron_bars", + "glass_pane", + "vine", + "nether_brick_fence", + "tripwire", + "cobblestone_wall", + "mossy_cobblestone_wall", + "white_stained_glass_pane", + "orange_stained_glass_pane", + "magenta_stained_glass_pane", + "light_blue_stained_glass_pane", + "yellow_stained_glass_pane", + "lime_stained_glass_pane", + "pink_stained_glass_pane", + "gray_stained_glass_pane", + "light_gray_stained_glass_pane", + "cyan_stained_glass_pane", + "purple_stained_glass_pane", + "blue_stained_glass_pane", + "brown_stained_glass_pane", + "green_stained_glass_pane", + "red_stained_glass_pane", + "black_stained_glass_pane", + "spruce_fence", + "birch_fence", + "jungle_fence", + "dark_oak_fence", + "acacia_fence", + "chorus_plant" + ], + "door": [ + "oak_door", + "iron_door", + "spruce_door", + "birch_door", + "jungle_door", + "acacia_door", + "dark_oak_door" + ], + "repeater_locked": [ + "repeater" + ], + "gate_in_wall": [ + "oak_fence_gate", + "spruce_fence_gate", + "birch_fence_gate", + "jungle_fence_gate", + "dark_oak_fence_gate", + "acacia_fence_gate" + ] + } +} From 93e9cf877b5de2cc9409fa9920db14d6d0abd525 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 20 May 2024 06:01:14 +0300 Subject: [PATCH 0095/1097] fix project build on windows --- scripts/esbuildPlugins.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/esbuildPlugins.mjs b/scripts/esbuildPlugins.mjs index 49547ea1..f6b539c1 100644 --- a/scripts/esbuildPlugins.mjs +++ b/scripts/esbuildPlugins.mjs @@ -7,8 +7,9 @@ import { filesize } from 'filesize' import MCProtocol from 'minecraft-protocol' import MCData from 'minecraft-data' import { throttle } from 'lodash-es' +import { fileURLToPath } from 'url' -const __dirname = dirname(new URL(import.meta.url).pathname) +const __dirname = dirname(fileURLToPath(new URL(import.meta.url))) const { supportedVersions } = MCProtocol const prod = process.argv.includes('--prod') From b6cb302457ab232200e34e1a165dc7aff0f1a832 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 20 May 2024 06:11:09 +0300 Subject: [PATCH 0096/1097] fix build! --- src/flyingSquidUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/flyingSquidUtils.ts b/src/flyingSquidUtils.ts index bd312bfb..1f070022 100644 --- a/src/flyingSquidUtils.ts +++ b/src/flyingSquidUtils.ts @@ -33,7 +33,6 @@ export const saveServer = async (autoSave = true) => { export const disconnect = async () => { if (localServer) { await saveServer() - //@ts-expect-error todo expose! void localServer.quit() // todo investigate we should await } window.history.replaceState({}, '', `${window.location.pathname}`) // remove qs From 0dfa7c3c9a283bc96a248333bcc40f098e5df18b Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 20 May 2024 06:17:47 +0300 Subject: [PATCH 0097/1097] fix: fix default gamepad bindings of nextHotbarSlot, prevHotbarSlot --- src/controls.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controls.ts b/src/controls.ts index 7d1e4cdf..b23d3beb 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -39,8 +39,8 @@ export const contro = new ControMax({ sneak: ['ShiftLeft'], toggleSneakOrDown: [null, 'Right Stick'], sprint: ['ControlLeft', 'Left Stick'], - nextHotbarSlot: [null, 'Left Bumper'], - prevHotbarSlot: [null, 'Right Bumper'], + nextHotbarSlot: [null, 'Right Bumper'], + prevHotbarSlot: [null, 'Left Bumper'], attackDestroy: [null, 'Right Trigger'], interactPlace: [null, 'Left Trigger'], chat: [['KeyT', 'Enter']], From 2a2667918b3cbfb0d4a028934d7d18641973bab3 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 21 May 2024 05:25:14 +0300 Subject: [PATCH 0098/1097] feat: limit rendering in background to 20fps so it uses less resources (+setting to control that) --- prismarine-viewer/viewer/lib/viewerWrapper.ts | 12 ++++++----- src/index.ts | 1 + src/optionsGuiScheme.tsx | 10 ++++++++++ src/optionsStorage.ts | 1 + src/react/OptionsItems.tsx | 20 ++++++++++++++++--- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/prismarine-viewer/viewer/lib/viewerWrapper.ts b/prismarine-viewer/viewer/lib/viewerWrapper.ts index c6419dff..b8017f38 100644 --- a/prismarine-viewer/viewer/lib/viewerWrapper.ts +++ b/prismarine-viewer/viewer/lib/viewerWrapper.ts @@ -5,9 +5,10 @@ export class ViewerWrapper { previousWindowWidth: number previousWindowHeight: number globalObject = globalThis as any - stopRenderOnBlur = true + stopRenderOnBlur = false addedToPage = false renderInterval = 0 + renderIntervalUnfocused: number | undefined fpsInterval constructor(public canvas: HTMLCanvasElement, public renderer?: THREE.WebGLRenderer) { @@ -44,7 +45,7 @@ export class ViewerWrapper { this.globalObject.requestAnimationFrame(this.render.bind(this)) } if (typeof window !== 'undefined') { - // this.trackWindowFocus() + this.trackWindowFocus() } } @@ -77,11 +78,12 @@ export class ViewerWrapper { for (const fn of beforeRenderFrame) fn() this.globalObject.requestAnimationFrame(this.render.bind(this)) if (this.globalObject.stopRender || this.renderer?.xr.isPresenting || (this.stopRenderOnBlur && !this.windowFocused)) return - if (this.renderInterval) { + const renderInterval = (this.windowFocused ? this.renderInterval : this.renderIntervalUnfocused) ?? this.renderInterval + if (renderInterval) { this.delta += time - this.lastTime this.lastTime = time - if (this.delta > this.renderInterval) { - this.delta %= this.renderInterval + if (this.delta > renderInterval) { + this.delta %= renderInterval // continue rendering } else { return diff --git a/src/index.ts b/src/index.ts index 8dbc46cf..1797c894 100644 --- a/src/index.ts +++ b/src/index.ts @@ -120,6 +120,7 @@ const renderWrapper = new ViewerWrapper(renderer.domElement, renderer) renderWrapper.addToPage() watchValue(options, (o) => { renderWrapper.renderInterval = o.frameLimit ? 1000 / o.frameLimit : 0 + renderWrapper.renderIntervalUnfocused = o.backgroundRendering === '5fps' ? 1000 / 5 : o.backgroundRendering === '20fps' ? 1000 / 20 : undefined }) const isFirefox = ua.getBrowser().name === 'Firefox' diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index b847fe11..46f258a8 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -43,6 +43,16 @@ export const guiOptionsScheme: { return +
+} diff --git a/src/reactUi.tsx b/src/reactUi.tsx index e384fbfd..d86cf202 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -38,6 +38,7 @@ import ServersListProvider from './react/ServersListProvider' import GamepadUiCursor from './react/GamepadUiCursor' import KeybindingsScreenProvider from './react/KeybindingsScreenProvider' import HeldMapUi from './react/HeldMapUi' +import BedTime from './react/BedTime' const RobustPortal = ({ children, to }) => { return createPortal({children}, to) @@ -116,6 +117,7 @@ const InGameUi = () => { + diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 2e20de29..85884b2f 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -14,7 +14,7 @@ import destroyStage9 from 'minecraft-assets/minecraft-assets/data/1.10/blocks/de import { Vec3 } from 'vec3' import { LineMaterial, Wireframe, LineSegmentsGeometry } from 'three-stdlib' -import { isGameActive } from './globalState' +import { hideCurrentModal, isGameActive, showModal } from './globalState' import { assertDefined } from './utils' import { options } from './optionsStorage' @@ -201,7 +201,29 @@ class WorldInteraction { 'shears', 'carrot_on_a_stick', 'warped_fungus_on_a_stick', 'spawn_egg', 'trident', 'crossbow', 'elytra', 'shield', 'turtle_helmet', ].includes(bot.heldItem.name) - if (cursorBlock && !activate) { + let stop = false + if (!bot.controlState.sneak) { + if (cursorBlock?.name === 'bed' || cursorBlock?.name.endsWith('_bed')) { + stop = true + showModal({ reactType: 'bed' }) + let cancelSleep = true + void bot.sleep(cursorBlock).catch((e) => { + if (cancelSleep) { + hideCurrentModal() + } + // if (e.message === 'bot is not sleeping') return + bot._client.emit('chat', { + message: JSON.stringify({ + text: e.message, + }) + }) + }) + setTimeout(() => { + cancelSleep = false + }) + } + } + if (cursorBlock && !activate && !stop) { const vecArray = [new Vec3(0, -1, 0), new Vec3(0, 1, 0), new Vec3(0, 0, -1), new Vec3(0, 0, 1), new Vec3(-1, 0, 0), new Vec3(1, 0, 0)] //@ts-expect-error const delta = cursorBlock.intersect.minus(cursorBlock.position) @@ -219,7 +241,7 @@ class WorldInteraction { bot.lookAt = oldLookAt }).catch(console.warn) } - } else { + } else if (!stop) { bot.activateItem() // todo offhand } this.lastBlockPlaced = 0 From bb85512cc10636e73ddb26b9e9bcfb40bde1fce1 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 22 May 2024 04:26:33 +0300 Subject: [PATCH 0103/1097] update known block are not rendered test --- .../viewer/lib/mesher/test/tests.test.ts | 237 +++++++++++------- .../viewer/prepare/moreGeneratedBlocks.ts | 1 + 2 files changed, 153 insertions(+), 85 deletions(-) diff --git a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts index 22e3a7b2..75dd98fa 100644 --- a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts +++ b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts @@ -1,96 +1,163 @@ import { test, expect } from 'vitest' import { setup } from './mesherTester' +import minecraftData from 'minecraft-data' +import minecraftAssets from 'minecraft-assets' -const version = '1.18.1' +const version = minecraftAssets.versions.at(-1) const addPositions = [ - // [[0, 0, 0], 'diamond_block'], - [[1, 0, 0], 'stone'], - [[-1, 0, 0], 'stone'], - [[0, 1, 0], 'stone'], - [[0, -1, 0], 'stone'], - [[0, 0, 1], 'stone'], - [[0, 0, -1], 'stone'], + // [[0, 0, 0], 'diamond_block'], + // [[1, 0, 0], 'stone'], + // [[-1, 0, 0], 'stone'], + // [[0, 1, 0], 'stone'], + // [[0, -1, 0], 'stone'], + // [[0, 0, 1], 'stone'], + // [[0, 0, -1], 'stone'], ] as const test('Known blocks are not rendered', () => { - const { mesherWorld, getGeometry, pos, mcData } = setup(version, addPositions as any) + const { mesherWorld, getGeometry, pos, mcData } = setup(version, addPositions as any) + const ignoreAsExpected = ['air', 'cave_air', 'void_air', 'barrier', 'water', 'lava', 'moving_piston', 'light'] - let time = 0 - let times = 0 - const invalidBlocks = {}/* as {[number, number]} */ - for (const block of mcData.blocksArray) { - if (block.maxStateId! - block.minStateId! > 100) continue - for (let i = block.minStateId!; i <= block.maxStateId!; i++) { - if (block.transparent) continue - mesherWorld.setBlockStateId(pos, i) - const start = performance.now() - const { centerFaces, totalTiles, centerTileNeighbors } = getGeometry() - time += performance.now() - start - times++ - if (centerFaces === 0 && centerTileNeighbors !== 0) { - if (invalidBlocks[block.name]) continue - invalidBlocks[block.name] = [i - block.minStateId!, centerTileNeighbors] - // console.log('INVALID', block.name, centerTileNeighbors, i - block.minStateId) - } - } - } - console.log('Average time', time / times) - // Fully expected - expect(invalidBlocks).toMatchInlineSnapshot(` - { - "creeper_head": [ - 0, - 6, - ], - "creeper_wall_head": [ - 0, - 6, - ], - "dragon_head": [ - 0, - 6, - ], - "dragon_wall_head": [ - 0, - 6, - ], - "player_head": [ - 0, - 6, - ], - "player_wall_head": [ - 0, - 6, - ], - "powder_snow": [ - 0, - 6, - ], - "skeleton_skull": [ - 0, - 6, - ], - "skeleton_wall_skull": [ - 0, - 6, - ], - "wither_skeleton_skull": [ - 0, - 6, - ], - "wither_skeleton_wall_skull": [ - 0, - 6, - ], - "zombie_head": [ - 0, - 6, - ], - "zombie_wall_head": [ - 0, - 6, - ], + let time = 0 + let times = 0 + const invalidBlocks = {}/* as {[number, number]} */ + for (const block of mcData.blocksArray) { + if (ignoreAsExpected.includes(block.name)) continue + // if (block.maxStateId! - block.minStateId! > 100) continue + // for (let i = block.minStateId!; i <= block.maxStateId!; i++) { + for (let i = block.defaultState!; i <= block.defaultState!; i++) { + // if (block.transparent) continue + mesherWorld.setBlockStateId(pos, i) + const start = performance.now() + const { centerFaces, totalTiles, centerTileNeighbors } = getGeometry() + time += performance.now() - start + times++ + if (centerFaces === 0) { + if (invalidBlocks[block.name]) continue + invalidBlocks[block.name] = true + // invalidBlocks[block.name] = [i - block.defaultState!, centerTileNeighbors] + // console.log('INVALID', block.name, centerTileNeighbors, i - block.minStateId) } - `) + } + } + console.log('Average time', time / times) + // should be fixed, but to avoid regressions & for visibility + expect(invalidBlocks).toMatchInlineSnapshot(` + { + "acacia_hanging_sign": true, + "acacia_wall_hanging_sign": true, + "bamboo_hanging_sign": true, + "bamboo_wall_hanging_sign": true, + "birch_hanging_sign": true, + "birch_wall_hanging_sign": true, + "black_banner": true, + "black_bed": true, + "black_candle": true, + "black_wall_banner": true, + "blue_banner": true, + "blue_bed": true, + "blue_candle": true, + "blue_wall_banner": true, + "brown_banner": true, + "brown_bed": true, + "brown_candle": true, + "brown_wall_banner": true, + "bubble_column": true, + "candle": true, + "cherry_hanging_sign": true, + "cherry_wall_hanging_sign": true, + "creeper_head": true, + "creeper_wall_head": true, + "crimson_hanging_sign": true, + "crimson_wall_hanging_sign": true, + "cyan_banner": true, + "cyan_bed": true, + "cyan_candle": true, + "cyan_wall_banner": true, + "dark_oak_hanging_sign": true, + "dark_oak_wall_hanging_sign": true, + "decorated_pot": true, + "dragon_head": true, + "dragon_wall_head": true, + "end_gateway": true, + "end_portal": true, + "gray_banner": true, + "gray_bed": true, + "gray_candle": true, + "gray_wall_banner": true, + "green_banner": true, + "green_bed": true, + "green_candle": true, + "green_wall_banner": true, + "jungle_hanging_sign": true, + "jungle_wall_hanging_sign": true, + "light_blue_banner": true, + "light_blue_bed": true, + "light_blue_candle": true, + "light_blue_wall_banner": true, + "light_gray_banner": true, + "light_gray_bed": true, + "light_gray_candle": true, + "light_gray_wall_banner": true, + "lime_banner": true, + "lime_bed": true, + "lime_candle": true, + "lime_wall_banner": true, + "magenta_banner": true, + "magenta_bed": true, + "magenta_candle": true, + "magenta_wall_banner": true, + "mangrove_hanging_sign": true, + "mangrove_wall_hanging_sign": true, + "oak_hanging_sign": true, + "oak_wall_hanging_sign": true, + "orange_banner": true, + "orange_bed": true, + "orange_candle": true, + "orange_wall_banner": true, + "piglin_head": true, + "piglin_wall_head": true, + "pink_banner": true, + "pink_bed": true, + "pink_candle": true, + "pink_petals": true, + "pink_wall_banner": true, + "player_head": true, + "player_wall_head": true, + "powder_snow_cauldron": true, + "purple_banner": true, + "purple_bed": true, + "purple_candle": true, + "purple_wall_banner": true, + "red_banner": true, + "red_bed": true, + "red_candle": true, + "red_wall_banner": true, + "repeater": true, + "sea_pickle": true, + "skeleton_skull": true, + "skeleton_wall_skull": true, + "snow": true, + "spruce_hanging_sign": true, + "spruce_wall_hanging_sign": true, + "structure_void": true, + "turtle_egg": true, + "warped_hanging_sign": true, + "warped_wall_hanging_sign": true, + "water_cauldron": true, + "white_banner": true, + "white_bed": true, + "white_candle": true, + "white_wall_banner": true, + "wither_skeleton_skull": true, + "wither_skeleton_wall_skull": true, + "yellow_banner": true, + "yellow_bed": true, + "yellow_candle": true, + "yellow_wall_banner": true, + "zombie_head": true, + "zombie_wall_head": true, + } + `) }) diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts index e0d2ef41..24b85cc3 100644 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts @@ -419,6 +419,7 @@ const handlers = [ [/(.+)_wall_sign$/, handleSign], [/(.+)_sign$/, handleSign], [/^(?:(ender|trapped)_)?chest$/, handleChest], + // [/(^|(.+)_)bed$/, handleBed], // no-op just suppress warning [/(^light|^moving_piston$)/, true], ] as const From 893f6182413e8ea5fef964a5a59897fb4be1e455 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Thu, 23 May 2024 00:54:41 +0300 Subject: [PATCH 0104/1097] hotfix starfield crash (#127) --- prismarine-viewer/viewer/lib/worldrendererThree.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index acf0e7bf..24b6a28a 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -323,7 +323,7 @@ class StarField { const clock = new THREE.Clock(); this.points.onBeforeRender = (renderer, scene, camera) => { - this.points!.position.copy(camera.position) + this.points?.position.copy?.(camera.position) material.uniforms.time.value = clock.getElapsedTime() * speed } } From c1d7d7c33f68c46f1a51cd33ba975251bc6bf77f Mon Sep 17 00:00:00 2001 From: gguio <109200692+gguio@users.noreply.github.com> Date: Thu, 23 May 2024 09:46:59 +0400 Subject: [PATCH 0105/1097] feat: Support for binds with modifiers (#130) Co-authored-by: gguio --- package.json | 2 +- pnpm-lock.yaml | 64 ++++++++++++++++++++++++++++----- src/controls.ts | 24 ++++++------- src/react/KeybindingsScreen.tsx | 32 +++++++++++++---- 4 files changed, 94 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index 6e73b981..9451b266 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "constants-browserify": "^1.0.0", - "contro-max": "^0.1.7", + "contro-max": "^0.1.8", "crypto-browserify": "^3.12.0", "cypress": "^10.11.0", "cypress-esbuild-preprocessor": "^1.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d784e17..8d34f233 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -268,8 +268,8 @@ importers: specifier: ^1.0.0 version: 1.0.0 contro-max: - specifier: ^0.1.7 - version: 0.1.7(typescript@5.5.0-beta) + specifier: ^0.1.8 + version: 0.1.8(typescript@5.5.0-beta) crypto-browserify: specifier: ^3.12.0 version: 3.12.0 @@ -3808,8 +3808,8 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - contro-max@0.1.7: - resolution: {integrity: sha512-HIYF1Dl50tUyTKaDsX+mPMDv2OjleNMVedYuBTX0n1wKNm9WxjWu2w74ATjz/8fHVL9GgmziIxAlFStd2je6kg==} + contro-max@0.1.8: + resolution: {integrity: sha512-5SoeudO8Zzfj/gbFTDrMRFJny02+MY1lBtb2NyCNiBLtHAfvhWZxZs/Z3yJvKL2rY/qKUZs9gTQOIDygBcBrdw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} convert-source-map@1.9.0: @@ -6043,6 +6043,11 @@ packages: resolution: {integrity: sha512-IHL8faXLLIWv1O+2v2NgyKlooilu/OiSL9orI8Kqed/rZvVOrFPzs2PwMAYjpQX9gxLPhiSU19KqZ8CjfNuqhg==} engines: {node: '>=14'} + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc: + resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc} + version: 1.47.0 + engines: {node: '>=14'} + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7: resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7} version: 1.47.0 @@ -6717,6 +6722,11 @@ packages: prismarine-chat@1.9.1: resolution: {integrity: sha512-x7WWa5MNhiLZSO6tw+YyKpzquFZ+DNISVgiV6K3SU0GsishMXe+nto02WhF/4AuFerKdugm9u1d/r4C4zSkJOg==} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16} + version: 1.35.0 + engines: {node: '>=14'} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f: resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f} version: 1.35.0 @@ -11936,11 +11946,11 @@ snapshots: flatmap: 0.0.3 long: 5.2.3 minecraft-data: 3.65.0 - minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -12839,7 +12849,7 @@ snapshots: content-type@1.0.5: {} - contro-max@0.1.7(typescript@5.5.0-beta): + contro-max@0.1.8(typescript@5.5.0-beta): dependencies: events: 3.3.0 lodash-es: 4.17.21 @@ -13206,7 +13216,7 @@ snapshots: diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687: dependencies: minecraft-data: 3.65.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) random-seed: 0.3.0 vec3: 0.1.8 @@ -15700,6 +15710,31 @@ snapshots: - encoding - supports-color + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13): + dependencies: + '@types/readable-stream': 4.0.12 + aes-js: 3.1.2 + buffer-equal: 1.0.1 + debug: 4.3.4(supports-color@8.1.1) + endian-toggle: 0.0.0 + lodash.get: 4.4.2 + lodash.merge: 4.6.2 + minecraft-data: 3.65.0 + minecraft-folder-path: 1.2.0 + node-fetch: 2.7.0(encoding@0.1.13) + node-rsa: 0.4.2 + prismarine-auth: 2.4.2(encoding@0.1.13) + prismarine-chat: 1.10.1 + prismarine-nbt: 2.5.0 + prismarine-realms: 1.3.2(encoding@0.1.13) + protodef: 1.15.0 + readable-stream: 4.5.2 + uuid-1345: 1.0.2 + yggdrasil: 1.7.0(encoding@0.1.13) + transitivePeerDependencies: + - encoding + - supports-color + minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13): dependencies: '@types/readable-stream': 4.0.12 @@ -16520,6 +16555,19 @@ snapshots: prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0): + dependencies: + prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-nbt: 2.5.0 + prismarine-registry: 1.7.0 + smart-buffer: 4.2.0 + uint4: 0.1.2 + vec3: 0.1.8 + xxhash-wasm: 0.4.2 + transitivePeerDependencies: + - minecraft-data + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) diff --git a/src/controls.ts b/src/controls.ts index 847741cf..f940d59d 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -6,7 +6,7 @@ import { proxy, subscribe } from 'valtio' import { ControMax } from 'contro-max/build/controMax' import { CommandEventArgument, SchemaCommandInput } from 'contro-max/build/types' import { stringStartsWith } from 'contro-max/build/stringUtils' -import { UserOverridesConfig } from 'contro-max/build/types/store' +import { UserOverrideCommand, UserOverridesConfig } from 'contro-max/build/types/store' import { isGameActive, showModal, gameAdditionalState, activeModalStack, hideCurrentModal, miscUiState } from './globalState' import { goFullscreen, pointerLock, reloadChunks } from './utils' import { options } from './optionsStorage' @@ -19,6 +19,7 @@ import { showOptionsModal } from './react/SelectOption' import widgets from './react/widgets' import { getItemFromBlock } from './botUtils' import { gamepadUiCursorState, moveGamepadCursorByPx } from './react/GamepadUiCursor' +import { updateBinds } from './react/KeybindingsScreenProvider' export const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}')) as UserOverridesConfig @@ -86,7 +87,7 @@ export const contro = new ControMax({ window.controMax = contro export type Command = CommandEventArgument['command'] -// updateCustomBinds() +updateBinds(customKeymaps) const updateDoPreventDefault = () => { controlOptions.preventDefault = miscUiState.gameLoaded && !activeModalStack.length @@ -296,19 +297,18 @@ function cycleHotbarSlot (dir: 1 | -1) { bot.setQuickBarSlot(newHotbarSlot) } -// custom commands hamdler -const customCommandsHandler = (buttonData: { code?: string, button?: string, state: boolean }) => { - if (!buttonData.state || !isGameActive(true)) return +// custom commands handler +const customCommandsHandler = ({ command }) => { + const [section, name] = command.split('.') + if (!isGameActive(true) || section !== 'custom') return - const codeOrButton = buttonData.code ?? buttonData.button - const inputType = buttonData.code ? 'keys' : 'gamepad' - for (const value of Object.values(contro.userConfig!.custom ?? {})) { - if (value[inputType]?.includes(codeOrButton!)) { - customCommandsConfig[(value as CustomCommand).type].handler((value as CustomCommand).inputs) - } + if (contro.userConfig?.custom) { + customCommandsConfig[(contro.userConfig.custom[name] as CustomCommand).type].handler( + (contro.userConfig.custom[name] as CustomCommand).inputs + ) } } -contro.on('pressedKeyOrButtonChanged', customCommandsHandler) +contro.on('trigger', customCommandsHandler) contro.on('trigger', ({ command }) => { const willContinue = !isGameActive(true) diff --git a/src/react/KeybindingsScreen.tsx b/src/react/KeybindingsScreen.tsx index 57d7d7ef..2de24de8 100644 --- a/src/react/KeybindingsScreen.tsx +++ b/src/react/KeybindingsScreen.tsx @@ -1,5 +1,6 @@ import { useState, useEffect, useRef, createContext, useContext } from 'react' import { UserOverridesConfig } from 'contro-max/build/types/store' +import { ModifierOnlyKeys } from 'contro-max/build/types/keyCodes' import { contro as controEx } from '../controls' import { hideModal } from '../globalState' import triangle from './ps_icons/playstation_triangle_console_controller_gamepad_icon.svg' @@ -96,22 +97,35 @@ export default ( updateBindMap() }, [userConfig]) - const updateBinding = (data) => { - if (data.state === true || !awaitingInputType) return + const updateBinding = (data: any) => { + if ((!data.state && awaitingInputType) || !awaitingInputType) { + setAwaitingInputType(null) + return + } + + if ('code' in data) { + if (data.state && [...contro.pressedKeys].includes(data.code)) return + if (data.code === 'Escape' || ['Mouse0', 'Mouse1', 'Mouse2'].includes(data.code)) { setAwaitingInputType(null) return } - setBinding({ code: data.code, state: true }, groupName, actionName, buttonNum) + const pressedModifiers = [...contro.pressedKeys].filter( + key => /^(Meta|Control|Alt|Shift)?$/.test(key) + ) + setBinding( + { code: pressedModifiers.length ? `${pressedModifiers[0]}+${data.code}` : data.code, state: true }, + groupName, + actionName, + buttonNum + ) } if ('button' in data) { contro.enabled = false void Promise.resolve().then(() => { contro.enabled = true }) setBinding(data, groupName, actionName, buttonNum) } - - setAwaitingInputType(null) } const updateBindMap = () => { @@ -368,8 +382,12 @@ const parseActionName = (action: string) => { const parseBindingName = (binding: string | undefined) => { if (!binding) return '' const cut = binding.replaceAll(/(Numpad|Digit|Key)/g, '') - const parts = cut.split(/(?=[A-Z\d])/) - return parts.reverse().join(' ') + + const parts = cut.includes('+') ? cut.split('+') : [cut] + for (let i = 0; i < parts.length; i++) { + parts[i] = parts[i].split(/(?=[A-Z\d])/).reverse().join(' ') + } + return parts.join(' + ') } const buttonsMap = { From 1de6ae8f2c71cc8a2d2ebbb9029c962dfe079f61 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 24 May 2024 04:19:33 +0300 Subject: [PATCH 0106/1097] fix: Fix crash in getItemUv function. now dropped items are always displayed --- src/index.ts | 39 ++++++++++++++++++++++++-------------- src/react/ChatProvider.tsx | 2 +- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/index.ts b/src/index.ts index 1797c894..89baaa10 100644 --- a/src/index.ts +++ b/src/index.ts @@ -142,24 +142,35 @@ new THREE.TextureLoader().load(itemsPng, (texture) => { viewer.entities.itemsTexture = texture // todo unify viewer.entities.getItemUv = (id) => { - const name = loadedData.items[id]?.name - const uv = itemsAtlases.latest.textures[name] - if (!uv) { - const variant = viewer.world.downloadedBlockStatesData[name]?.variants?.[''] - if (!variant) return - const uvBlock = (Array.isArray(variant) ? variant[0] : variant).model?.elements?.[0]?.faces?.north.texture - if (!uvBlock) return + try { + const name = loadedData.items[id]?.name + const uv = itemsAtlases.latest.textures[name] + if (!uv) { + const variant = viewer.world.downloadedBlockStatesData[name]?.variants?.[''] + if (!variant) return + const faces = (Array.isArray(variant) ? variant[0] : variant).model?.elements?.[0]?.faces + const uvBlock = faces?.north?.texture ?? faces?.up?.texture ?? faces?.down?.texture ?? faces?.west?.texture ?? faces?.east?.texture ?? faces?.south?.texture + if (!uvBlock) return + return { + ...uvBlock, + size: Math.abs(uvBlock.su), + texture: viewer.world.material.map + } + } return { - ...uvBlock, - size: Math.abs(uvBlock.su), + ...uv, + size: itemsAtlases.latest.size, + texture: viewer.entities.itemsTexture + } + } catch (err) { + reportError?.(err) + return { + u: 0, + v: 0, + size: 16 / viewer.world.material.map!.image.width, texture: viewer.world.material.map } } - return { - ...uv, - size: itemsAtlases.latest.size, - texture: viewer.entities.itemsTexture - } } }) viewer.entities.entitiesOptions = { diff --git a/src/react/ChatProvider.tsx b/src/react/ChatProvider.tsx index 0322c60f..ad4a705d 100644 --- a/src/react/ChatProvider.tsx +++ b/src/react/ChatProvider.tsx @@ -74,7 +74,7 @@ export default () => { if (items[0].match) items = items.map(i => i.match) } if (completeValue === '/') { - if (!items[0].startsWith('/')) { + if (!items[0]?.startsWith('/')) { // normalize items = items.map(item => `/${item}`) } From 8fdcbdfc60bd42e769c4aa0895722f586690ecfe Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 24 May 2024 04:21:41 +0300 Subject: [PATCH 0107/1097] fix: fix more starfield issues, make disableable --- .../viewer/lib/worldrendererThree.ts | 13 ++++++ src/entities.ts | 1 + src/optionsGuiScheme.tsx | 1 + src/optionsStorage.ts | 42 +++++++++++-------- src/watchOptions.ts | 5 +++ 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 24b6a28a..a2082a53 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -277,11 +277,23 @@ export class WorldRendererThree extends WorldRendererCommon { class StarField { points?: THREE.Points + private _enabled = true + get enabled () { + return this._enabled + } + set enabled (value) { + this._enabled = value + if (this.points) { + this.points.visible = value + } + } constructor(private scene: THREE.Scene) { } addToScene () { + if (this.points || !this.enabled) return + const radius = 80 const depth = 50 const count = 7000 @@ -332,6 +344,7 @@ class StarField { if (this.points) { this.points.geometry.dispose(); (this.points.material as THREE.Material).dispose(); + this.scene.remove(this.points) this.points = undefined; } diff --git a/src/entities.ts b/src/entities.ts index dbb59bed..b238d4ea 100644 --- a/src/entities.ts +++ b/src/entities.ts @@ -14,6 +14,7 @@ const updateAutoJump = () => { jumpOnAllEdges: options.autoParkour, // strictBlockCollision: true, }) + if (autoJump === bot.autoJumper.enabled) return if (autoJump) { bot.autoJumper.enable() } else { diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 46f258a8..88e6115f 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -69,6 +69,7 @@ export const guiOptionsScheme: { enableWarning: 'Enabling it will make chunks load ~4x slower', disabledDuringGame: true }, + starfieldRendering: {} }, ], main: [ diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index 9350d5ab..ed71cfdb 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -30,24 +30,7 @@ const defaultOptions = { touchButtonsSize: 40, touchButtonsOpacity: 80, touchButtonsPosition: 12, - touchControlsPositions: { - action: [ - 70, - 85 - ], - sneak: [ - 90, - 85 - ], - break: [ - 70, - 65 - ], - jump: [ - 90, - 65 - ], - } as Record, + touchControlsPositions: getDefaultTouchControlsPositions(), touchControlsType: 'classic' as 'classic' | 'joystick-buttons', gpuPreference: 'default' as 'default' | 'high-performance' | 'low-power', backgroundRendering: '20fps' as 'full' | '20fps' | '5fps', @@ -59,6 +42,7 @@ const defaultOptions = { dayCycleAndLighting: true, loadPlayerSkins: true, lowMemoryMode: false, + starfieldRendering: true, // antiAliasing: false, showChunkBorders: false, // todo rename option @@ -73,6 +57,7 @@ const defaultOptions = { disableLoadPrompts: false, guestUsername: 'guest', askGuestName: true, + errorReporting: true, /** Actually might be useful */ showCursorBlockInSpectator: false, renderEntities: true, @@ -91,6 +76,27 @@ const defaultOptions = { wysiwygSignEditor: 'auto' as 'auto' | 'always' | 'never', } +function getDefaultTouchControlsPositions () { + return { + action: [ + 70, + 85 + ], + sneak: [ + 90, + 85 + ], + break: [ + 70, + 65 + ], + jump: [ + 90, + 65 + ], + } as Record +} + const qsOptionsRaw = new URLSearchParams(location.search).getAll('setting') export const qsOptions = Object.fromEntries(qsOptionsRaw.map(o => { const [key, value] = o.split(':') diff --git a/src/watchOptions.ts b/src/watchOptions.ts index 56fc9c2c..4ff34be4 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -57,4 +57,9 @@ export const watchOptionsAfterViewerInit = () => { customEvents.on('gameLoaded', () => { viewer.world.mesherConfig.enableLighting = !bot.supportFeature('blockStateId') || options.newVersionsLighting }) + + watchValue(options, o => { + if (!(viewer.world instanceof WorldRendererThree)) return + viewer.world.starField.enabled = o.starfieldRendering + }) } From f2137d95a1a1ca0af04ebde6bd4c3b9194a1370f Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 24 May 2024 04:33:54 +0300 Subject: [PATCH 0108/1097] fix: fix critical memory leak block in the scene were not removed from the memory --- prismarine-viewer/viewer/lib/dispose.js | 6 ---- prismarine-viewer/viewer/lib/entities.js | 30 +++++++++---------- prismarine-viewer/viewer/lib/primitives.js | 7 ++--- prismarine-viewer/viewer/lib/threeJsUtils.ts | 13 ++++++++ .../viewer/lib/worldrendererThree.ts | 7 ++--- 5 files changed, 34 insertions(+), 29 deletions(-) delete mode 100644 prismarine-viewer/viewer/lib/dispose.js create mode 100644 prismarine-viewer/viewer/lib/threeJsUtils.ts diff --git a/prismarine-viewer/viewer/lib/dispose.js b/prismarine-viewer/viewer/lib/dispose.js deleted file mode 100644 index 15ec7b4b..00000000 --- a/prismarine-viewer/viewer/lib/dispose.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - dispose3 (o) { - o.geometry?.dispose() - o.dispose?.() - } -} diff --git a/prismarine-viewer/viewer/lib/entities.js b/prismarine-viewer/viewer/lib/entities.js index 136c77fe..930f62c9 100644 --- a/prismarine-viewer/viewer/lib/entities.js +++ b/prismarine-viewer/viewer/lib/entities.js @@ -2,7 +2,6 @@ import * as THREE from 'three' import * as TWEEN from '@tweenjs/tween.js' import * as Entity from './entity/EntityMesh' -import { dispose3 } from './dispose' import nbt from 'prismarine-nbt' import EventEmitter from 'events' import { PlayerObject, PlayerAnimation } from 'skinview3d' @@ -14,10 +13,11 @@ import { NameTagObject } from 'skinview3d/libs/nametag' import { flat, fromFormattedString } from '@xmcl/text-component' import mojangson from 'mojangson' import externalTexturesJson from './entity/externalTextures.json' +import { disposeObject } from './threeJsUtils' export const TWEEN_DURATION = 50 // todo should be 100 -function getUsernameTexture(username, { fontFamily = 'sans-serif' }) { +function getUsernameTexture (username, { fontFamily = 'sans-serif' }) { const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') if (!ctx) throw new Error('Could not get 2d context') @@ -61,7 +61,7 @@ const addNametag = (entity, options, mesh) => { // todo cleanup const nametags = {} -function getEntityMesh(entity, scene, options, overrides) { +function getEntityMesh (entity, scene, options, overrides) { if (entity.name) { try { // https://github.com/PrismarineJS/prismarine-viewer/pull/410 @@ -105,15 +105,15 @@ export class Entities extends EventEmitter { this.getItemUv = undefined } - clear() { + clear () { for (const mesh of Object.values(this.entities)) { this.scene.remove(mesh) - dispose3(mesh) + disposeObject(mesh) } this.entities = {} } - setDebugMode(mode, /** @type {THREE.Object3D?} */entity = null) { + setDebugMode (mode, /** @type {THREE.Object3D?} */entity = null) { this.debugMode = mode for (const mesh of entity ? [entity] : Object.values(this.entities)) { const boxHelper = mesh.children.find(c => c.name === 'debug') @@ -125,14 +125,14 @@ export class Entities extends EventEmitter { } } - setVisible(visible, /** @type {THREE.Object3D?} */entity = null) { + setVisible (visible, /** @type {THREE.Object3D?} */entity = null) { this.visible = visible for (const mesh of entity ? [entity] : Object.values(this.entities)) { mesh.visible = visible } } - render() { + render () { const dt = this.clock.getDelta() for (const entityId of Object.keys(this.entities)) { const playerObject = this.getPlayerObject(entityId) @@ -142,7 +142,7 @@ export class Entities extends EventEmitter { } } - getPlayerObject(entityId) { + getPlayerObject (entityId) { /** @type {(PlayerObject & { animation?: PlayerAnimation }) | undefined} */ const playerObject = this.entities[entityId]?.playerObject return playerObject @@ -152,7 +152,7 @@ export class Entities extends EventEmitter { defaultSteveTexture // true means use default skin url - updatePlayerSkin(entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { + updatePlayerSkin (entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { let playerObject = this.getPlayerObject(entityId) if (!playerObject) return // const username = this.entities[entityId].username @@ -235,14 +235,14 @@ export class Entities extends EventEmitter { playerObject.cape.map = null } - function isCanvasBlank(canvas) { + function isCanvasBlank (canvas) { return !canvas.getContext('2d') .getImageData(0, 0, canvas.width, canvas.height).data .some(channel => channel !== 0) } } - playAnimation(entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { + playAnimation (entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { const playerObject = this.getPlayerObject(entityPlayerId) if (!playerObject) return @@ -262,14 +262,14 @@ export class Entities extends EventEmitter { } - displaySimpleText(jsonLike) { + displaySimpleText (jsonLike) { if (!jsonLike) return const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike) const text = flat(parsed).map(x => x.text) return text.join('') } - update(/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { + update (/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { let isPlayerModel = entity.name === 'player' if (entity.name === 'zombie' || entity.name === 'zombie_villager' || entity.name === 'husk') { isPlayerModel = true @@ -456,7 +456,7 @@ export class Entities extends EventEmitter { if (e.additionalCleanup) e.additionalCleanup() this.emit('remove', entity) this.scene.remove(e) - dispose3(e) + disposeObject(e) // todo dispose textures as well ? delete this.entities[entity.id] } diff --git a/prismarine-viewer/viewer/lib/primitives.js b/prismarine-viewer/viewer/lib/primitives.js index f206ee87..c8a0c006 100644 --- a/prismarine-viewer/viewer/lib/primitives.js +++ b/prismarine-viewer/viewer/lib/primitives.js @@ -1,6 +1,5 @@ const THREE = require('three') const { MeshLine, MeshLineMaterial } = require('three.meshline') -const { dispose3 } = require('./dispose') function getMesh (primitive, camera) { if (primitive.type === 'line') { @@ -48,7 +47,7 @@ function getMesh (primitive, camera) { } class Primitives { - constructor (scene, camera) { + constructor(scene, camera) { this.scene = scene this.camera = camera this.primitives = {} @@ -57,7 +56,7 @@ class Primitives { clear () { for (const mesh of Object.values(this.primitives)) { this.scene.remove(mesh) - dispose3(mesh) + disposeObject(mesh) } this.primitives = {} } @@ -65,7 +64,7 @@ class Primitives { update (primitive) { if (this.primitives[primitive.id]) { this.scene.remove(this.primitives[primitive.id]) - dispose3(this.primitives[primitive.id]) + disposeObject(this.primitives[primitive.id]) delete this.primitives[primitive.id] } diff --git a/prismarine-viewer/viewer/lib/threeJsUtils.ts b/prismarine-viewer/viewer/lib/threeJsUtils.ts new file mode 100644 index 00000000..f856c244 --- /dev/null +++ b/prismarine-viewer/viewer/lib/threeJsUtils.ts @@ -0,0 +1,13 @@ +import * as THREE from 'three'; + +export const disposeObject = (obj: THREE.Object3D) => { + if (!obj) return + // not cleaning texture there as it might be used by other objects, but would be good to also do that + if (obj instanceof THREE.Mesh) { + obj.geometry.dispose(); + obj.material.dispose(); + } + if (obj.children) { + obj.children.forEach(disposeObject); + } +} diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index a2082a53..60156a50 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -1,13 +1,13 @@ import * as THREE from 'three' import { Vec3 } from 'vec3' import nbt from 'prismarine-nbt' -import { dispose3 } from './dispose' import PrismarineChatLoader from 'prismarine-chat' import { renderSign } from '../sign-renderer/' import { chunkPos, sectionPos } from './simpleUtils' import { WorldRendererCommon, WorldRendererConfig } from './worldrendererCommon' import * as tweenJs from '@tweenjs/tween.js' import { BloomPass, RenderPass, UnrealBloomPass, EffectComposer, WaterPass, GlitchPass } from 'three-stdlib' +import { disposeObject } from './threeJsUtils' export class WorldRendererThree extends WorldRendererCommon { outputFormat = 'threeJs' as const @@ -62,7 +62,7 @@ export class WorldRendererThree extends WorldRendererCommon { let object: THREE.Object3D = this.sectionObjects[data.key] if (object) { this.scene.remove(object) - dispose3(object) + disposeObject(object) delete this.sectionObjects[data.key] } @@ -263,7 +263,7 @@ export class WorldRendererThree extends WorldRendererCommon { const mesh = this.sectionObjects[key] if (mesh) { this.scene.remove(mesh) - dispose3(mesh) + disposeObject(mesh) } delete this.sectionObjects[key] } @@ -327,7 +327,6 @@ class StarField { material.blending = THREE.AdditiveBlending material.depthTest = false material.transparent = true - // material.unifo // Create points and add them to the scene this.points = new THREE.Points(geometry, material) From fcec85baa39f212a98e43a46b6bffa0eebc8455c Mon Sep 17 00:00:00 2001 From: Vitaly Date: Fri, 24 May 2024 10:21:03 +0300 Subject: [PATCH 0109/1097] feat: Make bow, foods cancellable and add use progression indicator feat: make item in offhand activatable --- prismarine-viewer/viewer/lib/threeJsUtils.ts | 5 +- src/react/Crosshair.css | 35 +++++++---- src/react/Crosshair.tsx | 64 +++++++++++++++++++- src/react/TitleProvider.tsx | 1 + src/worldInteractions.ts | 42 +++++++++---- 5 files changed, 121 insertions(+), 26 deletions(-) diff --git a/prismarine-viewer/viewer/lib/threeJsUtils.ts b/prismarine-viewer/viewer/lib/threeJsUtils.ts index f856c244..e4f9404b 100644 --- a/prismarine-viewer/viewer/lib/threeJsUtils.ts +++ b/prismarine-viewer/viewer/lib/threeJsUtils.ts @@ -1,11 +1,10 @@ import * as THREE from 'three'; export const disposeObject = (obj: THREE.Object3D) => { - if (!obj) return // not cleaning texture there as it might be used by other objects, but would be good to also do that if (obj instanceof THREE.Mesh) { - obj.geometry.dispose(); - obj.material.dispose(); + obj.geometry?.dispose?.(); + obj.material?.dispose?.(); } if (obj.children) { obj.children.forEach(disposeObject); diff --git a/src/react/Crosshair.css b/src/react/Crosshair.css index 94252ffa..7076f475 100644 --- a/src/react/Crosshair.css +++ b/src/react/Crosshair.css @@ -1,12 +1,25 @@ .crosshair { - z-index: -1; - width: 16px; - height: 16px; - background: var(--gui-icons); - background-size: calc(256px * var(--crosshair-scale)); - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - image-rendering: pixelated; - } + z-index: -1; + width: 16px; + height: 16px; + background: var(--gui-icons); + background-size: calc(256px * var(--crosshair-scale)); + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + image-rendering: pixelated; + pointer-events: none; +} + +.crosshair-indicator { + z-index: -1; + width: var(--crosshair-indicator-size); + height: 1.5px; + position: fixed; + top: calc(50% + 8px); + left: 50%; + transform: translate(-50%, -50%); + background: lightgray; + pointer-events: none; +} diff --git a/src/react/Crosshair.tsx b/src/react/Crosshair.tsx index 877b8df4..ab289db8 100644 --- a/src/react/Crosshair.tsx +++ b/src/react/Crosshair.tsx @@ -1,8 +1,70 @@ +import { useEffect, useState } from 'react' import './Crosshair.css' +import { proxy, useSnapshot } from 'valtio' import SharedHudVars from './SharedHudVars' +// todo move to mineflayer +export const itemBeingUsed = proxy({ + name: null as string | null, + hand: 0 as 0 | 1 +}) + export default () => { + const { name: usingItem, hand } = useSnapshot(itemBeingUsed) + + const [displayIndicator, setDisplayIndicator] = useState(true) + const [indicatorProgress, setIndicatorProgress] = useState(0) + const [alternativeIndicator, setAlternativeIndicator] = useState(false) + const boxMaxTimeMs = 1000 + // todo add sword indicator + const indicatorSize = 20 + + useEffect(() => { + bot.on('heldItemChanged' as any, () => { + const displayBar = (item: import('prismarine-item').Item | null) => { + const itemName = item?.name + if (!itemName) return + return loadedData.foodsArray.map((food) => food.name).includes(itemName) || itemName === 'bow' || itemName === 'shield' || itemName === 'crossbow' + } + setDisplayIndicator(displayBar(bot.heldItem) || displayBar(bot.inventory.slots[45]) || false) + }) + }, []) + + useEffect(() => { + setAlternativeIndicator(usingItem === 'shield') + if (!usingItem) return + const startTime = Date.now() + let maxTime = 0 + if (usingItem === 'bow' || usingItem === 'crossbow') { + maxTime = 1000 + } + const isFood = loadedData.foodsArray.some((food) => food.name === usingItem) + if (isFood) { + maxTime = 32 * 50 + } + if (!maxTime) return + + const id = setInterval(() => { + const progress = (Date.now() - startTime) / boxMaxTimeMs + if (progress >= 1) { + clearInterval(id) + } else { + setIndicatorProgress(progress) + } + }, 1000 / 60) + return () => { + setIndicatorProgress(0) + clearInterval(id) + } + }, [usingItem]) + return -
+
+ {displayIndicator &&
} } diff --git a/src/react/TitleProvider.tsx b/src/react/TitleProvider.tsx index 151a93c1..f19669ec 100644 --- a/src/react/TitleProvider.tsx +++ b/src/react/TitleProvider.tsx @@ -23,6 +23,7 @@ export default () => { const [openActionBar, setOpenActionBar] = useState(false) useMemo(() => { + // todo move to mineflayer bot._client.on('set_title_text', (packet) => { setTitle(JSON.parse(packet.text)) setOpenTitle(true) diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 85884b2f..239c02c2 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -17,6 +17,7 @@ import { LineMaterial, Wireframe, LineSegmentsGeometry } from 'three-stdlib' import { hideCurrentModal, isGameActive, showModal } from './globalState' import { assertDefined } from './utils' import { options } from './optionsStorage' +import { itemBeingUsed } from './react/Crosshair' function getViewDirection (pitch, yaw) { const csPitch = Math.cos(pitch) @@ -133,6 +134,9 @@ class WorldInteraction { } this.lastDugBlock = null }) + bot.on('heldItemChanged' as any, () => { + itemBeingUsed.name = null + }) const upLineMaterial = () => { const inCreative = bot.game.gameMode === 'creative' @@ -191,16 +195,20 @@ class WorldInteraction { // Place / interact / activate if (this.buttons[2] && this.lastBlockPlaced >= 4) { - const activate = bot.heldItem && ['egg', 'fishing_rod', 'firework_rocket', - 'fire_charge', 'snowball', 'ender_pearl', 'experience_bottle', 'potion', - 'glass_bottle', 'bucket', 'water_bucket', 'lava_bucket', 'milk_bucket', - 'minecart', 'boat', 'tnt_minecart', 'chest_minecart', 'hopper_minecart', - 'command_block_minecart', 'armor_stand', 'lead', 'name_tag', - // - 'writable_book', 'written_book', 'compass', 'clock', 'filled_map', 'empty_map', 'map', - 'shears', 'carrot_on_a_stick', 'warped_fungus_on_a_stick', - 'spawn_egg', 'trident', 'crossbow', 'elytra', 'shield', 'turtle_helmet', - ].includes(bot.heldItem.name) + const activatableItems = (itemName: string) => { + return ['egg', 'fishing_rod', 'firework_rocket', + 'fire_charge', 'snowball', 'ender_pearl', 'experience_bottle', 'potion', + 'glass_bottle', 'bucket', 'water_bucket', 'lava_bucket', 'milk_bucket', + 'minecart', 'boat', 'tnt_minecart', 'chest_minecart', 'hopper_minecart', + 'command_block_minecart', 'armor_stand', 'lead', 'name_tag', + // + 'writable_book', 'written_book', 'compass', 'clock', 'filled_map', 'empty_map', 'map', + 'shears', 'carrot_on_a_stick', 'warped_fungus_on_a_stick', + 'spawn_egg', 'trident', 'crossbow', 'elytra', 'shield', 'turtle_helmet', 'bow', 'crossbow', 'bucket_of_cod', + ...loadedData.foodsArray.map((f) => f.name), + ].includes(itemName) + } + const activate = bot.heldItem && activatableItems(bot.heldItem.name) let stop = false if (!bot.controlState.sneak) { if (cursorBlock?.name === 'bed' || cursorBlock?.name.endsWith('_bed')) { @@ -223,6 +231,7 @@ class WorldInteraction { }) } } + // todo placing with offhand if (cursorBlock && !activate && !stop) { const vecArray = [new Vec3(0, -1, 0), new Vec3(0, 1, 0), new Vec3(0, 0, -1), new Vec3(0, 0, 1), new Vec3(-1, 0, 0), new Vec3(1, 0, 0)] //@ts-expect-error @@ -242,10 +251,21 @@ class WorldInteraction { }).catch(console.warn) } } else if (!stop) { - bot.activateItem() // todo offhand + const offhand = activate ? false : activatableItems(bot.inventory.slots[45]?.name ?? '') + bot.activateItem(offhand) // todo offhand + itemBeingUsed.name = (offhand ? bot.inventory.slots[45]?.name : bot.heldItem?.name) ?? null + itemBeingUsed.hand = offhand ? 1 : 0 } this.lastBlockPlaced = 0 } + // stop using activated item (cancel) + if (itemBeingUsed.name && !this.buttons[2]) { + itemBeingUsed.name = null + // "only foods and bow can be deactivated" - not true, shields also can be deactivated and client always sends this + // if (bot.heldItem && (loadedData.foodsArray.map((f) => f.name).includes(bot.heldItem.name) || bot.heldItem.name === 'bow')) { + bot.deactivateItem() + // } + } // Stop break if ((!this.buttons[0] && this.lastButtons[0]) || cursorChanged) { From 87e724d5f6d7d4b8630a5f491857e8042f3206c6 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Fri, 24 May 2024 11:05:44 +0300 Subject: [PATCH 0110/1097] fix: fix offhand slot in hotbar display --- pnpm-lock.yaml | 8 ++++---- src/react/HotbarRenderApp.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8d34f233..6fdf4afa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -299,7 +299,7 @@ importers: version: 1.0.0 minecraft-inventory-gui: specifier: github:zardoy/minecraft-inventory-gui#next - version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c(@types/react@18.2.20)(react@18.2.0) + version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5(@types/react@18.2.20)(react@18.2.0) mineflayer: specifier: github:PrismarineJS/mineflayer version: https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f(encoding@0.1.13) @@ -6035,8 +6035,8 @@ packages: minecraft-folder-path@1.2.0: resolution: {integrity: sha512-qaUSbKWoOsH9brn0JQuBhxNAzTDMwrOXorwuRxdJKKKDYvZhtml+6GVCUrY5HRiEsieBEjCUnhVpDuQiKsiFaw==} - minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c: - resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c} + minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5: + resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5} version: 1.0.1 minecraft-protocol@1.47.0: @@ -15678,7 +15678,7 @@ snapshots: minecraft-folder-path@1.2.0: {} - minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/5554c7ab0a74bce52aa5f5f04a48eb8d3b9ac65c(@types/react@18.2.20)(react@18.2.0): + minecraft-inventory-gui@https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5(@types/react@18.2.20)(react@18.2.0): dependencies: valtio: 1.11.2(@types/react@18.2.20)(react@18.2.0) transitivePeerDependencies: diff --git a/src/react/HotbarRenderApp.tsx b/src/react/HotbarRenderApp.tsx index 3b50f49b..02689485 100644 --- a/src/react/HotbarRenderApp.tsx +++ b/src/react/HotbarRenderApp.tsx @@ -93,7 +93,7 @@ export default () => { }, } as any) const { canvasManager } = inv - inv.inventory.supportsOffhand = bot.supportFeature('doesntHaveOffHandSlot') + inv.inventory.supportsOffhand = !bot.supportFeature('doesntHaveOffHandSlot') inv.pwindow.disablePicking = true canvasManager.children[0].disableHighlight = true From f4ef8f7d85e16727887fddc6c90228ccf235690d Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 25 May 2024 00:18:43 +0300 Subject: [PATCH 0111/1097] cleanup: remove preflat handling --- .../viewer/prepare/moreGeneratedBlocks.ts | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts index 24b85cc3..ffb1a705 100644 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts @@ -1,6 +1,5 @@ import Jimp from 'jimp' import minecraftData from 'minecraft-data' -import prismarineRegistry from 'prismarine-registry' import { McAssets } from './modelsBuilder' import path from 'path' import fs from 'fs' @@ -11,8 +10,6 @@ const twoTileTextures: string[] = [] let currentImage: Jimp let currentBlockName: string let currentMcAssets: McAssets -let isPreFlattening = false -const postFlatenningRegistry = prismarineRegistry('1.13') const __dirname = path.dirname(fileURLToPath(new URL(import.meta.url))) type SidesType = { @@ -24,9 +21,9 @@ type SidesType = { "down": string } -const getBlockStates = (name: string, postFlatenningName = name) => { - const mcData = isPreFlattening ? postFlatenningRegistry : minecraftData(currentMcAssets.version) - return mcData.blocksByName[isPreFlattening ? postFlatenningName : name]?.states +const getBlockStates = (name: string) => { + const mcData = minecraftData(currentMcAssets.version) + return mcData.blocksByName[name]?.states } export const addBlockCustomSidesModel = (name: string, sides: SidesType) => { @@ -124,7 +121,7 @@ const handleShulkerBox = async (dataBase: string, match: RegExpExecArray) => { } const handleSign = async (dataBase: string, match: RegExpExecArray) => { - const states = getBlockStates(currentBlockName, currentBlockName === 'wall_sign' ? 'wall_sign' : 'sign') + const states = getBlockStates(currentBlockName) if (!states) return const [, signMaterial = ''] = match @@ -375,17 +372,11 @@ const handleChest = async (dataBase: string, match: RegExpExecArray) => { if (modelName.endsWith('_left')) chestTextureName = `${chestTextureName}_left` if (modelName.endsWith('_right')) chestTextureName = `${chestTextureName}_right` - // reading latest version since the texture wasn't changed, but in pre-flatenning need custom mapping for doubled_chest const texture = path.join(currentMcAssets.directory, `../1.19.1/entity/chest/${chestTextureName}.png`) currentImage = await Jimp.read(texture) const model = structuredClone(chestModels[modelName]) - // todo < 1.9 - if (currentMcAssets.version === '1.8.8') { - // doesn't have definition of block yet - model.parent = undefined - } model.textures.particle = particle const newModelName = `${currentBlockName}_${modelName}` for (const variant of blockStatesVariants) { @@ -438,7 +429,6 @@ export const tryHandleBlockEntity = async (dataBase, blockName) => { export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { const mcData = minecraftData(mcAssets.version) - isPreFlattening = !mcData.supportFeature('blockStateId') const allTheBlocks = mcData.blocksArray.map(x => x.name) currentMcAssets = mcAssets From 0d8beef65c5022cf32dd2ea758891bad700e2374 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 26 May 2024 18:58:46 +0300 Subject: [PATCH 0112/1097] feat: add gamemode selector in create world screen. always use creative with ?singleplayer=1 --- cypress/e2e/index.spec.ts | 27 ++----------------- cypress/e2e/shared.ts | 15 +++++++++++ .../viewer/prepare/generateTextures.ts | 7 ++--- scripts/esbuildPlugins.mjs | 18 ++++++------- scripts/githubActions.mjs | 8 +++--- src/optionsStorage.ts | 4 ++- src/react/CreateWorld.tsx | 14 +++++++--- src/react/CreateWorldProvider.tsx | 7 ++--- src/react/Crosshair.tsx | 2 +- src/workerWorkaround.ts | 2 ++ tsconfig.json | 2 +- 11 files changed, 56 insertions(+), 50 deletions(-) create mode 100644 cypress/e2e/shared.ts create mode 100644 src/workerWorkaround.ts diff --git a/cypress/e2e/index.spec.ts b/cypress/e2e/index.spec.ts index 455b1283..05b50211 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,14 +21,8 @@ const testWorldLoad = () => { }) } -const setOptions = (options: Partial) => { - cy.window().then(win => { - Object.assign(win['options'], options) - }) -} - it('Loads & renders singleplayer', () => { - visit('/?singleplayer=1') + cleanVisit('/?singleplayer=1') setOptions({ localServerOptions: { generation: { @@ -69,10 +53,3 @@ it('Loads & renders zip world', () => { cy.get('input[type="file"]').selectFile('cypress/superflat.zip', { force: true }) testWorldLoad() }) - -it.skip('Performance test', () => { - // select that world - // from -2 85 24 - // await bot.loadPlugin(pathfinder.pathfinder) - // bot.pathfinder.goto(new pathfinder.goals.GoalXZ(28, -28)) -}) diff --git a/cypress/e2e/shared.ts b/cypress/e2e/shared.ts new file mode 100644 index 00000000..9292a8d5 --- /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/prismarine-viewer/viewer/prepare/generateTextures.ts b/prismarine-viewer/viewer/prepare/generateTextures.ts index dc838c65..f66fb5d7 100644 --- a/prismarine-viewer/viewer/prepare/generateTextures.ts +++ b/prismarine-viewer/viewer/prepare/generateTextures.ts @@ -19,9 +19,10 @@ const warnings = new Set() Promise.resolve().then(async () => { generateItemsAtlases() console.time('generateTextures') - for (const version of mcAssets.versions as typeof mcAssets['versions']) { + const versions = process.argv.includes('-l') ? [mcAssets.versions.at(-1)!] : mcAssets.versions + for (const version of versions as typeof mcAssets['versions']) { // for debugging (e.g. when above is overridden) - if (!mcAssets.versions.includes(version)) { + if (!versions.includes(version)) { throw new Error(`Version ${version} is not supported by minecraft-assets`) } if (versionToNumber(version) < versionToNumber('1.13')) { @@ -45,7 +46,7 @@ Promise.resolve().then(async () => { fs.copySync(assets.directory, path.resolve(texturesPath, version), { overwrite: true }) } - fs.writeFileSync(path.join(publicPath, 'supportedVersions.json'), '[' + mcAssets.versions.map(v => `"${v}"`).toString() + ']') + fs.writeFileSync(path.join(publicPath, 'supportedVersions.json'), '[' + versions.map(v => `"${v}"`).toString() + ']') warnings.forEach(x => console.warn(x)) console.timeEnd('generateTextures') }) diff --git a/scripts/esbuildPlugins.mjs b/scripts/esbuildPlugins.mjs index f6b539c1..fe4018f3 100644 --- a/scripts/esbuildPlugins.mjs +++ b/scripts/esbuildPlugins.mjs @@ -40,7 +40,7 @@ export const startWatchingHmr = () => { const mesherSharedPlugins = [ { name: 'minecraft-data', - setup (build) { + setup(build) { build.onLoad({ filter: /data[\/\\]pc[\/\\]common[\/\\]legacy.json$/, }, async (args) => { @@ -59,7 +59,7 @@ const plugins = [ ...mesherSharedPlugins, { name: 'strict-aliases', - setup (build) { + setup(build) { build.onResolve({ filter: /^minecraft-protocol$/, }, async ({ kind, resolveDir }) => { @@ -110,7 +110,7 @@ const plugins = [ }, { name: 'data-assets', - setup (build) { + setup(build) { build.onResolve({ filter: /.*/, }, async ({ path, ...rest }) => { @@ -161,7 +161,7 @@ const plugins = [ }, { name: 'prevent-incorrect-linking', - setup (build) { + setup(build) { build.onResolve({ filter: /.+/, }, async ({ resolveDir, path, importer, kind, pluginData }) => { @@ -184,7 +184,7 @@ const plugins = [ }, { name: 'watch-notify', - setup (build) { + setup(build) { let count = 0 let time let prevHash @@ -234,7 +234,7 @@ const plugins = [ }, { name: 'esbuild-readdir', - setup (build) { + setup(build) { build.onResolve({ filter: /^esbuild-readdir:.+$/, }, ({ resolveDir, path }) => { @@ -262,7 +262,7 @@ const plugins = [ }, { name: 'esbuild-import-glob', - setup (build) { + setup(build) { build.onResolve({ filter: /^esbuild-import-glob\(path:(.+),skipFiles:(.+)\)+$/, }, ({ resolveDir, path }) => { @@ -292,7 +292,7 @@ const plugins = [ }, { name: 'fix-dynamic-require', - setup (build) { + setup(build) { build.onResolve({ filter: /1\.14\/chunk/, }, async ({ resolveDir, path }) => { @@ -321,7 +321,7 @@ const plugins = [ }, { name: 'react-displayname', - setup (build) { + setup(build) { build.onLoad({ filter: /.tsx$/, }, async ({ path }) => { diff --git a/scripts/githubActions.mjs b/scripts/githubActions.mjs index ba7b8566..ab786ea9 100644 --- a/scripts/githubActions.mjs +++ b/scripts/githubActions.mjs @@ -6,10 +6,10 @@ const fns = { async getAlias () { const aliasesRaw = process.env.ALIASES if (!aliasesRaw) throw new Error('No aliases found') - const aliases = aliasesRaw.split('\n').map((x) => x.split('=')) + const aliases = aliasesRaw.split('\n').map((x) => x.trim().split('=')) const githubActionsPull = process.env.PULL_URL?.split('/').at(-1) - if (!githubActionsPull) throw new Error(`Not a pull request, got ${process.env.GITHUB_REF}`) - const prNumber = githubActionsPull[1] + if (!githubActionsPull) throw new Error(`Not a pull request, got ${process.env.PULL_URL}`) + const prNumber = githubActionsPull const alias = aliases.find((x) => x[0] === prNumber) if (alias) { // set github output @@ -18,7 +18,7 @@ const fns = { } } -function setOutput(key, value) { +function setOutput (key, value) { // Temporary hack until core actions library catches up with github new recommendations const output = process.env['GITHUB_OUTPUT'] fs.appendFileSync(output, `${key}=${value}${os.EOL}`) diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index ed71cfdb..2a13abf4 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -52,7 +52,9 @@ const defaultOptions = { excludeCommunicationDebugEvents: [], preventDevReloadWhilePlaying: false, numWorkers: 4, - localServerOptions: {} as any, + localServerOptions: { + gameMode: 1 + } as any, preferLoadReadonly: false, disableLoadPrompts: false, guestUsername: 'guest', diff --git a/src/react/CreateWorld.tsx b/src/react/CreateWorld.tsx index ceed77ec..87b36777 100644 --- a/src/react/CreateWorld.tsx +++ b/src/react/CreateWorld.tsx @@ -8,17 +8,19 @@ import styles from './createWorld.module.css' // const worldTypes = ['default', 'flat', 'largeBiomes', 'amplified', 'customized', 'buffet', 'debug_all_block_states'] const worldTypes = ['default', 'flat'/* , 'void' */] +const gameModes = ['survival', 'creative'/* , 'adventure', 'spectator' */] export const creatingWorldState = proxy({ title: '', type: worldTypes[0], + gameMode: gameModes[0], version: '' }) export default ({ cancelClick, createClick, customizeClick, versions, defaultVersion }) => { const [quota, setQuota] = useState('') - const { title, type, version } = useSnapshot(creatingWorldState) + const { title, type, version, gameMode } = useSnapshot(creatingWorldState) useEffect(() => { creatingWorldState.version = defaultVersion void navigator.storage?.estimate?.().then(({ quota, usage }) => { @@ -54,9 +56,15 @@ export default ({ cancelClick, createClick, customizeClick, versions, defaultVer - + {/* */} +
Default and other world types are WIP
diff --git a/src/react/CreateWorldProvider.tsx b/src/react/CreateWorldProvider.tsx index 728e47ff..0f99ec42 100644 --- a/src/react/CreateWorldProvider.tsx +++ b/src/react/CreateWorldProvider.tsx @@ -3,8 +3,8 @@ import { hideCurrentModal, showModal } from '../globalState' import defaultLocalServerOptions from '../defaultLocalServerOptions' import { mkdirRecursive, uniqueFileNameFromWorldName } from '../browserfs' import CreateWorld, { WorldCustomize, creatingWorldState } from './CreateWorld' -import { useIsModalActive } from './utilsApp' import { getWorldsPath } from './SingleplayerProvider' +import { useIsModalActive } from './utilsApp' export default () => { const activeCreate = useIsModalActive('create-world') @@ -23,7 +23,7 @@ export default () => { }} createClick={async () => { // create new world - const { title, type, version } = creatingWorldState + const { title, type, version, gameMode } = creatingWorldState // todo display path in ui + disable if exist const savePath = await uniqueFileNameFromWorldName(title, getWorldsPath()) await mkdirRecursive(savePath) @@ -51,7 +51,8 @@ export default () => { levelName: title, version, generation, - 'worldFolder': savePath + 'worldFolder': savePath, + gameMode: gameMode === 'survival' ? 0 : 1, }, })) }} diff --git a/src/react/Crosshair.tsx b/src/react/Crosshair.tsx index ab289db8..9079fb66 100644 --- a/src/react/Crosshair.tsx +++ b/src/react/Crosshair.tsx @@ -12,7 +12,7 @@ export const itemBeingUsed = proxy({ export default () => { const { name: usingItem, hand } = useSnapshot(itemBeingUsed) - const [displayIndicator, setDisplayIndicator] = useState(true) + const [displayIndicator, setDisplayIndicator] = useState(false) const [indicatorProgress, setIndicatorProgress] = useState(0) const [alternativeIndicator, setAlternativeIndicator] = useState(false) const boxMaxTimeMs = 1000 diff --git a/src/workerWorkaround.ts b/src/workerWorkaround.ts new file mode 100644 index 00000000..00419b8c --- /dev/null +++ b/src/workerWorkaround.ts @@ -0,0 +1,2 @@ +global = globalThis +globalThis.window = globalThis diff --git a/tsconfig.json b/tsconfig.json index 5d018a46..dbbb9ced 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ "forceConsistentCasingInFileNames": true, "useUnknownInCatchVariables": false, "skipLibCheck": true, - "experimentalDecorators": true, + "strictBindCallApply": true, // this the only options that allows smooth transition from js to ts (by not dropping types from js files) // however might need to consider includeing *only needed libraries* instead of using this "maxNodeModuleJsDepth": 1, From e129184ff1d14388a0d4d7b2d5a57e5a7f031422 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Mon, 27 May 2024 10:14:42 +0300 Subject: [PATCH 0113/1097] fix tsc --- src/workerWorkaround.ts | 2 ++ tsconfig.json | 1 + 2 files changed, 3 insertions(+) diff --git a/src/workerWorkaround.ts b/src/workerWorkaround.ts index 00419b8c..7fad22cf 100644 --- a/src/workerWorkaround.ts +++ b/src/workerWorkaround.ts @@ -1,2 +1,4 @@ +//@ts-nocheck +// eslint-disable-next-line no-global-assign global = globalThis globalThis.window = globalThis diff --git a/tsconfig.json b/tsconfig.json index dbbb9ced..454e60cb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,6 +15,7 @@ "forceConsistentCasingInFileNames": true, "useUnknownInCatchVariables": false, "skipLibCheck": true, + "experimentalDecorators": true, "strictBindCallApply": true, // this the only options that allows smooth transition from js to ts (by not dropping types from js files) // however might need to consider includeing *only needed libraries* instead of using this From 68269ee975f7c1f0d620dc6aac02b3efe2d5b533 Mon Sep 17 00:00:00 2001 From: gguio <109200692+gguio@users.noreply.github.com> Date: Mon, 27 May 2024 12:24:28 +0400 Subject: [PATCH 0114/1097] feat: Screenshot on F2 and hide/show UI on F1 (#136) Co-authored-by: gguio --- src/controls.ts | 18 ++++++++++++++++++ src/globalState.ts | 1 + src/index.ts | 2 ++ src/reactUi.tsx | 4 +++- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/controls.ts b/src/controls.ts index f940d59d..a3a22029 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -651,6 +651,24 @@ window.addEventListener('keydown', (e) => { } }) +window.addEventListener('keydown', (e) => { + if (e.code !== 'F2' || e.repeat || !isGameActive(true)) return + e.preventDefault() + const canvas = document.getElementById('viewer-canvas') as HTMLCanvasElement + if (!canvas) return + const link = document.createElement('a') + link.href = canvas.toDataURL('image/png') + const date = new Date() + link.download = `screenshot ${date.toLocaleString().replaceAll('.', '-').replace(',', '')}.png` + link.click() +}) + +window.addEventListener('keydown', (e) => { + if (e.code !== 'F1' || e.repeat || !isGameActive(true)) return + e.preventDefault() + miscUiState.showUI = !miscUiState.showUI +}) + // #region experimental debug things window.addEventListener('keydown', (e) => { if (e.code === 'F11') { diff --git a/src/globalState.ts b/src/globalState.ts index 4b62f8d6..b7dc1602 100644 --- a/src/globalState.ts +++ b/src/globalState.ts @@ -138,6 +138,7 @@ export const miscUiState = proxy({ wanOpened: false, /** wether game hud is shown (in playing state) */ gameLoaded: false, + showUI: true, loadedServerIndex: '', /** currently trying to load or loaded mc version, after all data is loaded */ loadedDataVersion: null as string | null, diff --git a/src/index.ts b/src/index.ts index 89baaa10..d02f7b92 100644 --- a/src/index.ts +++ b/src/index.ts @@ -108,6 +108,8 @@ let renderer: THREE.WebGLRenderer try { renderer = new THREE.WebGLRenderer({ powerPreference: options.gpuPreference, + preserveDrawingBuffer: true, + logarithmicDepthBuffer: true, }) } catch (err) { console.error(err) diff --git a/src/reactUi.tsx b/src/reactUi.tsx index d86cf202..497f091f 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -143,6 +143,8 @@ const WidgetDisplay = ({ name, Component }) => { } const App = () => { + const { showUI } = useSnapshot(miscUiState) + return
@@ -154,7 +156,7 @@ const App = () => {
- + {showUI && } From cbaeb8c9186be140634f577d9396f129e39b81e0 Mon Sep 17 00:00:00 2001 From: gguio <109200692+gguio@users.noreply.github.com> Date: Tue, 28 May 2024 13:34:22 +0400 Subject: [PATCH 0115/1097] fix hide ui was resetting state (#138) --- src/reactUi.tsx | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 497f091f..ab1e4ae5 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -95,7 +95,7 @@ const InGameComponent = ({ children }) => { } const InGameUi = () => { - const { gameLoaded } = useSnapshot(miscUiState) + const { gameLoaded, showUI } = useSnapshot(miscUiState) if (!gameLoaded) return return <> @@ -107,17 +107,21 @@ const InGameUi = () => { - - - +
+ + + + +
- - - - - +
+ + + +
+ {showUI && }
From def2baba8fd728a16f38feb9649b3a4b95d6a12e Mon Sep 17 00:00:00 2001 From: Vitaly Date: Tue, 28 May 2024 18:52:15 +0300 Subject: [PATCH 0116/1097] rm unused pmui-playscreen --- index.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/index.html b/index.html index 3e921855..6d3b326b 100644 --- a/index.html +++ b/index.html @@ -94,9 +94,7 @@
-
- -
+
From 295967cc4d6ff4b5b9f83b6fe4f6b2c7f4600158 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 29 May 2024 10:56:57 +0300 Subject: [PATCH 0117/1097] fix inspectPacket function --- src/devtools.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devtools.ts b/src/devtools.ts index 4dbeb51d..e836af02 100644 --- a/src/devtools.ts +++ b/src/devtools.ts @@ -29,7 +29,7 @@ window.len = (obj) => Object.keys(obj).length window.inspectPacket = (packetName, full = false) => { const listener = (...args) => console.log('packet', packetName, full ? args : args[0]) const attach = () => { - bot?.on(packetName, listener) + bot?._client.on(packetName, listener) } attach() customEvents.on('mineflayerBotCreated', attach) From d96ff9ef3a23fc130a0133cc5c2b67dfa41da538 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 29 May 2024 11:16:42 +0300 Subject: [PATCH 0118/1097] fix: was unable to go edit server screen after hitting cancel --- src/react/ServersListProvider.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index bd39bc10..bb23004f 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -186,6 +186,12 @@ const Inner = () => { } }, [serverEditScreen]) + useDidUpdateEffect(() => { + if (!isEditScreenModal) { + setServerEditScreen(null) + } + }, [isEditScreenModal]) + if (isEditScreenModal) { return Date: Sat, 1 Jun 2024 10:36:04 +0300 Subject: [PATCH 0119/1097] fix: page was reloading infinitely in some edge cases, give some time service workers to unregister in these cases --- src/react/MainMenu.tsx | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/react/MainMenu.tsx b/src/react/MainMenu.tsx index f99b6b98..3e3170f4 100644 --- a/src/react/MainMenu.tsx +++ b/src/react/MainMenu.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from 'react' import { openURL } from 'prismarine-viewer/viewer/lib/simpleUtils' import { haveDirectoryPicker } from '../utils' +import { activeModalStack } from '../globalState' import styles from './mainMenu.module.css' import Button from './Button' import ButtonWithTooltip from './ButtonWithTooltip' @@ -17,12 +18,24 @@ interface Props { mapsProvider?: string } -const refreshApp = async () => { +const refreshApp = async (failedUpdate = false) => { const registration = await navigator.serviceWorker.getRegistration() await registration?.unregister() - window.justReloaded = true - sessionStorage.justReloaded = true - window.location.reload() + if (failedUpdate) { + await new Promise(resolve => { + setTimeout(resolve, 2000) + }) + } + if (activeModalStack.length !== 0) return + if (failedUpdate) { + sessionStorage.justReloaded = false + // try to force bypass cache + location.search = '?update=true' + } else { + window.justReloaded = true + sessionStorage.justReloaded = true + window.location.reload() + } } const httpsRegex = /^https?:\/\// @@ -40,10 +53,10 @@ export default ({ connectToServerAction, mapsProvider, singleplayerAction, optio const contents = await f.text() const isLatest = contents === process.env.BUILD_VERSION if (!isLatest && sessionStorage.justReloaded) { - // try to force bypass cache - location.search = '?update=true' + setVersionStatus('(force reloading, wait)') + void refreshApp(true) + return } - sessionStorage.justReloaded = false setVersionStatus(`(${isLatest ? 'latest' : 'new version available'})`) setVersionTitle(`Loaded: ${process.env.BUILD_VERSION}. Remote: ${contents}`) }, () => { }) From c5e636f2416312cf58c8a84cb0937f5cad007c23 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 2 Jun 2024 00:59:23 +0300 Subject: [PATCH 0120/1097] fix (and now check) hide ui --- src/reactUi.tsx | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/reactUi.tsx b/src/reactUi.tsx index ab1e4ae5..2f57e6f0 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -101,19 +101,19 @@ const InGameUi = () => { return <> {/* apply scaling */} - - - - - -
+ + + + + + +
-
@@ -129,7 +129,7 @@ const InGameUi = () => { {/* because of z-index */} - + {showUI && } @@ -147,8 +147,6 @@ const WidgetDisplay = ({ name, Component }) => { } const App = () => { - const { showUI } = useSnapshot(miscUiState) - return
@@ -160,7 +158,7 @@ const App = () => {
- {showUI && } + From 0b2e92c8606a66782243fc632985b569178112f2 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 2 Jun 2024 10:29:29 +0300 Subject: [PATCH 0121/1097] fix sentry 5431874132 --- src/react/HotbarRenderApp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/react/HotbarRenderApp.tsx b/src/react/HotbarRenderApp.tsx index 02689485..9c6dbe40 100644 --- a/src/react/HotbarRenderApp.tsx +++ b/src/react/HotbarRenderApp.tsx @@ -88,7 +88,7 @@ export default () => { return } const hotbarSlot = slot - bot.inventory.hotbarStart - if (hotbarSlot < 0 || hotbarSlot > 9) return + if (hotbarSlot < 0 || hotbarSlot > 8) return bot.setQuickBarSlot(hotbarSlot) }, } as any) From b317d8ad354e375b4a00c146eafeebf4d86a4170 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 2 Jun 2024 14:20:21 +0300 Subject: [PATCH 0122/1097] fix: reduce fps drops on chunks load a bit by batching operations with a few other minor optimizations --- prismarine-viewer/viewer/lib/entities.js | 39 +++++++++-------- prismarine-viewer/viewer/lib/mesher/mesher.ts | 36 +++++++++++++++- prismarine-viewer/viewer/lib/threeJsUtils.ts | 8 ++-- .../viewer/lib/worldDataEmitter.ts | 11 ++++- .../viewer/lib/worldrendererCommon.ts | 34 +++++++++++++-- .../viewer/lib/worldrendererThree.ts | 43 ++++++++++++++++--- src/optionsGuiScheme.tsx | 3 +- src/react/DebugOverlay.tsx | 26 ++++++----- src/watchOptions.ts | 2 +- src/worldInteractions.ts | 1 + 10 files changed, 153 insertions(+), 50 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.js b/prismarine-viewer/viewer/lib/entities.js index 930f62c9..28fc6d89 100644 --- a/prismarine-viewer/viewer/lib/entities.js +++ b/prismarine-viewer/viewer/lib/entities.js @@ -17,7 +17,7 @@ import { disposeObject } from './threeJsUtils' export const TWEEN_DURATION = 50 // todo should be 100 -function getUsernameTexture (username, { fontFamily = 'sans-serif' }) { +function getUsernameTexture(username, { fontFamily = 'sans-serif' }) { const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') if (!ctx) throw new Error('Could not get 2d context') @@ -61,7 +61,7 @@ const addNametag = (entity, options, mesh) => { // todo cleanup const nametags = {} -function getEntityMesh (entity, scene, options, overrides) { +function getEntityMesh(entity, scene, options, overrides) { if (entity.name) { try { // https://github.com/PrismarineJS/prismarine-viewer/pull/410 @@ -94,18 +94,19 @@ function getEntityMesh (entity, scene, options, overrides) { export class Entities extends EventEmitter { constructor(scene) { super() + /** @type {THREE.Scene} */ this.scene = scene this.entities = {} this.entitiesOptions = {} this.debugMode = 'none' this.onSkinUpdate = () => { } this.clock = new THREE.Clock() - this.visible = true + this.rendering = true this.itemsTexture = null this.getItemUv = undefined } - clear () { + clear() { for (const mesh of Object.values(this.entities)) { this.scene.remove(mesh) disposeObject(mesh) @@ -113,7 +114,7 @@ export class Entities extends EventEmitter { this.entities = {} } - setDebugMode (mode, /** @type {THREE.Object3D?} */entity = null) { + setDebugMode(mode, /** @type {THREE.Object3D?} */entity = null) { this.debugMode = mode for (const mesh of entity ? [entity] : Object.values(this.entities)) { const boxHelper = mesh.children.find(c => c.name === 'debug') @@ -125,14 +126,18 @@ export class Entities extends EventEmitter { } } - setVisible (visible, /** @type {THREE.Object3D?} */entity = null) { - this.visible = visible - for (const mesh of entity ? [entity] : Object.values(this.entities)) { - mesh.visible = visible + setRendering(rendering, /** @type {THREE.Object3D?} */entity = null) { + this.rendering = rendering + for (const ent of entity ? [entity] : Object.values(this.entities)) { + if (rendering) { + if (!this.scene.children.includes(ent)) this.scene.add(ent) + } else { + this.scene.remove(ent) + } } } - render () { + render() { const dt = this.clock.getDelta() for (const entityId of Object.keys(this.entities)) { const playerObject = this.getPlayerObject(entityId) @@ -142,7 +147,7 @@ export class Entities extends EventEmitter { } } - getPlayerObject (entityId) { + getPlayerObject(entityId) { /** @type {(PlayerObject & { animation?: PlayerAnimation }) | undefined} */ const playerObject = this.entities[entityId]?.playerObject return playerObject @@ -152,7 +157,7 @@ export class Entities extends EventEmitter { defaultSteveTexture // true means use default skin url - updatePlayerSkin (entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { + updatePlayerSkin(entityId, username, /** @type {string | true} */skinUrl, /** @type {string | true | undefined} */capeUrl = undefined) { let playerObject = this.getPlayerObject(entityId) if (!playerObject) return // const username = this.entities[entityId].username @@ -235,14 +240,14 @@ export class Entities extends EventEmitter { playerObject.cape.map = null } - function isCanvasBlank (canvas) { + function isCanvasBlank(canvas) { return !canvas.getContext('2d') .getImageData(0, 0, canvas.width, canvas.height).data .some(channel => channel !== 0) } } - playAnimation (entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { + playAnimation(entityPlayerId, /** @type {'walking' | 'running' | 'oneSwing' | 'idle'} */animation) { const playerObject = this.getPlayerObject(entityPlayerId) if (!playerObject) return @@ -262,14 +267,14 @@ export class Entities extends EventEmitter { } - displaySimpleText (jsonLike) { + displaySimpleText(jsonLike) { if (!jsonLike) return const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike) const text = flat(parsed).map(x => x.text) return text.join('') } - update (/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { + update(/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { let isPlayerModel = entity.name === 'player' if (entity.name === 'zombie' || entity.name === 'zombie_villager' || entity.name === 'husk') { isPlayerModel = true @@ -392,7 +397,7 @@ export class Entities extends EventEmitter { this.updatePlayerSkin(entity.id, '', overrides?.texture || stevePng) } this.setDebugMode(this.debugMode, group) - this.setVisible(this.visible, group) + this.setRendering(this.rendering, group) } //@ts-ignore diff --git a/prismarine-viewer/viewer/lib/mesher/mesher.ts b/prismarine-viewer/viewer/lib/mesher/mesher.ts index bc1d3bbb..d0c82280 100644 --- a/prismarine-viewer/viewer/lib/mesher/mesher.ts +++ b/prismarine-viewer/viewer/lib/mesher/mesher.ts @@ -19,6 +19,29 @@ function sectionKey (x, y, z) { return `${x},${y},${z}` } +const batchMessagesLimit = 100 + +let queuedMessages = [] as any[] +let queueWaiting = false +const postMessage = (data, transferList = []) => { + queuedMessages.push({ data, transferList }) + if (queuedMessages.length > batchMessagesLimit) { + drainQueue(0, batchMessagesLimit) + } + if (queueWaiting) return + queueWaiting = true + setTimeout(() => { + queueWaiting = false + drainQueue(0, queuedMessages.length) + }) +} + +function drainQueue (from, to) { + const messages = queuedMessages.slice(from, to) + global.postMessage(messages.map(m => m.data), messages.flatMap(m => m.transferList) as unknown as string) + queuedMessages = queuedMessages.slice(to) +} + function setSectionDirty (pos, value = true) { const x = Math.floor(pos.x / 16) * 16 const y = Math.floor(pos.y / 16) * 16 @@ -43,7 +66,7 @@ const softCleanup = () => { world = new World(world.config.version) } -self.onmessage = ({ data }) => { +const handleMessage = data => { const globalVar: any = globalThis if (data.type === 'mcData') { @@ -52,7 +75,7 @@ self.onmessage = ({ data }) => { if (data.config) { world ??= new World(data.config.version) - world.config = {...world.config, ...data.config} + world.config = { ...world.config, ...data.config } globalThis.world = world } @@ -80,6 +103,15 @@ self.onmessage = ({ data }) => { } } +self.onmessage = ({ data }) => { + if (Array.isArray(data)) { + data.forEach(handleMessage) + return + } + + handleMessage(data) +} + setInterval(() => { if (world === null || !blockStatesReady) return diff --git a/prismarine-viewer/viewer/lib/threeJsUtils.ts b/prismarine-viewer/viewer/lib/threeJsUtils.ts index e4f9404b..ee22c477 100644 --- a/prismarine-viewer/viewer/lib/threeJsUtils.ts +++ b/prismarine-viewer/viewer/lib/threeJsUtils.ts @@ -1,12 +1,12 @@ -import * as THREE from 'three'; +import * as THREE from 'three' export const disposeObject = (obj: THREE.Object3D) => { // not cleaning texture there as it might be used by other objects, but would be good to also do that if (obj instanceof THREE.Mesh) { - obj.geometry?.dispose?.(); - obj.material?.dispose?.(); + obj.geometry?.dispose?.() + obj.material?.dispose?.() } if (obj.children) { - obj.children.forEach(disposeObject); + obj.children.forEach(disposeObject) } } diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index 40cc3413..3a8fbd40 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -129,6 +129,15 @@ export class WorldDataEmitter extends EventEmitter { } } + readdDebug () { + const clonedLoadedChunks = { ...this.loadedChunks } + this.unloadAllChunks() + for (const loadedChunk in clonedLoadedChunks) { + const [x, z] = loadedChunk.split(',').map(Number) + this.loadChunk(new Vec3(x, 0, z)) + } + } + async loadChunk (pos: ChunkPos, isLightUpdate = false) { const [botX, botZ] = chunkPos(this.lastPos) const dx = Math.abs(botX - Math.floor(pos.x / 16)) @@ -187,7 +196,7 @@ export class WorldDataEmitter extends EventEmitter { const positions = generateSpiralMatrix(this.viewDistance).map(([x, z]) => { const pos = new Vec3((botX + x) * 16, 0, (botZ + z) * 16) if (!this.loadedChunks[`${pos.x},${pos.z}`]) return pos - return undefined + return undefined! }).filter(a => !!a) this.lastPos.update(pos) await this._loadChunks(positions) diff --git a/prismarine-viewer/viewer/lib/worldrendererCommon.ts b/prismarine-viewer/viewer/lib/worldrendererCommon.ts index d1786650..1a87fa5d 100644 --- a/prismarine-viewer/viewer/lib/worldrendererCommon.ts +++ b/prismarine-viewer/viewer/lib/worldrendererCommon.ts @@ -73,10 +73,10 @@ export abstract class WorldRendererCommon const src = typeof window === 'undefined' ? `${__dirname}/${workerName}` : workerName const worker: any = new Worker(src) - worker.onmessage = async ({ data }) => { + const handleMessage = (data) => { if (!this.active) return this.handleWorkerMessage(data) - await new Promise(resolve => { + new Promise(resolve => { setTimeout(resolve, 0) }) if (data.type === 'sectionFinished') { @@ -105,6 +105,13 @@ export abstract class WorldRendererCommon this.renderUpdateEmitter.emit('update') } } + worker.onmessage = ({ data }) => { + if (Array.isArray(data)) { + data.forEach(handleMessage) + return + } + handleMessage(data) + } if (worker.on) worker.on('message', (data) => { worker.onmessage({ data }) }) this.workers.push(worker) } @@ -215,6 +222,7 @@ export abstract class WorldRendererCommon } addColumn (x: number, z: number, chunk: any, isLightUpdate: boolean) { + if (!this.active) return if (this.workers.length === 0) throw new Error('workers not initialized yet') this.initialChunksLoad = false this.loadedChunks[`${x},${z}`] = true @@ -256,6 +264,9 @@ export abstract class WorldRendererCommon if ((pos.z & 15) === 15) this.setSectionDirty(pos.offset(0, 0, 16)) } + queueAwaited = false + messagesQueue = {} as { [workerIndex: string]: any[] } + setSectionDirty (pos: Vec3, value = true) { if (this.viewDistance === -1) throw new Error('viewDistance not set') this.allChunksFinished = false @@ -269,7 +280,9 @@ export abstract class WorldRendererCommon // is always dispatched to the same worker const hash = mod(Math.floor(pos.x / 16) + Math.floor(pos.y / 16) + Math.floor(pos.z / 16), this.workers.length) this.sectionsOutstanding.set(key, (this.sectionsOutstanding.get(key) ?? 0) + 1) - this.workers[hash].postMessage({ + this.messagesQueue[hash] ??= [] + this.messagesQueue[hash].push({ + // this.workers[hash].postMessage({ type: 'dirty', x: pos.x, y: pos.y, @@ -277,6 +290,21 @@ export abstract class WorldRendererCommon value, config: this.mesherConfig, }) + this.dispatchMessages() + } + + dispatchMessages () { + if (this.queueAwaited) return + this.queueAwaited = true + setTimeout(() => { + // group messages and send as one + for (const workerIndex in this.messagesQueue) { + const worker = this.workers[Number(workerIndex)] + worker.postMessage(this.messagesQueue[workerIndex]) + } + this.messagesQueue = {} + this.queueAwaited = false + }) } // Listen for chunk rendering updates emitted if a worker finished a render and resolve if the number diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 60156a50..4d28519a 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -16,6 +16,7 @@ export class WorldRendererThree extends WorldRendererCommon { chunkTextures = new Map() signsCache = new Map() starField: StarField + cameraSectionPos: Vec3 = new Vec3(0, 0, 0) get tilesRendered () { return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).tilesCount, 0) @@ -42,16 +43,18 @@ export class WorldRendererThree extends WorldRendererCommon { */ updatePosDataChunk (key: string) { const [x, y, z] = key.split(',').map(x => Math.floor(+x / 16)) - const [xPlayer, yPlayer, zPlayer] = this.camera.position.toArray().map(x => Math.floor(x / 16)) // sum of distances: x + y + z - const chunkDistance = Math.abs(x - xPlayer) + Math.abs(y - yPlayer) + Math.abs(z - zPlayer) + const chunkDistance = Math.abs(x - this.cameraSectionPos.x) + Math.abs(y - this.cameraSectionPos.y) + Math.abs(z - this.cameraSectionPos.z) const section = this.sectionObjects[key].children.find(child => child.name === 'mesh')! section.renderOrder = 500 - chunkDistance } updateViewerPosition (pos: Vec3): void { this.viewerPosition = pos - for (const [key, value] of Object.entries(this.sectionObjects)) { + const cameraPos = this.camera.position.toArray().map(x => Math.floor(x / 16)) as [number, number, number] + this.cameraSectionPos = new Vec3(...cameraPos) + for (const key in this.sectionObjects) { + const value = this.sectionObjects[key] if (!value) continue this.updatePosDataChunk(key) } @@ -95,7 +98,10 @@ export class WorldRendererThree extends WorldRendererCommon { mesh.name = 'mesh' object = new THREE.Group() object.add(mesh) - const boxHelper = new THREE.BoxHelper(mesh, 0xffff00) + // mesh with static dimensions: 16x16x16 + const staticChunkMesh = new THREE.Mesh(new THREE.BoxGeometry(16, 16, 16), new THREE.MeshBasicMaterial({ color: 0x000000, transparent: true, opacity: 0 })) + staticChunkMesh.position.set(data.geometry.sx, data.geometry.sy, data.geometry.sz) + const boxHelper = new THREE.BoxHelper(staticChunkMesh, 0xffff00) boxHelper.name = 'helper' object.add(boxHelper) object.name = 'chunk' @@ -117,6 +123,11 @@ export class WorldRendererThree extends WorldRendererCommon { } this.sectionObjects[data.key] = object this.updatePosDataChunk(data.key) + object.matrixAutoUpdate = false + mesh.onAfterRender = (renderer, scene, camera, geometry, material, group) => { + // mesh.matrixAutoUpdate = false + } + this.scene.add(object) } @@ -253,6 +264,24 @@ export class WorldRendererThree extends WorldRendererCommon { } } + readdChunks () { + for (const key of Object.keys(this.sectionObjects)) { + this.scene.remove(this.sectionObjects[key]) + } + setTimeout(() => { + for (const key of Object.keys(this.sectionObjects)) { + this.scene.add(this.sectionObjects[key]) + } + }, 500) + } + + disableUpdates (children = this.scene.children) { + for (const child of children) { + child.matrixWorldNeedsUpdate = false + this.disableUpdates(child.children ?? []) + } + } + removeColumn (x, z) { super.removeColumn(x, z) @@ -332,7 +361,7 @@ class StarField { this.points = new THREE.Points(geometry, material) this.scene.add(this.points) - const clock = new THREE.Clock(); + const clock = new THREE.Clock() this.points.onBeforeRender = (renderer, scene, camera) => { this.points?.position.copy?.(camera.position) material.uniforms.time.value = clock.getElapsedTime() * speed @@ -342,10 +371,10 @@ class StarField { remove () { if (this.points) { this.points.geometry.dispose(); - (this.points.material as THREE.Material).dispose(); + (this.points.material as THREE.Material).dispose() this.scene.remove(this.points) - this.points = undefined; + this.points = undefined } } } diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 88e6115f..9be844d3 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -69,7 +69,8 @@ export const guiOptionsScheme: { enableWarning: 'Enabling it will make chunks load ~4x slower', disabledDuringGame: true }, - starfieldRendering: {} + starfieldRendering: {}, + renderEntities: {}, }, ], main: [ diff --git a/src/react/DebugOverlay.tsx b/src/react/DebugOverlay.tsx index 4b3c19b1..dd288b49 100644 --- a/src/react/DebugOverlay.tsx +++ b/src/react/DebugOverlay.tsx @@ -83,6 +83,16 @@ export default () => { packetsCountByNamePerSec.current.sent = {} }, 1000) + const freqUpdateInterval = setInterval(() => { + setPos(prev => { return { ...bot.entity.position } }) + setSkyL(prev => bot.world.getSkyLight(bot.entity.position)) + setBlockL(prev => bot.world.getBlockLight(bot.entity.position)) + setBiomeId(prev => bot.world.getBiome(bot.entity.position)) + setDimension(bot.game.dimension) + setDay(bot.time.day) + setCursorBlock(worldInteractions.cursorBlock) + }, 100) + // @ts-expect-error bot._client.on('packet', readPacket) // @ts-expect-error @@ -91,25 +101,12 @@ export default () => { sent.current.count++ managePackets('sent', name, data) }) - bot.on('move', () => { - setPos(prev => { return { ...bot.entity.position }}) - setSkyL(prev => bot.world.getSkyLight(bot.entity.position)) - setBlockL(prev => bot.world.getBlockLight(bot.entity.position)) - setBiomeId(prev => bot.world.getBiome(bot.entity.position)) - setDimension(bot.game.dimension) - }) - bot.on('time', () => { - setDay(bot.time.day) - }) bot.on('entitySpawn', () => { setEntitiesCount(Object.values(bot.entities).length) }) bot.on('entityGone', () => { setEntitiesCount(Object.values(bot.entities).length) }) - bot.on('physicsTick', () => { - setCursorBlock(worldInteractions.cursorBlock) - }) try { const gl = window.renderer.getContext() @@ -121,6 +118,7 @@ export default () => { return () => { document.removeEventListener('keydown', handleF3) clearInterval(packetsUpdateInterval) + clearInterval(freqUpdateInterval) } }, []) @@ -169,7 +167,7 @@ export default () => { ) } ) - : '' } + : ''} {cursorBlock ? (

Looking at: {cursorBlock.position.x} {cursorBlock.position.y} {cursorBlock.position.z}

) : ''} diff --git a/src/watchOptions.ts b/src/watchOptions.ts index 4ff34be4..e379cb50 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -41,7 +41,7 @@ export const watchOptionsAfterViewerInit = () => { }) watchValue(options, o => { - viewer.entities.setVisible(o.renderEntities) + viewer.entities.setRendering(o.renderEntities) }) // viewer.world.mesherConfig.smoothLighting = options.smoothLighting diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 239c02c2..330dabd7 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -73,6 +73,7 @@ class WorldInteraction { this.blockBreakMesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), breakMaterial) this.blockBreakMesh.visible = false this.blockBreakMesh.renderOrder = 999 + this.blockBreakMesh.name = 'blockBreakMesh' viewer.scene.add(this.blockBreakMesh) // Setup events From 95b80d93ba95cc887ccdf964484c396ab2cb06ee Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 4 Jun 2024 01:45:33 +0300 Subject: [PATCH 0123/1097] fix: waterlogged z-fighting fix --- prismarine-viewer/viewer/lib/mesher/models.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/prismarine-viewer/viewer/lib/mesher/models.ts b/prismarine-viewer/viewer/lib/mesher/models.ts index 40b82ea2..39148aaa 100644 --- a/prismarine-viewer/viewer/lib/mesher/models.ts +++ b/prismarine-viewer/viewer/lib/mesher/models.ts @@ -35,7 +35,7 @@ function prepareTints (tints) { }) } -const calculatedBlocksEntries = Object.entries(legacyJson.clientCalculatedBlocks); +const calculatedBlocksEntries = Object.entries(legacyJson.clientCalculatedBlocks) export function preflatBlockCalculation (block: Block, world: World, position: Vec3) { const type = calculatedBlocksEntries.find(([name, blocks]) => blocks.includes(block.name))?.[0] if (!type) return @@ -239,9 +239,9 @@ function renderLiquid (world, cursor, texture, type, biome, water, attr) { for (const pos of corners) { const height = cornerHeights[pos[2] * 2 + pos[0]] attr.t_positions.push( - (pos[0] ? 1 : 0) + (cursor.x & 15) - 8, - (pos[1] ? height : 0) + (cursor.y & 15) - 8, - (pos[2] ? 1 : 0) + (cursor.z & 15) - 8) + (pos[0] ? 0.999 : 0.001) + (cursor.x & 15) - 8, + (pos[1] ? height - 0.001 : 0.001) + (cursor.y & 15) - 8, + (pos[2] ? 0.999 : 0.001) + (cursor.z & 15) - 8) attr.t_normals.push(...dir) attr.t_uvs.push(pos[3] * su + u, pos[4] * sv * (pos[1] ? 1 : height) + v) attr.t_colors.push(tint[0], tint[1], tint[2]) From 28e24a7a870a8b217f4d1d3b85f2b39473765c4f Mon Sep 17 00:00:00 2001 From: Wolf2323 Date: Tue, 4 Jun 2024 01:34:29 +0200 Subject: [PATCH 0124/1097] fix: fix rendering of Decorated Pot (#134) --- .../viewer/lib/mesher/test/tests.test.ts | 1 - prismarine-viewer/viewer/prepare/atlas.ts | 42 ++++++++++++--- .../blockModels/1.20/decorated_pot.json | 47 +++++++++++++++++ .../blockStates/1.20/decorated_pot.json | 19 +++++++ .../data/1.20/blockModels/decorated_pot.json | 47 +++++++++++++++++ .../data/1.20/blockStates/decorated_pot.json | 19 +++++++ .../viewer/prepare/moreGeneratedBlocks.ts | 51 +++++++++++++++++-- 7 files changed, 214 insertions(+), 12 deletions(-) create mode 100644 prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json create mode 100644 prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/decorated_pot.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/decorated_pot.json diff --git a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts index 75dd98fa..5a80fa49 100644 --- a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts +++ b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts @@ -77,7 +77,6 @@ test('Known blocks are not rendered', () => { "cyan_wall_banner": true, "dark_oak_hanging_sign": true, "dark_oak_wall_hanging_sign": true, - "decorated_pot": true, "dragon_head": true, "dragon_wall_head": true, "end_gateway": true, diff --git a/prismarine-viewer/viewer/prepare/atlas.ts b/prismarine-viewer/viewer/prepare/atlas.ts index cb30b727..fc3e4029 100644 --- a/prismarine-viewer/viewer/prepare/atlas.ts +++ b/prismarine-viewer/viewer/prepare/atlas.ts @@ -35,7 +35,7 @@ export type JsonAtlas = { } } -export const makeTextureAtlas = (input: string[], getInputData: (name) => { contents: string, tileWidthMult?: number }, tilesCount = input.length, suSvOptimize: 'remove' | null = null): { +export const makeTextureAtlas = (input: string[], getInputData: (name) => { contents: string, tileWidthMult?: number, origSizeTextures?}, tilesCount = input.length, suSvOptimize: 'remove' | null = null): { image: Buffer, canvas: Canvas, json: JsonAtlas @@ -49,6 +49,7 @@ export const makeTextureAtlas = (input: string[], getInputData: (name) => { cont const texturesIndex = {} + let skipXY = [] as [x: number, y: number][] let offset = 0 const suSv = tileSize / imgSize for (const i in input) { @@ -56,20 +57,44 @@ export const makeTextureAtlas = (input: string[], getInputData: (name) => { cont const x = (pos % texSize) * tileSize const y = Math.floor(pos / texSize) * tileSize + if (skipXY.some(([sx, sy]) => sx === x + 1 && sy === y)) { + // todo more offsets + offset++ + } + const img = new Image() - const keyValue = input[i]; - const inputData = getInputData(keyValue); + const keyValue = input[i] + const inputData = getInputData(keyValue) img.src = inputData.contents - const renderWidth = tileSize * (inputData.tileWidthMult ?? 1) - g.drawImage(img, 0, 0, renderWidth, tileSize, x, y, renderWidth, tileSize) + let su = suSv + let sv = suSv + let renderWidth = tileSize * (inputData.tileWidthMult ?? 1) + let renderHeight = tileSize + if (inputData.origSizeTextures?.[keyValue]) { + // todo check have enough space + renderWidth = Math.ceil(img.width / tileSize) * tileSize + renderHeight = Math.ceil(img.height / tileSize) * tileSize + su = renderWidth / imgSize + sv = renderHeight / imgSize + if (renderWidth > tileSize) { + offset += Math.ceil(renderWidth / tileSize) - 1 + } + if (renderHeight > tileSize) { + const skipYs = Math.ceil(renderHeight / tileSize) - 1 + for (let i = 1; i <= skipYs; i++) { + skipXY.push([x, y + i]) + } + } + } + g.drawImage(img, 0, 0, renderWidth, renderHeight, x, y, renderWidth, renderHeight) const cleanName = keyValue.split('.').slice(0, -1).join('.') || keyValue texturesIndex[cleanName] = { u: x / imgSize, v: y / imgSize, ...suSvOptimize === 'remove' ? {} : { - su: suSv, - sv: suSv + su: su, + sv: sv } } } @@ -91,7 +116,7 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) { // const textureFiles = mostEncounteredBlocks.map(x => x + '.png') textureFiles.unshift(...localTextures) - const { generated: additionalTextures, twoTileTextures } = getAdditionalTextures() + const { generated: additionalTextures, twoTileTextures, origSizeTextures } = getAdditionalTextures() textureFiles.push(...Object.keys(additionalTextures)) const atlas = makeTextureAtlas(textureFiles, name => { @@ -105,6 +130,7 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) { return { contents, tileWidthMult: twoTileTextures.includes(name) ? 2 : undefined, + origSizeTextures } }) return atlas diff --git a/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json b/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json new file mode 100644 index 00000000..364c72d4 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json @@ -0,0 +1,47 @@ +{ + "texture_size": [32, 32], + "textures": { + "0": "entity/decorated_pot/decorated_pot_base" + }, + "elements": [ + { + "name": "Body", + "from": [1, 0, 1], + "to": [15, 16, 15], + "faces": { + "north": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "east": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "south": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "west": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "up": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"}, + "down": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"} + } + }, + { + "name": "Neck", + "from": [5, 16, 5], + "to": [11, 17, 11], + "faces": { + "north": {"uv": [6, 5.5, 9, 6], "texture": "#0"}, + "east": {"uv": [9, 5.5, 12, 6], "texture": "#0"}, + "south": {"uv": [2.5, 5.5, 5.5, 6], "texture": "#0"}, + "west": {"uv": [0, 5.5, 3, 6], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 3], "texture": "#0"}, + "down": {"uv": [0, 0, 3, 3], "texture": "#0"} + } + }, + { + "name": "Head", + "from": [4, 17, 4], + "to": [12, 20, 12], + "faces": { + "north": {"uv": [0, 4, 4, 5.5], "texture": "#0"}, + "east": {"uv": [4, 4, 8, 5.5], "texture": "#0"}, + "south": {"uv": [8, 4, 12, 5.5], "texture": "#0"}, + "west": {"uv": [12, 4, 16, 5.5], "texture": "#0"}, + "up": {"uv": [4, 0, 8, 4], "texture": "#0"}, + "down": {"uv": [8, 0, 12, 4], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json b/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json new file mode 100644 index 00000000..5b46a220 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "decorated_pot", + "y": 90 + }, + "facing=south": { + "model": "decorated_pot", + "y": 180 + }, + "facing=west": { + "model": "decorated_pot", + "y": 270 + }, + "facing=north": { + "model": "decorated_pot" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/decorated_pot.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/decorated_pot.json new file mode 100644 index 00000000..364c72d4 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/decorated_pot.json @@ -0,0 +1,47 @@ +{ + "texture_size": [32, 32], + "textures": { + "0": "entity/decorated_pot/decorated_pot_base" + }, + "elements": [ + { + "name": "Body", + "from": [1, 0, 1], + "to": [15, 16, 15], + "faces": { + "north": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "east": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "south": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "west": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, + "up": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"}, + "down": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"} + } + }, + { + "name": "Neck", + "from": [5, 16, 5], + "to": [11, 17, 11], + "faces": { + "north": {"uv": [6, 5.5, 9, 6], "texture": "#0"}, + "east": {"uv": [9, 5.5, 12, 6], "texture": "#0"}, + "south": {"uv": [2.5, 5.5, 5.5, 6], "texture": "#0"}, + "west": {"uv": [0, 5.5, 3, 6], "texture": "#0"}, + "up": {"uv": [0, 0, 3, 3], "texture": "#0"}, + "down": {"uv": [0, 0, 3, 3], "texture": "#0"} + } + }, + { + "name": "Head", + "from": [4, 17, 4], + "to": [12, 20, 12], + "faces": { + "north": {"uv": [0, 4, 4, 5.5], "texture": "#0"}, + "east": {"uv": [4, 4, 8, 5.5], "texture": "#0"}, + "south": {"uv": [8, 4, 12, 5.5], "texture": "#0"}, + "west": {"uv": [12, 4, 16, 5.5], "texture": "#0"}, + "up": {"uv": [4, 0, 8, 4], "texture": "#0"}, + "down": {"uv": [8, 0, 12, 4], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/decorated_pot.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/decorated_pot.json new file mode 100644 index 00000000..5b46a220 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/decorated_pot.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "decorated_pot", + "y": 90 + }, + "facing=south": { + "model": "decorated_pot", + "y": 180 + }, + "facing=west": { + "model": "decorated_pot", + "y": 270 + }, + "facing=north": { + "model": "decorated_pot" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts index ffb1a705..695464ea 100644 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts @@ -7,6 +7,7 @@ import { fileURLToPath } from 'url' // todo refactor const twoTileTextures: string[] = [] +const origSizeTextures: string[] = [] let currentImage: Jimp let currentBlockName: string let currentMcAssets: McAssets @@ -82,7 +83,7 @@ const getBlockTexturesFromJimp = async > (sides: for (const [side, jimp] of Object.entries(sides)) { const textureName = `${textureNameBase}_${side}` const sideTexture = withUv ? { uv: [0, 0, jimp.getWidth(), jimp.getHeight()], texture: textureName } : textureName - const base64 = await jimp.getBase64Async(jimp.getMIME()) + const base64Url = await jimp.getBase64Async(jimp.getMIME()) if (side === 'side') { sidesTextures['north'] = sideTexture sidesTextures['east'] = sideTexture @@ -91,7 +92,7 @@ const getBlockTexturesFromJimp = async > (sides: } else { sidesTextures[side] = sideTexture } - generatedImageTextures[textureName] = base64 + generatedImageTextures[textureName] = base64Url } return sidesTextures @@ -229,6 +230,7 @@ const handleSign = async (dataBase: string, match: RegExpExecArray) => { twoTileTextures.push(blockTextures.up.texture) } +// TODO! should not be there! move to data with signs! const chestModels = { chest: { "parent": "block/block", @@ -401,6 +403,32 @@ const handleChest = async (dataBase: string, match: RegExpExecArray) => { currentMcAssets.blocksStates[currentBlockName] = blockStates } +function getParsedJSON (block: string, type: string) { + const versionParts = currentMcAssets.version.split(".") + const version = versionParts[0] + "." + versionParts[1] + return JSON.parse(fs.readFileSync(path.join(__dirname, `${type}/${version}/${block}.json`), 'utf-8')) +} + +function getBlockState (match: string) { + return getParsedJSON(match, 'blockStates') +} + +async function loadBlockModelTextures (dataBase: string, blockModel: any) { + for (const key in Object.entries(blockModel.textures)) { + const texture: string = blockModel.textures[key] + currentImage = await Jimp.read(dataBase + texture + '.png') + blockModel.textures.particle = texture + generatedImageTextures[texture] = `data:image/png;base64,${fs.readFileSync(path.join(dataBase, texture + '.png'), 'base64')}` + origSizeTextures[texture] = true + } +} + +async function getBlockModel (dataBase: string, block: string) { + const blockModel = getParsedJSON(block, 'blockModels') + await loadBlockModelTextures(dataBase, blockModel) + return blockModel +} + const handlers = [ [/(.+)_shulker_box$/, handleShulkerBox], [/^shulker_box$/, handleShulkerBox], @@ -427,6 +455,21 @@ export const tryHandleBlockEntity = async (dataBase, blockName) => { } } +const handleExternalData = async (dataBase: string, version: string) => { + const [major, minor] = version.split(".") + const dataVer = `${major}.${minor}` + if (!fs.existsSync(path.join(__dirname, 'data', dataVer))) return + const allModels = fs.readdirSync(path.join(__dirname, 'data', dataVer, 'blockModels')).map(x => x.replace('.json', '')) + for (const model of allModels) { + currentMcAssets.blocksModels[model] = await getBlockModel(dataBase, model) + } + + const allBlockStates = fs.readdirSync(path.join(__dirname, 'data', dataVer, 'blockStates')).map(x => x.replace('.json', '')) + for (const blockState of allBlockStates) { + currentMcAssets.blocksStates[blockState] = await getBlockState(blockState) + } +} + export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { const mcData = minecraftData(mcAssets.version) const allTheBlocks = mcData.blocksArray.map(x => x.name) @@ -447,6 +490,8 @@ export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { } } + await handleExternalData(mcAssets.directory, mcAssets.version) + const warnings: string[] = [] for (const [name, model] of Object.entries(mcAssets.blocksModels)) { if (Object.keys(model).length === 1 && model.textures) { @@ -462,5 +507,5 @@ export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { } export const getAdditionalTextures = () => { - return { generated: generatedImageTextures, twoTileTextures } + return { generated: generatedImageTextures, twoTileTextures, origSizeTextures } } From 228039c2450dcdee4a858b77ad740b99278e0ada Mon Sep 17 00:00:00 2001 From: Wolf2323 Date: Tue, 4 Jun 2024 12:41:53 +0200 Subject: [PATCH 0125/1097] cleanup external data handling in more generated blocks (#141) Co-authored-by: Vitaly Turovsky --- .../blockModels/1.20/decorated_pot.json | 47 ------------------- .../blockStates/1.20/decorated_pot.json | 19 -------- .../viewer/prepare/moreGeneratedBlocks.ts | 37 ++++++--------- 3 files changed, 14 insertions(+), 89 deletions(-) delete mode 100644 prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json delete mode 100644 prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json diff --git a/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json b/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json deleted file mode 100644 index 364c72d4..00000000 --- a/prismarine-viewer/viewer/prepare/blockModels/1.20/decorated_pot.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "texture_size": [32, 32], - "textures": { - "0": "entity/decorated_pot/decorated_pot_base" - }, - "elements": [ - { - "name": "Body", - "from": [1, 0, 1], - "to": [15, 16, 15], - "faces": { - "north": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, - "east": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, - "south": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, - "west": {"uv": [0, 6.5, 7, 13.5], "texture": "#0"}, - "up": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"}, - "down": {"uv": [7, 6.5, 14, 13.5], "texture": "#0"} - } - }, - { - "name": "Neck", - "from": [5, 16, 5], - "to": [11, 17, 11], - "faces": { - "north": {"uv": [6, 5.5, 9, 6], "texture": "#0"}, - "east": {"uv": [9, 5.5, 12, 6], "texture": "#0"}, - "south": {"uv": [2.5, 5.5, 5.5, 6], "texture": "#0"}, - "west": {"uv": [0, 5.5, 3, 6], "texture": "#0"}, - "up": {"uv": [0, 0, 3, 3], "texture": "#0"}, - "down": {"uv": [0, 0, 3, 3], "texture": "#0"} - } - }, - { - "name": "Head", - "from": [4, 17, 4], - "to": [12, 20, 12], - "faces": { - "north": {"uv": [0, 4, 4, 5.5], "texture": "#0"}, - "east": {"uv": [4, 4, 8, 5.5], "texture": "#0"}, - "south": {"uv": [8, 4, 12, 5.5], "texture": "#0"}, - "west": {"uv": [12, 4, 16, 5.5], "texture": "#0"}, - "up": {"uv": [4, 0, 8, 4], "texture": "#0"}, - "down": {"uv": [8, 0, 12, 4], "texture": "#0"} - } - } - ] -} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json b/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json deleted file mode 100644 index 5b46a220..00000000 --- a/prismarine-viewer/viewer/prepare/blockStates/1.20/decorated_pot.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "variants": { - "facing=east": { - "model": "decorated_pot", - "y": 90 - }, - "facing=south": { - "model": "decorated_pot", - "y": 180 - }, - "facing=west": { - "model": "decorated_pot", - "y": 270 - }, - "facing=north": { - "model": "decorated_pot" - } - } -} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts index 695464ea..b343e595 100644 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts @@ -403,18 +403,8 @@ const handleChest = async (dataBase: string, match: RegExpExecArray) => { currentMcAssets.blocksStates[currentBlockName] = blockStates } -function getParsedJSON (block: string, type: string) { - const versionParts = currentMcAssets.version.split(".") - const version = versionParts[0] + "." + versionParts[1] - return JSON.parse(fs.readFileSync(path.join(__dirname, `${type}/${version}/${block}.json`), 'utf-8')) -} - -function getBlockState (match: string) { - return getParsedJSON(match, 'blockStates') -} - async function loadBlockModelTextures (dataBase: string, blockModel: any) { - for (const key in Object.entries(blockModel.textures)) { + for (const key in blockModel.textures) { const texture: string = blockModel.textures[key] currentImage = await Jimp.read(dataBase + texture + '.png') blockModel.textures.particle = texture @@ -423,12 +413,6 @@ async function loadBlockModelTextures (dataBase: string, blockModel: any) { } } -async function getBlockModel (dataBase: string, block: string) { - const blockModel = getParsedJSON(block, 'blockModels') - await loadBlockModelTextures(dataBase, blockModel) - return blockModel -} - const handlers = [ [/(.+)_shulker_box$/, handleShulkerBox], [/^shulker_box$/, handleShulkerBox], @@ -458,15 +442,22 @@ export const tryHandleBlockEntity = async (dataBase, blockName) => { const handleExternalData = async (dataBase: string, version: string) => { const [major, minor] = version.split(".") const dataVer = `${major}.${minor}` - if (!fs.existsSync(path.join(__dirname, 'data', dataVer))) return - const allModels = fs.readdirSync(path.join(__dirname, 'data', dataVer, 'blockModels')).map(x => x.replace('.json', '')) - for (const model of allModels) { - currentMcAssets.blocksModels[model] = await getBlockModel(dataBase, model) + const baseDir = path.join(__dirname, 'data', dataVer) + if (!fs.existsSync(baseDir)) return + + const blockModelsDir = path.join(baseDir, 'blockModels') + const allBlockModels = fs.readdirSync(blockModelsDir).map(x => x.replace('.json', '')) + for (const blockModel of allBlockModels) { + const model = JSON.parse(fs.readFileSync(path.join(blockModelsDir, blockModel + '.json'), 'utf-8')) + currentMcAssets.blocksModels[blockModel] = model + await loadBlockModelTextures(dataBase, model) } - const allBlockStates = fs.readdirSync(path.join(__dirname, 'data', dataVer, 'blockStates')).map(x => x.replace('.json', '')) + const blockStatesDir = path.join(baseDir, 'blockStates') + const allBlockStates = fs.readdirSync(blockStatesDir).map(x => x.replace('.json', '')) for (const blockState of allBlockStates) { - currentMcAssets.blocksStates[blockState] = await getBlockState(blockState) + const state = JSON.parse(fs.readFileSync(path.join(blockStatesDir, blockState + '.json'), 'utf-8')) + currentMcAssets.blocksStates[blockState] = state } } From 32de8ebacda4e63ea93d73219e978ffd9c09123a Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 4 Jun 2024 18:00:42 +0300 Subject: [PATCH 0126/1097] fix: fix all known minecraft-protocol issues. Fixed auto-version. Fixed: kick messages are now always displayed! --- cypress/minecraft-server.mjs | 1 + pnpm-lock.yaml | 8 ++++---- src/index.ts | 27 +++++++++++++++++---------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/cypress/minecraft-server.mjs b/cypress/minecraft-server.mjs index 18f4e3db..32be0c9d 100644 --- a/cypress/minecraft-server.mjs +++ b/cypress/minecraft-server.mjs @@ -2,6 +2,7 @@ import mcServer from 'flying-squid' import defaultOptions from 'flying-squid/config/default-settings.json' assert { type: 'json' } +/** @type {Options} */ const serverOptions = { ...defaultOptions, 'online-mode': false, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6fdf4afa..8bf3f7d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,7 +138,7 @@ importers: version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify - version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434 node-gzip: specifier: ^1.1.2 version: 1.1.2 @@ -6224,8 +6224,8 @@ packages: nested-error-stacks@2.1.1: resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070: - resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070} + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434} version: 0.2.4 nice-try@1.0.5: @@ -15990,7 +15990,7 @@ snapshots: nested-error-stacks@2.1.1: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d827dba61bd2f9ac9a6086fe2079a0fccadd070: + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434: dependencies: body-parser: 1.20.2 express: 4.18.2 diff --git a/src/index.ts b/src/index.ts index d02f7b92..e89bc186 100644 --- a/src/index.ts +++ b/src/index.ts @@ -186,7 +186,7 @@ let lastMouseMove: number const updateCursor = () => { worldInteractions.update() } -function onCameraMove (e) { +function onCameraMove(e) { if (e.type !== 'touchmove' && !pointerLock.hasPointerLock) return e.stopPropagation?.() const now = performance.now() @@ -212,7 +212,7 @@ contro.on('stickMovement', ({ stick, vector }) => { miscUiState.usingGamepadInput = true }) -function hideCurrentScreens () { +function hideCurrentScreens() { activeModalStacks['main-menu'] = [...activeModalStack] insertActiveModalStack('', []) } @@ -220,7 +220,7 @@ function hideCurrentScreens () { const loadSingleplayer = (serverOverrides = {}, flattenedServerOverrides = {}) => { void connect({ singleplayer: true, username: options.localUsername, password: '', serverOverrides, serverOverridesFlat: flattenedServerOverrides }) } -function listenGlobalEvents () { +function listenGlobalEvents() { window.addEventListener('connect', e => { const options = (e as CustomEvent).detail void connect(options) @@ -261,7 +261,7 @@ const cleanConnectIp = (host: string | undefined, defaultPort: string | undefine } } -async function connect (connectOptions: ConnectOptions) { +async function connect(connectOptions: ConnectOptions) { if (miscUiState.gameLoaded) return miscUiState.hasErrors = false lastConnectOptions.value = connectOptions @@ -444,18 +444,18 @@ async function connect (connectOptions: ConnectOptions) { } : {}, ...singleplayer ? { version: serverOptions.version, - connect () { }, + connect() { }, Client: CustomChannelClient as any, } : {}, username, password, viewDistance: renderDistance, checkTimeoutInterval: 240 * 1000, - noPongTimeout: 240 * 1000, + // noPongTimeout: 240 * 1000, closeTimeout: 240 * 1000, respawn: options.autoRespawn, maxCatchupTicks: 0, - async versionSelectedHook (client) { + async versionSelectedHook(client) { await downloadMcData(client.version) setLoadingScreenStatus(initialLoadingText) }, @@ -484,6 +484,13 @@ async function connect (connectOptions: ConnectOptions) { //@ts-expect-error bot._client.socket._ws.addEventListener('close', () => { console.log('WebSocket connection closed') + setTimeout(() => { + if (bot) { + bot.emit('end', 'WebSocket connection closed with unknown reason') + } + }, 1000) + }) + bot._client.socket.on('close', () => { setTimeout(() => { if (bot) { bot.emit('end', 'WebSocket connection closed with unknown reason') @@ -606,7 +613,7 @@ async function connect (connectOptions: ConnectOptions) { dayCycle() // Bot position callback - function botPosition () { + function botPosition() { viewer.world.lastCamUpdate = Date.now() // this might cause lag, but not sure viewer.setFirstPersonCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch) @@ -626,7 +633,7 @@ async function connect (connectOptions: ConnectOptions) { bot.entity.yaw -= x } - function changeCallback () { + function changeCallback() { if (notificationProxy.id === 'pointerlockchange') { hideNotification() } @@ -895,7 +902,7 @@ downloadAndOpenFile().then((downloadAction) => { const unsubscribe = subscribe(miscUiState, checkCanDisplay) checkCanDisplay() // eslint-disable-next-line no-inner-declarations - function checkCanDisplay () { + function checkCanDisplay() { if (miscUiState.appConfig) { unsubscribe() openServerEditor() From 423aa6a49c75022e48e636b3eaa21509810bfef4 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 4 Jun 2024 18:04:34 +0300 Subject: [PATCH 0127/1097] fix eslint --- src/index.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/index.ts b/src/index.ts index e89bc186..07781028 100644 --- a/src/index.ts +++ b/src/index.ts @@ -186,7 +186,7 @@ let lastMouseMove: number const updateCursor = () => { worldInteractions.update() } -function onCameraMove(e) { +function onCameraMove (e) { if (e.type !== 'touchmove' && !pointerLock.hasPointerLock) return e.stopPropagation?.() const now = performance.now() @@ -212,7 +212,7 @@ contro.on('stickMovement', ({ stick, vector }) => { miscUiState.usingGamepadInput = true }) -function hideCurrentScreens() { +function hideCurrentScreens () { activeModalStacks['main-menu'] = [...activeModalStack] insertActiveModalStack('', []) } @@ -220,7 +220,7 @@ function hideCurrentScreens() { const loadSingleplayer = (serverOverrides = {}, flattenedServerOverrides = {}) => { void connect({ singleplayer: true, username: options.localUsername, password: '', serverOverrides, serverOverridesFlat: flattenedServerOverrides }) } -function listenGlobalEvents() { +function listenGlobalEvents () { window.addEventListener('connect', e => { const options = (e as CustomEvent).detail void connect(options) @@ -261,7 +261,7 @@ const cleanConnectIp = (host: string | undefined, defaultPort: string | undefine } } -async function connect(connectOptions: ConnectOptions) { +async function connect (connectOptions: ConnectOptions) { if (miscUiState.gameLoaded) return miscUiState.hasErrors = false lastConnectOptions.value = connectOptions @@ -444,7 +444,7 @@ async function connect(connectOptions: ConnectOptions) { } : {}, ...singleplayer ? { version: serverOptions.version, - connect() { }, + connect () { }, Client: CustomChannelClient as any, } : {}, username, @@ -455,7 +455,7 @@ async function connect(connectOptions: ConnectOptions) { closeTimeout: 240 * 1000, respawn: options.autoRespawn, maxCatchupTicks: 0, - async versionSelectedHook(client) { + async versionSelectedHook (client) { await downloadMcData(client.version) setLoadingScreenStatus(initialLoadingText) }, @@ -613,7 +613,7 @@ async function connect(connectOptions: ConnectOptions) { dayCycle() // Bot position callback - function botPosition() { + function botPosition () { viewer.world.lastCamUpdate = Date.now() // this might cause lag, but not sure viewer.setFirstPersonCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch) @@ -633,7 +633,7 @@ async function connect(connectOptions: ConnectOptions) { bot.entity.yaw -= x } - function changeCallback() { + function changeCallback () { if (notificationProxy.id === 'pointerlockchange') { hideNotification() } @@ -902,7 +902,7 @@ downloadAndOpenFile().then((downloadAction) => { const unsubscribe = subscribe(miscUiState, checkCanDisplay) checkCanDisplay() // eslint-disable-next-line no-inner-declarations - function checkCanDisplay() { + function checkCanDisplay () { if (miscUiState.appConfig) { unsubscribe() openServerEditor() From 98da719e08495d75dfac919477ab0d71bf676a9e Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 5 Jun 2024 11:58:26 +0300 Subject: [PATCH 0128/1097] fix show ui when has modals --- src/reactUi.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 2f57e6f0..449d7883 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -4,7 +4,7 @@ import { useSnapshot } from 'valtio' import { QRCodeSVG } from 'qrcode.react' import { createPortal } from 'react-dom' import { useEffect, useMemo, useState } from 'react' -import { miscUiState } from './globalState' +import { activeModalStack, miscUiState } from './globalState' import DeathScreenProvider from './react/DeathScreenProvider' import OptionsRenderApp from './react/OptionsRenderApp' import MainMenuRenderApp from './react/MainMenuRenderApp' @@ -95,7 +95,9 @@ const InGameComponent = ({ children }) => { } const InGameUi = () => { - const { gameLoaded, showUI } = useSnapshot(miscUiState) + const { gameLoaded, showUI: showUIRaw } = useSnapshot(miscUiState) + const hasModals = useSnapshot(activeModalStack).length > 0 + const showUI = showUIRaw || hasModals if (!gameLoaded) return return <> From 9a41214674458eea922298a2ae66d263b74705fa Mon Sep 17 00:00:00 2001 From: Vitaly Date: Thu, 6 Jun 2024 16:52:05 +0300 Subject: [PATCH 0129/1097] fix: fix breaking mesh was highlighted --- src/worldInteractions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 330dabd7..0245d418 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -68,7 +68,8 @@ class WorldInteraction { } const breakMaterial = new THREE.MeshBasicMaterial({ transparent: true, - blending: THREE.MultiplyBlending + blending: THREE.MultiplyBlending, + alphaTest: 0.5, }) this.blockBreakMesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), breakMaterial) this.blockBreakMesh.visible = false From d04a66738ef5c713379f155ac1f2bfaf1d610e33 Mon Sep 17 00:00:00 2001 From: arhellist <92224498+arhellist@users.noreply.github.com> Date: Thu, 6 Jun 2024 18:23:43 +0400 Subject: [PATCH 0130/1097] fix game crash (#144) --- src/react/DebugOverlay.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/react/DebugOverlay.tsx b/src/react/DebugOverlay.tsx index dd288b49..c83418f5 100644 --- a/src/react/DebugOverlay.tsx +++ b/src/react/DebugOverlay.tsx @@ -73,7 +73,7 @@ export default () => { } } - useMemo(() => { + useEffect(() => { document.addEventListener('keydown', handleF3) const packetsUpdateInterval = setInterval(() => { setPacketsString(prev => `↓ ${received.current.count} (${(received.current.size / 1024).toFixed(2)} KB/s, ${getFixedFilesize(receivedTotal.current)}) ↑ ${sent.current.count}`) From fec59aac03c5d04c15f9e1932c154fb26b694582 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 6 Jun 2024 17:30:11 +0300 Subject: [PATCH 0131/1097] up mineflayer --- package.json | 2 +- pnpm-lock.yaml | 49 ++++++++++--------------------------------------- src/index.ts | 9 --------- 3 files changed, 11 insertions(+), 49 deletions(-) diff --git a/package.json b/package.json index 9451b266..fa28ae5d 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "http-server": "^14.1.1", "https-browserify": "^1.0.0", "minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next", - "mineflayer": "github:PrismarineJS/mineflayer", + "mineflayer": "github:zardoy/mineflayer", "mineflayer-pathfinder": "^2.4.4", "npm-run-all": "^4.1.5", "os-browserify": "^0.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8bf3f7d0..f9928dc6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -301,8 +301,8 @@ importers: specifier: github:zardoy/minecraft-inventory-gui#next version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5(@types/react@18.2.20)(react@18.2.0) mineflayer: - specifier: github:PrismarineJS/mineflayer - version: https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f(encoding@0.1.13) + specifier: github:zardoy/mineflayer + version: https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192(encoding@0.1.13) mineflayer-pathfinder: specifier: ^2.4.4 version: 2.4.4 @@ -6039,10 +6039,6 @@ packages: resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5} version: 1.0.1 - minecraft-protocol@1.47.0: - resolution: {integrity: sha512-IHL8faXLLIWv1O+2v2NgyKlooilu/OiSL9orI8Kqed/rZvVOrFPzs2PwMAYjpQX9gxLPhiSU19KqZ8CjfNuqhg==} - engines: {node: '>=14'} - minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc: resolution: {tarball: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc} version: 1.47.0 @@ -6071,8 +6067,8 @@ packages: resolution: {integrity: sha512-QMMNPx4IyZE7ydAzjvGLQLCnQNUOfkk1qVZKxTTS9q3qPTAewz4GhsVUBtbQ8LSbHthe5RcQ1Sgxs4wlIma/Qw==} engines: {node: '>=18'} - mineflayer@https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f: - resolution: {tarball: https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f} + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192} version: 4.20.1 engines: {node: '>=18'} @@ -15685,31 +15681,6 @@ snapshots: - '@types/react' - react - minecraft-protocol@1.47.0(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13): - dependencies: - '@types/readable-stream': 4.0.12 - aes-js: 3.1.2 - buffer-equal: 1.0.1 - debug: 4.3.4(supports-color@8.1.1) - endian-toggle: 0.0.0 - lodash.get: 4.4.2 - lodash.merge: 4.6.2 - minecraft-data: 3.65.0 - minecraft-folder-path: 1.2.0 - node-fetch: 2.7.0(encoding@0.1.13) - node-rsa: 0.4.2 - prismarine-auth: 2.4.2(encoding@0.1.13) - prismarine-chat: 1.10.1 - prismarine-nbt: 2.5.0 - prismarine-realms: 1.3.2(encoding@0.1.13) - protodef: 1.15.0 - readable-stream: 4.5.2 - uuid-1345: 1.0.2 - yggdrasil: 1.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding - - supports-color - minecraft-protocol@https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13): dependencies: '@types/readable-stream': 4.0.12 @@ -15804,11 +15775,11 @@ snapshots: mineflayer@4.20.1(encoding@0.1.13): dependencies: minecraft-data: 3.65.0 - minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/ccab9fb39681f3ebe0d264e2a3f833aa3c5a1ac7(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-chat: 1.10.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -15824,14 +15795,14 @@ snapshots: - encoding - supports-color - mineflayer@https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/5a544cf2547a6e0f1f17786962d77a33c661c02f(encoding@0.1.13): + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192(encoding@0.1.13): dependencies: minecraft-data: 3.65.0 - minecraft-protocol: 1.47.0(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) + minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 - prismarine-chat: 1.9.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + prismarine-chat: 1.10.1 + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 diff --git a/src/index.ts b/src/index.ts index 07781028..3b48a492 100644 --- a/src/index.ts +++ b/src/index.ts @@ -568,15 +568,6 @@ async function connect (connectOptions: ConnectOptions) { window.Vec3 = Vec3 window.pathfinder = pathfinder - // patch mineflayer - // todo move to mineflayer - bot.inventory.on('updateSlot', (index) => { - if ((index as unknown as number) === bot.quickBarSlot + bot.inventory.hotbarStart) { - //@ts-expect-error - bot.emit('heldItemChanged') - } - }) - miscUiState.gameLoaded = true miscUiState.loadedServerIndex = connectOptions.serverIndex ?? '' customEvents.emit('gameLoaded') From bd54b5bd807534bb30deb7e0314f089bcee8d715 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 6 Jun 2024 19:09:07 +0300 Subject: [PATCH 0132/1097] fix: username override of servers was never used --- src/react/ServersList.tsx | 18 ++++++++++-------- src/react/ServersListProvider.tsx | 17 +++++++++-------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/react/ServersList.tsx b/src/react/ServersList.tsx index f6b89452..f3759bce 100644 --- a/src/react/ServersList.tsx +++ b/src/react/ServersList.tsx @@ -5,14 +5,12 @@ import Singleplayer from './Singleplayer' import Input from './Input' import Button from './Button' import PixelartIcon from './PixelartIcon' +import { BaseServerInfo } from './AddServerOrConnect' interface Props extends React.ComponentProps { - joinServer: (ip: string, overrides: { - username?: string - password?: string - proxy?: string - versionOverride?: string + joinServer: (info: BaseServerInfo, additional: { shouldSave?: boolean + index?: number }) => void initialProxies: SavedProxiesLocalStorage updateProxies: (proxies: SavedProxiesLocalStorage) => void @@ -67,9 +65,11 @@ export default ({ initialProxies, updateProxies: updateProxiesProp, joinServer, version = parts.at(-1)! ip = parts.slice(0, -1).join(':') } - joinServer(ip, { - shouldSave: save, + joinServer({ + ip, versionOverride: version, + }, { + shouldSave: save, }) }} > @@ -116,7 +116,9 @@ export default ({ initialProxies, updateProxies: updateProxiesProp, joinServer, serversLayout onWorldAction={(action, serverName) => { if (action === 'load') { - joinServer(serverName, {}) + joinServer({ + ip: serverName, + }, {}) } props.onWorldAction?.(action, serverName) }} diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index bb23004f..9772c9b4 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -231,10 +231,11 @@ const Inner = () => { } return { + joinServer={(overrides, { shouldSave }) => { + const indexOrIp = overrides.ip let ip = indexOrIp let server: StoreServerItem | undefined - if (overrides.shouldSave === undefined) { + if (shouldSave === undefined) { // hack: inner component doesn't know of overrides for existing servers server = serversListSorted.find(s => s.index.toString() === indexOrIp)! ip = server.ip @@ -242,7 +243,7 @@ const Inner = () => { } const lastJoinedUsername = serversListSorted.find(s => s.usernameOverride)?.usernameOverride - let username = overrides.username || defaultUsername + let username = overrides.usernameOverride || defaultUsername if (!username) { username = prompt('Username', lastJoinedUsername || '') if (!username) return @@ -251,13 +252,13 @@ const Inner = () => { const options = { username, server: normalizeIp(ip), - proxy: overrides.proxy || selectedProxy, + proxy: overrides.proxyOverride || selectedProxy, botVersion: overrides.versionOverride ?? /* legacy */ overrides['version'], - password: overrides.password, + password: overrides.passwordOverride, ignoreQs: true, autoLoginPassword: server?.autoLogin?.[username], onSuccessfulPlay () { - if (overrides.shouldSave && !serversList.some(s => s.ip === ip)) { + if (shouldSave && !serversList.some(s => s.ip === ip)) { const newServersList: StoreServerItem[] = [...serversList, { ip, lastJoined: Date.now(), @@ -267,7 +268,7 @@ const Inner = () => { setNewServersList(newServersList) // component is not mounted } - if (overrides.shouldSave === undefined) { // loading saved + if (shouldSave === undefined) { // loading saved // find and update const server = serversList.find(s => s.ip === ip) if (server) { @@ -286,7 +287,7 @@ const Inner = () => { localStorage.setItem('selectedProxy', selectedProxy) } }, - serverIndex: overrides.shouldSave ? serversList.length.toString() : indexOrIp // assume last + serverIndex: shouldSave ? serversList.length.toString() : indexOrIp // assume last } satisfies ConnectOptions dispatchEvent(new CustomEvent('connect', { detail: options })) // qsOptions From aa18c3cbbdd1dd770f75f6695dd6bfff15b61a51 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 6 Jun 2024 19:52:12 +0300 Subject: [PATCH 0133/1097] add ping proxy implementation --- src/index.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/index.ts b/src/index.ts index 3b48a492..fe584b4d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -498,6 +498,22 @@ async function connect (connectOptions: ConnectOptions) { }) }) }) + let i = 0 + //@ts-expect-error + bot.pingProxy = async () => { + const curI = ++i + return new Promise(resolve => { + //@ts-expect-error + bot._client.socket._ws.send(`ping:${curI}`) + const date = Date.now() + const onPong = (received) => { + if (received !== curI.toString()) return + bot._client.socket.off('pong' as any, onPong) + resolve(Date.now() - date) + } + bot._client.socket.on('pong' as any, onPong) + }) + } } // socket setup actually can be delayed because of dns lookup if (bot._client.socket) { From 1e741c7c7a44fd783c2f76875b2d20cc618f8683 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 6 Jun 2024 19:53:08 +0300 Subject: [PATCH 0134/1097] up net-browserify --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f9928dc6..7ced3b41 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,7 +138,7 @@ importers: version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify - version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99 node-gzip: specifier: ^1.1.2 version: 1.1.2 @@ -6220,8 +6220,8 @@ packages: nested-error-stacks@2.1.1: resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434: - resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434} + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99} version: 0.2.4 nice-try@1.0.5: @@ -15961,7 +15961,7 @@ snapshots: nested-error-stacks@2.1.1: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/e7c50bf824ae5b4d987967fd921d8634dad03434: + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99: dependencies: body-parser: 1.20.2 express: 4.18.2 From 4c03d68b03f4748d41fe238a4aa81a8f14ed0089 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 7 Jun 2024 00:22:41 +0300 Subject: [PATCH 0135/1097] up browserify --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ced3b41..10add82d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,7 +138,7 @@ importers: version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify - version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61 node-gzip: specifier: ^1.1.2 version: 1.1.2 @@ -6220,8 +6220,8 @@ packages: nested-error-stacks@2.1.1: resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99: - resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99} + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61} version: 0.2.4 nice-try@1.0.5: @@ -15961,7 +15961,7 @@ snapshots: nested-error-stacks@2.1.1: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/7d4650ff39943d1358a05d7197c3caa12fa8fb99: + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61: dependencies: body-parser: 1.20.2 express: 4.18.2 From bbf8fbf4a5fed3387b2329f39d3037cde595dbff Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 7 Jun 2024 01:30:00 +0300 Subject: [PATCH 0136/1097] fix o.text.includes is not a function crash --- src/botUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/botUtils.ts b/src/botUtils.ts index 30e13834..79b10118 100644 --- a/src/botUtils.ts +++ b/src/botUtils.ts @@ -101,7 +101,7 @@ export const formatMessage = (message: MessageInput, mcData: IndexedData = globa msglist = msglist.map(msg => { // normalize § - if (!msg.text.includes('§')) return msg + if (!msg.text.includes?.('§')) return msg const newMsg = fromFormattedString(msg.text) return flat(newMsg) }).flat(Infinity) From 94c665d851f8366b31ca4aa8873526dd53840af8 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 8 Jun 2024 23:13:44 +0300 Subject: [PATCH 0137/1097] move everything to frequent update interval --- src/react/DebugOverlay.tsx | 7 +------ src/reactUi.tsx | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/react/DebugOverlay.tsx b/src/react/DebugOverlay.tsx index c83418f5..bb38672e 100644 --- a/src/react/DebugOverlay.tsx +++ b/src/react/DebugOverlay.tsx @@ -91,6 +91,7 @@ export default () => { setDimension(bot.game.dimension) setDay(bot.time.day) setCursorBlock(worldInteractions.cursorBlock) + setEntitiesCount(Object.values(bot.entities).length) }, 100) // @ts-expect-error @@ -101,12 +102,6 @@ export default () => { sent.current.count++ managePackets('sent', name, data) }) - bot.on('entitySpawn', () => { - setEntitiesCount(Object.values(bot.entities).length) - }) - bot.on('entityGone', () => { - setEntitiesCount(Object.values(bot.entities).length) - }) try { const gl = window.renderer.getContext() diff --git a/src/reactUi.tsx b/src/reactUi.tsx index 449d7883..8a9cc32c 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -98,7 +98,7 @@ const InGameUi = () => { const { gameLoaded, showUI: showUIRaw } = useSnapshot(miscUiState) const hasModals = useSnapshot(activeModalStack).length > 0 const showUI = showUIRaw || hasModals - if (!gameLoaded) return + if (!gameLoaded || !bot) return return <> From 6be0bc8c9a93d79f0524d0e8bdb7041941e5c27d Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 8 Jun 2024 23:20:07 +0300 Subject: [PATCH 0138/1097] fix: elytra equipped crashed hud bars fix sentry 5457375830 --- src/react/HudBarsProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/react/HudBarsProvider.tsx b/src/react/HudBarsProvider.tsx index 746d4819..ea78ae08 100644 --- a/src/react/HudBarsProvider.tsx +++ b/src/react/HudBarsProvider.tsx @@ -82,7 +82,7 @@ export default () => { const item = bot.inventory.slots[slotIndex] ?? null if (!item) continue const armorName = item.name.split('_') - points += armor[armorName[0]][armorName[1]] + points += armor[armorName[0]]?.[armorName[1]] ?? 0 } setArmorValue(points) } From 409577d8e0b272ec155e9cbfc96e94a0295b49de Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 9 Jun 2024 00:19:08 +0300 Subject: [PATCH 0139/1097] up net --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10add82d..38a9ebb6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,7 +138,7 @@ importers: version: 2.0.4 net-browserify: specifier: github:zardoy/prismarinejs-net-browserify - version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61 + version: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/99434199f25d3c6bbe15833bb78ec40b07c2df6f node-gzip: specifier: ^1.1.2 version: 1.1.2 @@ -6220,8 +6220,8 @@ packages: nested-error-stacks@2.1.1: resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61: - resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61} + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/99434199f25d3c6bbe15833bb78ec40b07c2df6f: + resolution: {tarball: https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/99434199f25d3c6bbe15833bb78ec40b07c2df6f} version: 0.2.4 nice-try@1.0.5: @@ -15961,7 +15961,7 @@ snapshots: nested-error-stacks@2.1.1: {} - net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/2ed580ba422781addd1166ab31eede5914cd5f61: + net-browserify@https://codeload.github.com/zardoy/prismarinejs-net-browserify/tar.gz/99434199f25d3c6bbe15833bb78ec40b07c2df6f: dependencies: body-parser: 1.20.2 express: 4.18.2 From 6268561e4148dbaec0de0c6965e3423ccb709849 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 9 Jun 2024 01:09:02 +0300 Subject: [PATCH 0140/1097] make inputs in server editor a bit smaller, fix proxy select --- src/react/AddServerOrConnect.tsx | 60 +++++++++++++++++++------------- src/react/ServersList.tsx | 4 +-- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/react/AddServerOrConnect.tsx b/src/react/AddServerOrConnect.tsx index 500c1e61..d74ff8fe 100644 --- a/src/react/AddServerOrConnect.tsx +++ b/src/react/AddServerOrConnect.tsx @@ -23,6 +23,8 @@ interface Props { defaults?: Pick } +const ELEMENTS_WIDTH = 190 + export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQs, onQsConnect, defaults }: Props) => { const qsParams = parseQs ? new URLSearchParams(window.location.search) : undefined @@ -41,24 +43,25 @@ export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQ const lockConnect = qsParams?.get('lockConnect') === 'true' return - { - e.preventDefault() - let ip = serverIp.includes(':') ? serverIp : `${serverIp}:${serverPort}` - ip = ip.replace(/:$/, '') - onConfirm({ - name: serverName, - ip, - versionOverride, - proxyOverride, - usernameOverride, - passwordOverride - }) - }} + { + e.preventDefault() + let ip = serverIp.includes(':') ? serverIp : `${serverIp}:${serverPort}` + ip = ip.replace(/:$/, '') + onConfirm({ + name: serverName, + ip, + versionOverride, + proxyOverride, + usernameOverride, + passwordOverride + }) + }} >
setProxyOverride(value)} placeholder={defaults?.proxyOverride} /> setUsernameOverride(value)} placeholder={defaults?.usernameOverride} /> setPasswordOverride(value)} /* placeholder='For advanced usage only' */ /> - {!lockConnect && <>} + {!lockConnect && <> + { + onBack() + }}>Cancel + Save + } {qsParams?.get('ip') &&
- + >Connect
}
} +const ButtonWrapper = ({ ...props }: React.ComponentProps) => { + props.style ??= {} + props.style.width = ELEMENTS_WIDTH + return
From 05a0d3a184ae4478470f11046b89d7f45160b4a1 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 9 Jun 2024 02:02:26 +0300 Subject: [PATCH 0141/1097] fix: attack entities on left click not on right click --- src/worldInteractions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/worldInteractions.ts b/src/worldInteractions.ts index 0245d418..49c21c2e 100644 --- a/src/worldInteractions.ts +++ b/src/worldInteractions.ts @@ -90,7 +90,7 @@ class WorldInteraction { const entity = getEntityCursor() - if (entity && e.button === 2) { + if (entity && e.button === 0) { bot.attack(entity) } else { // bot From 353bec4c6b718ab3a2b54f147a35d04fa274c058 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Sun, 9 Jun 2024 18:12:34 +0300 Subject: [PATCH 0142/1097] fix: fix entity label display for older versions of minecraft --- prismarine-viewer/viewer/lib/entities.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.js b/prismarine-viewer/viewer/lib/entities.js index 28fc6d89..94f06e0c 100644 --- a/prismarine-viewer/viewer/lib/entities.js +++ b/prismarine-viewer/viewer/lib/entities.js @@ -267,11 +267,15 @@ export class Entities extends EventEmitter { } - displaySimpleText(jsonLike) { + parseEntityLabel(jsonLike) { if (!jsonLike) return - const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike) - const text = flat(parsed).map(x => x.text) - return text.join('') + try { + const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike) + const text = flat(parsed).map(x => x.text) + return text.join('') + } catch (err) { + return jsonLike + } } update(/** @type {import('prismarine-entity').Entity & {delete?, pos}} */entity, overrides) { @@ -410,7 +414,7 @@ export class Entities extends EventEmitter { } } // not player - const displayText = entity.metadata?.[3] && this.displaySimpleText(entity.metadata[2]) + const displayText = entity.metadata?.[3] && this.parseEntityLabel(entity.metadata[2]) if (entity.name !== 'player' && displayText) { addNametag({ ...entity, username: displayText }, this.entitiesOptions, this.entities[entity.id].children.find(c => c.name === 'mesh')) } From 7f3d5ca1f0ead78528f065c55ba3724f951b875b Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 10 Jun 2024 03:27:34 +0300 Subject: [PATCH 0143/1097] rename project to minecraft-web-client fixes issue146 --- README.NPM.MD | 2 +- package.json | 2 +- package.npm.json | 2 +- scripts/downloadSoundsMap.mjs | 2 +- scripts/prepareSounds.mjs | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.NPM.MD b/README.NPM.MD index 24c90bc9..c036adba 100644 --- a/README.NPM.MD +++ b/README.NPM.MD @@ -24,7 +24,7 @@ const App = () => { } ``` -See [Storybook](https://mcraft.fun/storybook/) or [Storybook (Mirror link)](https://mcon.vercel.app/storybook/) for more examples and full components list. Also take a look at the full [standalone example](https://github.com/zardoy/prismarine-web-client/tree/experiments/UiStandaloneExample.tsx). +See [Storybook](https://mcraft.fun/storybook/) or [Storybook (Mirror link)](https://mcon.vercel.app/storybook/) for more examples and full components list. Also take a look at the full [standalone example](https://github.com/zardoy/minecraft-web-client/tree/experiments/UiStandaloneExample.tsx). There are two types of components: diff --git a/package.json b/package.json index fa28ae5d..7bbde636 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "prismarine-web-client", + "name": "minecraft-web-client", "version": "0.0.0-dev", "description": "A minecraft client running in a browser", "scripts": { diff --git a/package.npm.json b/package.npm.json index bae8b60f..7e13d67b 100644 --- a/package.npm.json +++ b/package.npm.json @@ -26,7 +26,7 @@ }, "module": "./dist/react/npmReactComponents.js", "types": "./dist/react/npmReactComponents.d.ts", - "repository": "zardoy/prismarine-web-client", + "repository": "zardoy/minecraft-web-client", "version": "0.0.0-dev", "dependencies": {}, "peerDependencies": { diff --git a/scripts/downloadSoundsMap.mjs b/scripts/downloadSoundsMap.mjs index 066a3df7..3c335f8f 100644 --- a/scripts/downloadSoundsMap.mjs +++ b/scripts/downloadSoundsMap.mjs @@ -1,6 +1,6 @@ import fs from 'fs' -const url = 'https://github.com/zardoy/prismarine-web-client/raw/sounds-generated/sounds.js' +const url = 'https://github.com/zardoy/minecraft-web-client/raw/sounds-generated/sounds.js' const savePath = 'dist/sounds.js' fetch(url).then(res => res.text()).then(data => { fs.writeFileSync(savePath, data, 'utf8') diff --git a/scripts/prepareSounds.mjs b/scripts/prepareSounds.mjs index 4ed119cb..8f3e5bef 100644 --- a/scripts/prepareSounds.mjs +++ b/scripts/prepareSounds.mjs @@ -61,7 +61,7 @@ const downloadAllSounds = async () => { } prevSounds = soundAssets } - async function downloadSound ({ name, hash, size }, namePath, log) { + async function downloadSound({ name, hash, size }, namePath, log) { const savePath = path.resolve(`generated/sounds/${namePath}`) if (fs.existsSync(savePath)) { // console.log('skipped', name) @@ -86,7 +86,7 @@ const downloadAllSounds = async () => { } writer.close() } - async function downloadSounds (assets, addPath = '') { + async function downloadSounds(assets, addPath = '') { for (let i = 0; i < assets.length; i += 5) { await Promise.all(assets.slice(i, i + 5).map((asset, j) => downloadSound(asset, `${addPath}${asset.name}`, () => { console.log('downloading', addPath, asset.name, i + j, '/', assets.length) @@ -135,7 +135,7 @@ const convertSounds = async () => { } const CONCURRENCY = 5 - for(let i = 0; i < toConvert.length; i += CONCURRENCY) { + for (let i = 0; i < toConvert.length; i += CONCURRENCY) { await Promise.all(toConvert.slice(i, i + CONCURRENCY).map((oggPath, j) => convertSound(i + j))) } } @@ -221,7 +221,7 @@ const makeSoundsBundle = async () => { const allSoundsMeta = { format: 'mp3', - baseUrl: 'https://raw.githubusercontent.com/zardoy/prismarine-web-client/sounds-generated/sounds/' + baseUrl: 'https://raw.githubusercontent.com/zardoy/minecraft-web-client/sounds-generated/sounds/' } await build({ From 7f4edbedba20b22bd9b903c780a2c268679d6463 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Jun 2024 03:26:24 +0300 Subject: [PATCH 0144/1097] rm manimali, replace with a better server --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index 1bbbfd47..e4f86060 100644 --- a/config.json +++ b/config.json @@ -15,9 +15,9 @@ "description": "One of the best servers here. Join now!" }, { - "ip": "play.minemalia.com", + "ip": "sus.shhnowisnottheti.me", "version": "1.18.2", - "description": "Only login with existing accounts." + "description": "Creative, your own 'boxes' (islands)" } ] } From 38e4efc79b4054bfc354ccaaf6fe5c5f572a3978 Mon Sep 17 00:00:00 2001 From: Wolf2323 Date: Tue, 11 Jun 2024 20:14:58 +0200 Subject: [PATCH 0145/1097] fix: improve signs models & text, added all missing sign types (#143) Co-authored-by: Vitaly Turovsky --- prismarine-viewer/viewer/lib/mesher/models.ts | 4 +- .../viewer/lib/mesher/test/tests.test.ts | 22 -- .../viewer/lib/worldrendererThree.ts | 27 +- prismarine-viewer/viewer/prepare/atlas.ts | 49 +-- .../data/1.13/blockModels/sign/oak.json | 6 + .../data/1.13/blockModels/sign/oak_wall.json | 6 + .../data/1.13/blockModels/sign/sign.json | 140 +++++++ .../data/1.13/blockModels/sign/sign_wall.json | 72 ++++ .../data/1.13/blockStates/sign/sign.json | 67 ++++ .../data/1.13/blockStates/sign/wall_sign.json | 19 + .../data/1.14/blockModels/sign/acacia.json | 6 + .../1.14/blockModels/sign/acacia_wall.json | 6 + .../data/1.14/blockModels/sign/birch.json | 6 + .../1.14/blockModels/sign/birch_wall.json | 6 + .../data/1.14/blockModels/sign/dark_oak.json | 6 + .../1.14/blockModels/sign/dark_oak_wall.json | 6 + .../data/1.14/blockModels/sign/jungle.json | 6 + .../1.14/blockModels/sign/jungle_wall.json | 7 + .../data/1.14/blockModels/sign/spruce.json | 6 + .../1.14/blockModels/sign/spruce_wall.json | 6 + .../1.14/blockStates/sign/acacia_sign.json | 67 ++++ .../blockStates/sign/acacia_wall_sign.json | 19 + .../1.14/blockStates/sign/birch_sign.json | 67 ++++ .../blockStates/sign/birch_wall_sign.json | 19 + .../1.14/blockStates/sign/dark_oak_sign.json | 67 ++++ .../blockStates/sign/dark_oak_wall_sign.json | 19 + .../1.14/blockStates/sign/jungle_sign.json | 67 ++++ .../blockStates/sign/jungle_wall_sign.json | 19 + .../data/1.14/blockStates/sign/oak_sign.json | 67 ++++ .../1.14/blockStates/sign/oak_wall_sign.json | 19 + .../1.14/blockStates/sign/spruce_sign.json | 67 ++++ .../blockStates/sign/spruce_wall_sign.json | 19 + .../data/1.16/blockModels/sign/crimson.json | 6 + .../1.16/blockModels/sign/crimson_wall.json | 6 + .../data/1.16/blockModels/sign/warped.json | 6 + .../1.16/blockModels/sign/warped_wall.json | 6 + .../1.16/blockStates/sign/crimson_sign.json | 67 ++++ .../blockStates/sign/crimson_wall_sign.json | 19 + .../1.16/blockStates/sign/warped_sign.json | 67 ++++ .../blockStates/sign/warped_wall_sign.json | 19 + .../data/1.19/blockModels/sign/mangrove.json | 6 + .../1.19/blockModels/sign/mangrove_wall.json | 6 + .../1.19/blockStates/sign/mangrove_sign.json | 67 ++++ .../blockStates/sign/mangrove_wall_sign.json | 19 + .../1.20/blockModels/sign/acacia_hanging.json | 7 + .../blockModels/sign/acacia_wall_hanging.json | 7 + .../data/1.20/blockModels/sign/bamboo.json | 6 + .../1.20/blockModels/sign/bamboo_hanging.json | 7 + .../1.20/blockModels/sign/bamboo_wall.json | 6 + .../blockModels/sign/bamboo_wall_hanging.json | 7 + .../1.20/blockModels/sign/birch_hanging.json | 7 + .../blockModels/sign/birch_wall_hanging.json | 7 + .../data/1.20/blockModels/sign/cherry.json | 6 + .../1.20/blockModels/sign/cherry_hanging.json | 7 + .../1.20/blockModels/sign/cherry_wall.json | 6 + .../blockModels/sign/cherry_wall_hanging.json | 7 + .../blockModels/sign/crimson_hanging.json | 7 + .../sign/crimson_wall_hanging.json | 7 + .../blockModels/sign/dark_oak_hanging.json | 7 + .../sign/dark_oak_wall_hanging.json | 7 + .../data/1.20/blockModels/sign/hanging.json | 115 ++++++ .../1.20/blockModels/sign/jungle_hanging.json | 7 + .../blockModels/sign/jungle_wall_hanging.json | 7 + .../blockModels/sign/mangrove_hanging.json | 7 + .../sign/mangrove_wall_hanging.json | 7 + .../1.20/blockModels/sign/oak_hanging.json | 7 + .../blockModels/sign/oak_wall_hanging.json | 7 + .../1.20/blockModels/sign/spruce_hanging.json | 7 + .../blockModels/sign/spruce_wall_hanging.json | 7 + .../1.20/blockModels/sign/wall_hanging.json | 347 ++++++++++++++++++ .../1.20/blockModels/sign/warped_hanging.json | 7 + .../blockModels/sign/warped_wall_hanging.json | 7 + .../blockStates/sign/acacia_hanging_sign.json | 67 ++++ .../sign/acacia_wall_hanging_sign.json | 19 + .../blockStates/sign/bamboo_hanging_sign.json | 67 ++++ .../1.20/blockStates/sign/bamboo_sign.json | 67 ++++ .../sign/bamboo_wall_hanging_sign.json | 19 + .../blockStates/sign/bamboo_wall_sign.json | 19 + .../blockStates/sign/birch_hanging_sign.json | 67 ++++ .../sign/birch_wall_hanging_sign.json | 19 + .../blockStates/sign/cherry_hanging_sign.json | 67 ++++ .../1.20/blockStates/sign/cherry_sign.json | 67 ++++ .../sign/cherry_wall_hanging_sign.json | 19 + .../blockStates/sign/cherry_wall_sign.json | 19 + .../sign/crimson_hanging_sign.json | 67 ++++ .../sign/crimson_wall_hanging_sign.json | 19 + .../sign/dark_oak_hanging_sign.json | 67 ++++ .../sign/dark_oak_wall_hanging_sign.json | 19 + .../blockStates/sign/jungle_hanging_sign.json | 67 ++++ .../sign/jungle_wall_hanging_sign.json | 19 + .../sign/mangrove_hanging_sign.json | 67 ++++ .../sign/mangrove_wall_hanging_sign.json | 19 + .../blockStates/sign/oak_hanging_sign.json | 67 ++++ .../sign/oak_wall_hanging_sign.json | 19 + .../blockStates/sign/spruce_hanging_sign.json | 67 ++++ .../sign/spruce_wall_hanging_sign.json | 19 + .../blockStates/sign/warped_hanging_sign.json | 67 ++++ .../sign/warped_wall_hanging_sign.json | 19 + .../viewer/prepare/modelsBuilder.ts | 10 +- .../viewer/prepare/moreGeneratedBlocks.ts | 193 +++------- 100 files changed, 3048 insertions(+), 196 deletions(-) create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_wall_hanging.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_wall_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_hanging_sign.json create mode 100644 prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_wall_hanging_sign.json diff --git a/prismarine-viewer/viewer/lib/mesher/models.ts b/prismarine-viewer/viewer/lib/mesher/models.ts index 39148aaa..c978c240 100644 --- a/prismarine-viewer/viewer/lib/mesher/models.ts +++ b/prismarine-viewer/viewer/lib/mesher/models.ts @@ -520,9 +520,11 @@ export function getSectionGeometry (sx, sy, sz, world: World) { "west": 1, "east": 3 } - const isWall = block.name.endsWith('wall_sign') || block.name.endsWith('hanging_sign') + const isWall = block.name.endsWith('wall_sign') || block.name.endsWith('wall_hanging_sign') + const isHanging = block.name.endsWith('hanging_sign') attr.signs[key] = { isWall, + isHanging, rotation: isWall ? facingRotationMap[props.facing] : +props.rotation } } diff --git a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts index 5a80fa49..de5db815 100644 --- a/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts +++ b/prismarine-viewer/viewer/lib/mesher/test/tests.test.ts @@ -45,12 +45,6 @@ test('Known blocks are not rendered', () => { // should be fixed, but to avoid regressions & for visibility expect(invalidBlocks).toMatchInlineSnapshot(` { - "acacia_hanging_sign": true, - "acacia_wall_hanging_sign": true, - "bamboo_hanging_sign": true, - "bamboo_wall_hanging_sign": true, - "birch_hanging_sign": true, - "birch_wall_hanging_sign": true, "black_banner": true, "black_bed": true, "black_candle": true, @@ -65,18 +59,12 @@ test('Known blocks are not rendered', () => { "brown_wall_banner": true, "bubble_column": true, "candle": true, - "cherry_hanging_sign": true, - "cherry_wall_hanging_sign": true, "creeper_head": true, "creeper_wall_head": true, - "crimson_hanging_sign": true, - "crimson_wall_hanging_sign": true, "cyan_banner": true, "cyan_bed": true, "cyan_candle": true, "cyan_wall_banner": true, - "dark_oak_hanging_sign": true, - "dark_oak_wall_hanging_sign": true, "dragon_head": true, "dragon_wall_head": true, "end_gateway": true, @@ -89,8 +77,6 @@ test('Known blocks are not rendered', () => { "green_bed": true, "green_candle": true, "green_wall_banner": true, - "jungle_hanging_sign": true, - "jungle_wall_hanging_sign": true, "light_blue_banner": true, "light_blue_bed": true, "light_blue_candle": true, @@ -107,10 +93,6 @@ test('Known blocks are not rendered', () => { "magenta_bed": true, "magenta_candle": true, "magenta_wall_banner": true, - "mangrove_hanging_sign": true, - "mangrove_wall_hanging_sign": true, - "oak_hanging_sign": true, - "oak_wall_hanging_sign": true, "orange_banner": true, "orange_bed": true, "orange_candle": true, @@ -138,12 +120,8 @@ test('Known blocks are not rendered', () => { "skeleton_skull": true, "skeleton_wall_skull": true, "snow": true, - "spruce_hanging_sign": true, - "spruce_wall_hanging_sign": true, "structure_void": true, "turtle_egg": true, - "warped_hanging_sign": true, - "warped_wall_hanging_sign": true, "water_cauldron": true, "white_banner": true, "white_bed": true, diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 4d28519a..095e5a94 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -112,11 +112,11 @@ export class WorldRendererThree extends WorldRendererCommon { } // should not compute it once if (Object.keys(data.geometry.signs).length) { - for (const [posKey, { isWall, rotation }] of Object.entries(data.geometry.signs)) { + for (const [posKey, { isWall, isHanging, rotation }] of Object.entries(data.geometry.signs)) { const [x, y, z] = posKey.split(',') const signBlockEntity = this.blockEntities[posKey] if (!signBlockEntity) continue - const sign = this.renderSign(new Vec3(+x, +y, +z), rotation, isWall, nbt.simplify(signBlockEntity)) + const sign = this.renderSign(new Vec3(+x, +y, +z), rotation, isWall, isHanging, nbt.simplify(signBlockEntity)) if (!sign) continue object.add(sign) } @@ -165,7 +165,7 @@ export class WorldRendererThree extends WorldRendererCommon { this.renderer.render(this.scene, this.camera) } - renderSign (position: Vec3, rotation: number, isWall: boolean, blockEntity) { + renderSign (position: Vec3, rotation: number, isWall: boolean, isHanging: boolean, blockEntity) { const tex = this.getSignTexture(position, blockEntity) if (!tex) return @@ -182,13 +182,16 @@ export class WorldRendererThree extends WorldRendererCommon { mesh.renderOrder = 999 // todo @sa2urami shouldnt all this be done in worker? - mesh.scale.set(1, 7 / 16, 1) - if (isWall) { - mesh.position.set(0, 0, -(8 - 1.5) / 16 + 0.001) + const lineHeight = 7 / 16; + const scaleFactor = isHanging ? 1.3 : 1 + mesh.scale.set(1 * scaleFactor, lineHeight * scaleFactor, 1 * scaleFactor) + + const thickness = (isHanging ? 2 : 1.5) / 16 + const wallSpacing = 0.25 / 16; + if (isWall && !isHanging) { + mesh.position.set(0, 0, -0.5 + thickness + wallSpacing + 0.0001) } else { - // standing - const faceEnd = 8.75 - mesh.position.set(0, 0, (faceEnd - 16 / 2) / 16 + 0.001) + mesh.position.set(0, 0, thickness / 2 + 0.0001) } const group = new THREE.Group() @@ -196,8 +199,10 @@ export class WorldRendererThree extends WorldRendererCommon { rotation * (isWall ? 90 : 45 / 2) ), 0) group.add(mesh) - const y = isWall ? 4.5 / 16 + mesh.scale.y / 2 : (1 - (mesh.scale.y / 2)) - group.position.set(position.x + 0.5, position.y + y, position.z + 0.5) + const height = (isHanging ? 10 : 8)/16 + const heightOffset = (isHanging ? 0 : isWall ? 4.333 : 9.333) / 16 + const textPosition = height/2 + heightOffset + group.position.set(position.x + 0.5, position.y + textPosition, position.z + 0.5) return group } diff --git a/prismarine-viewer/viewer/prepare/atlas.ts b/prismarine-viewer/viewer/prepare/atlas.ts index fc3e4029..cf73fdc4 100644 --- a/prismarine-viewer/viewer/prepare/atlas.ts +++ b/prismarine-viewer/viewer/prepare/atlas.ts @@ -49,19 +49,18 @@ export const makeTextureAtlas = (input: string[], getInputData: (name) => { cont const texturesIndex = {} - let skipXY = [] as [x: number, y: number][] - let offset = 0 + let nextX = 0 + let nextY = 0 + let rowMaxY = 0 + + const goToNextRow = () => { + nextX = 0 + nextY += rowMaxY + rowMaxY = 0 + } + const suSv = tileSize / imgSize for (const i in input) { - const pos = +i + offset - const x = (pos % texSize) * tileSize - const y = Math.floor(pos / texSize) * tileSize - - if (skipXY.some(([sx, sy]) => sx === x + 1 && sy === y)) { - // todo more offsets - offset++ - } - const img = new Image() const keyValue = input[i] const inputData = getInputData(keyValue) @@ -76,16 +75,24 @@ export const makeTextureAtlas = (input: string[], getInputData: (name) => { cont renderHeight = Math.ceil(img.height / tileSize) * tileSize su = renderWidth / imgSize sv = renderHeight / imgSize - if (renderWidth > tileSize) { - offset += Math.ceil(renderWidth / tileSize) - 1 - } - if (renderHeight > tileSize) { - const skipYs = Math.ceil(renderHeight / tileSize) - 1 - for (let i = 1; i <= skipYs; i++) { - skipXY.push([x, y + i]) - } + if (renderHeight > imgSize || renderWidth > imgSize) { + throw new Error('Texture ' + keyValue + ' is too big') } } + + if (nextX + renderWidth > imgSize) { + goToNextRow() + } + + const x = nextX + const y = nextY + + nextX += renderWidth + rowMaxY = Math.max(rowMaxY, renderHeight) + if (nextX >= imgSize) { + goToNextRow() + } + g.drawImage(img, 0, 0, renderWidth, renderHeight, x, y, renderWidth, renderHeight) const cleanName = keyValue.split('.').slice(0, -1).join('.') || keyValue @@ -116,7 +123,7 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) { // const textureFiles = mostEncounteredBlocks.map(x => x + '.png') textureFiles.unshift(...localTextures) - const { generated: additionalTextures, twoTileTextures, origSizeTextures } = getAdditionalTextures() + const { generated: additionalTextures, origSizeTextures } = getAdditionalTextures() textureFiles.push(...Object.keys(additionalTextures)) const atlas = makeTextureAtlas(textureFiles, name => { @@ -129,7 +136,7 @@ export function makeBlockTextureAtlas (mcAssets: McAssets) { return { contents, - tileWidthMult: twoTileTextures.includes(name) ? 2 : undefined, + // tileWidthMult: twoTileTextures.includes(name) ? 2 : undefined, origSizeTextures } }) diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak.json b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak.json new file mode 100644 index 00000000..2f16a429 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/sign" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak_wall.json b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak_wall.json new file mode 100644 index 00000000..dfdb230f --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/oak_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/sign" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign.json b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign.json new file mode 100644 index 00000000..4562cfae --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign.json @@ -0,0 +1,140 @@ +{ + "elements": [ + { + "from": [ + 7.25, + 0, + 7.25 + ], + "to": [ + 8.75, + 9.333, + 8.75 + ], + "faces": { + "north": { + "uv": [ + 1.5, + 8, + 2, + 15 + ], + "texture": "#sign" + }, + "east": { + "uv": [ + 1, + 8, + 1.5, + 15 + ], + "texture": "#sign" + }, + "south": { + "uv": [ + 0.5, + 8, + 1, + 15 + ], + "texture": "#sign" + }, + "west": { + "uv": [ + 0, + 8, + 0.5, + 15 + ], + "texture": "#sign" + }, + "up": { + "uv": [ + 0.5, + 7, + 1, + 8 + ], + "texture": "#sign" + }, + "down": { + "uv": [ + 1, + 7, + 1.5, + 8 + ], + "texture": "#sign" + } + } + }, + { + "from": [ + 0, + 9.333, + 7.25 + ], + "to": [ + 16, + 17.333, + 8.75 + ], + "faces": { + "north": { + "uv": [ + 7, + 1, + 13, + 7 + ], + "texture": "#sign" + }, + "east": { + "uv": [ + 6.5, + 1, + 7, + 7 + ], + "texture": "#sign" + }, + "south": { + "uv": [ + 0.5, + 1, + 6.5, + 7 + ], + "texture": "#sign" + }, + "west": { + "uv": [ + 0, + 1, + 0.5, + 7 + ], + "texture": "#sign" + }, + "up": { + "uv": [ + 0.5, + 0, + 6.5, + 1 + ], + "texture": "#sign" + }, + "down": { + "uv": [ + 6.5, + 1, + 12.5, + 0 + ], + "texture": "#sign" + } + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign_wall.json b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign_wall.json new file mode 100644 index 00000000..b743c983 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockModels/sign/sign_wall.json @@ -0,0 +1,72 @@ +{ + "elements": [ + { + "from": [ + 0, + 4.333, + 0.25 + ], + "to": [ + 16, + 12.333, + 1.75 + ], + "faces": { + "north": { + "uv": [ + 7, + 1, + 13, + 7 + ], + "texture": "#sign" + }, + "east": { + "uv": [ + 6.5, + 1, + 7, + 7 + ], + "texture": "#sign" + }, + "south": { + "uv": [ + 0.5, + 1, + 6.5, + 7 + ], + "texture": "#sign" + }, + "west": { + "uv": [ + 0, + 1, + 0.5, + 7 + ], + "texture": "#sign" + }, + "up": { + "uv": [ + 0.5, + 0, + 6.5, + 1 + ], + "texture": "#sign" + }, + "down": { + "uv": [ + 6.5, + 1, + 12.5, + 0 + ], + "texture": "#sign" + } + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/sign.json b/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/sign.json new file mode 100644 index 00000000..4ebcedcd --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/oak" + }, + "rotation=1": { + "model": "sign/oak", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/oak", + "y": 45 + }, + "rotation=3": { + "model": "sign/oak", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/oak", + "y": 90 + }, + "rotation=5": { + "model": "sign/oak", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/oak", + "y": 135 + }, + "rotation=7": { + "model": "sign/oak", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/oak", + "y": 180 + }, + "rotation=9": { + "model": "sign/oak", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/oak", + "y": 225 + }, + "rotation=11": { + "model": "sign/oak", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/oak", + "y": 270 + }, + "rotation=13": { + "model": "sign/oak", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/oak", + "y": 315 + }, + "rotation=15": { + "model": "sign/oak", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/wall_sign.json new file mode 100644 index 00000000..26453d53 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.13/blockStates/sign/wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/oak_wall" + }, + "facing=west": { + "model": "sign/oak_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/oak_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/oak_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia.json new file mode 100644 index 00000000..7057ded0 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/acacia" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia_wall.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia_wall.json new file mode 100644 index 00000000..70b755bf --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/acacia_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/acacia" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch.json new file mode 100644 index 00000000..d20d1438 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/birch" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch_wall.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch_wall.json new file mode 100644 index 00000000..c7983bee --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/birch_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/birch" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak.json new file mode 100644 index 00000000..803add52 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/dark_oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak_wall.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak_wall.json new file mode 100644 index 00000000..b410acfe --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/dark_oak_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/dark_oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle.json new file mode 100644 index 00000000..17d52250 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/jungle" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle_wall.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle_wall.json new file mode 100644 index 00000000..bfe6c8f8 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/jungle_wall.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/jungle" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce.json new file mode 100644 index 00000000..8f2b2179 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/spruce" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce_wall.json b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce_wall.json new file mode 100644 index 00000000..1509eb3c --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockModels/sign/spruce_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/spruce" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_sign.json new file mode 100644 index 00000000..370c2c84 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/acacia" + }, + "rotation=1": { + "model": "sign/acacia", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/acacia", + "y": 45 + }, + "rotation=3": { + "model": "sign/acacia", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/acacia", + "y": 90 + }, + "rotation=5": { + "model": "sign/acacia", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/acacia", + "y": 135 + }, + "rotation=7": { + "model": "sign/acacia", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/acacia", + "y": 180 + }, + "rotation=9": { + "model": "sign/acacia", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/acacia", + "y": 225 + }, + "rotation=11": { + "model": "sign/acacia", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/acacia", + "y": 270 + }, + "rotation=13": { + "model": "sign/acacia", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/acacia", + "y": 315 + }, + "rotation=15": { + "model": "sign/acacia", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_wall_sign.json new file mode 100644 index 00000000..b524b126 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/acacia_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/acacia_wall" + }, + "facing=west": { + "model": "sign/acacia_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/acacia_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/acacia_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_sign.json new file mode 100644 index 00000000..2ffe5fd5 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/birch" + }, + "rotation=1": { + "model": "sign/birch", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/birch", + "y": 45 + }, + "rotation=3": { + "model": "sign/birch", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/birch", + "y": 90 + }, + "rotation=5": { + "model": "sign/birch", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/birch", + "y": 135 + }, + "rotation=7": { + "model": "sign/birch", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/birch", + "y": 180 + }, + "rotation=9": { + "model": "sign/birch", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/birch", + "y": 225 + }, + "rotation=11": { + "model": "sign/birch", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/birch", + "y": 270 + }, + "rotation=13": { + "model": "sign/birch", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/birch", + "y": 315 + }, + "rotation=15": { + "model": "sign/birch", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_wall_sign.json new file mode 100644 index 00000000..622924b5 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/birch_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/birch_wall" + }, + "facing=west": { + "model": "sign/birch_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/birch_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/birch_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_sign.json new file mode 100644 index 00000000..6001019b --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/dark_oak" + }, + "rotation=1": { + "model": "sign/dark_oak", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/dark_oak", + "y": 45 + }, + "rotation=3": { + "model": "sign/dark_oak", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/dark_oak", + "y": 90 + }, + "rotation=5": { + "model": "sign/dark_oak", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/dark_oak", + "y": 135 + }, + "rotation=7": { + "model": "sign/dark_oak", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/dark_oak", + "y": 180 + }, + "rotation=9": { + "model": "sign/dark_oak", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/dark_oak", + "y": 225 + }, + "rotation=11": { + "model": "sign/dark_oak", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/dark_oak", + "y": 270 + }, + "rotation=13": { + "model": "sign/dark_oak", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/dark_oak", + "y": 315 + }, + "rotation=15": { + "model": "sign/dark_oak", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_wall_sign.json new file mode 100644 index 00000000..4b5cc921 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/dark_oak_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/dark_oak_wall" + }, + "facing=west": { + "model": "sign/dark_oak_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/dark_oak_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/dark_oak_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_sign.json new file mode 100644 index 00000000..983c2d68 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/jungle" + }, + "rotation=1": { + "model": "sign/jungle", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/jungle", + "y": 45 + }, + "rotation=3": { + "model": "sign/jungle", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/jungle", + "y": 90 + }, + "rotation=5": { + "model": "sign/jungle", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/jungle", + "y": 135 + }, + "rotation=7": { + "model": "sign/jungle", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/jungle", + "y": 180 + }, + "rotation=9": { + "model": "sign/jungle", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/jungle", + "y": 225 + }, + "rotation=11": { + "model": "sign/jungle", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/jungle", + "y": 270 + }, + "rotation=13": { + "model": "sign/jungle", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/jungle", + "y": 315 + }, + "rotation=15": { + "model": "sign/jungle", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_wall_sign.json new file mode 100644 index 00000000..898f7323 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/jungle_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/jungle_wall" + }, + "facing=west": { + "model": "sign/jungle_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/jungle_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/jungle_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_sign.json new file mode 100644 index 00000000..4ebcedcd --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/oak" + }, + "rotation=1": { + "model": "sign/oak", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/oak", + "y": 45 + }, + "rotation=3": { + "model": "sign/oak", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/oak", + "y": 90 + }, + "rotation=5": { + "model": "sign/oak", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/oak", + "y": 135 + }, + "rotation=7": { + "model": "sign/oak", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/oak", + "y": 180 + }, + "rotation=9": { + "model": "sign/oak", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/oak", + "y": 225 + }, + "rotation=11": { + "model": "sign/oak", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/oak", + "y": 270 + }, + "rotation=13": { + "model": "sign/oak", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/oak", + "y": 315 + }, + "rotation=15": { + "model": "sign/oak", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_wall_sign.json new file mode 100644 index 00000000..26453d53 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/oak_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/oak_wall" + }, + "facing=west": { + "model": "sign/oak_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/oak_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/oak_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_sign.json new file mode 100644 index 00000000..78722223 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/spruce" + }, + "rotation=1": { + "model": "sign/spruce", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/spruce", + "y": 45 + }, + "rotation=3": { + "model": "sign/spruce", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/spruce", + "y": 90 + }, + "rotation=5": { + "model": "sign/spruce", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/spruce", + "y": 135 + }, + "rotation=7": { + "model": "sign/spruce", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/spruce", + "y": 180 + }, + "rotation=9": { + "model": "sign/spruce", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/spruce", + "y": 225 + }, + "rotation=11": { + "model": "sign/spruce", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/spruce", + "y": 270 + }, + "rotation=13": { + "model": "sign/spruce", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/spruce", + "y": 315 + }, + "rotation=15": { + "model": "sign/spruce", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_wall_sign.json new file mode 100644 index 00000000..8366709a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.14/blockStates/sign/spruce_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/spruce_wall" + }, + "facing=west": { + "model": "sign/spruce_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/spruce_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/spruce_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson.json b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson.json new file mode 100644 index 00000000..201e42ad --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/crimson" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson_wall.json b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson_wall.json new file mode 100644 index 00000000..3faf8661 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/crimson_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/crimson" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped.json b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped.json new file mode 100644 index 00000000..6dd3269e --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/warped" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped_wall.json b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped_wall.json new file mode 100644 index 00000000..a046ec14 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockModels/sign/warped_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/warped" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_sign.json b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_sign.json new file mode 100644 index 00000000..5df00a29 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/crimson" + }, + "rotation=1": { + "model": "sign/crimson", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/crimson", + "y": 45 + }, + "rotation=3": { + "model": "sign/crimson", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/crimson", + "y": 90 + }, + "rotation=5": { + "model": "sign/crimson", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/crimson", + "y": 135 + }, + "rotation=7": { + "model": "sign/crimson", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/crimson", + "y": 180 + }, + "rotation=9": { + "model": "sign/crimson", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/crimson", + "y": 225 + }, + "rotation=11": { + "model": "sign/crimson", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/crimson", + "y": 270 + }, + "rotation=13": { + "model": "sign/crimson", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/crimson", + "y": 315 + }, + "rotation=15": { + "model": "sign/crimson", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_wall_sign.json new file mode 100644 index 00000000..149227b2 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/crimson_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/crimson_wall" + }, + "facing=west": { + "model": "sign/crimson_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/crimson_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/crimson_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_sign.json b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_sign.json new file mode 100644 index 00000000..4af216ca --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/warped" + }, + "rotation=1": { + "model": "sign/warped", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/warped", + "y": 45 + }, + "rotation=3": { + "model": "sign/warped", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/warped", + "y": 90 + }, + "rotation=5": { + "model": "sign/warped", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/warped", + "y": 135 + }, + "rotation=7": { + "model": "sign/warped", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/warped", + "y": 180 + }, + "rotation=9": { + "model": "sign/warped", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/warped", + "y": 225 + }, + "rotation=11": { + "model": "sign/warped", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/warped", + "y": 270 + }, + "rotation=13": { + "model": "sign/warped", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/warped", + "y": 315 + }, + "rotation=15": { + "model": "sign/warped", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_wall_sign.json new file mode 100644 index 00000000..b1d7f5e0 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.16/blockStates/sign/warped_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/warped_wall" + }, + "facing=west": { + "model": "sign/warped_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/warped_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/warped_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove.json b/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove.json new file mode 100644 index 00000000..bb82e85a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/mangrove" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove_wall.json b/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove_wall.json new file mode 100644 index 00000000..30e9bd55 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.19/blockModels/sign/mangrove_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/mangrove" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_sign.json b/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_sign.json new file mode 100644 index 00000000..54a92e7e --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/mangrove" + }, + "rotation=1": { + "model": "sign/mangrove", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/mangrove", + "y": 45 + }, + "rotation=3": { + "model": "sign/mangrove", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/mangrove", + "y": 90 + }, + "rotation=5": { + "model": "sign/mangrove", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/mangrove", + "y": 135 + }, + "rotation=7": { + "model": "sign/mangrove", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/mangrove", + "y": 180 + }, + "rotation=9": { + "model": "sign/mangrove", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/mangrove", + "y": 225 + }, + "rotation=11": { + "model": "sign/mangrove", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/mangrove", + "y": 270 + }, + "rotation=13": { + "model": "sign/mangrove", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/mangrove", + "y": 315 + }, + "rotation=15": { + "model": "sign/mangrove", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_wall_sign.json new file mode 100644 index 00000000..d00760e7 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.19/blockStates/sign/mangrove_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/mangrove_wall" + }, + "facing=west": { + "model": "sign/mangrove_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/mangrove_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/mangrove_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_hanging.json new file mode 100644 index 00000000..13702388 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/acacia" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_wall_hanging.json new file mode 100644 index 00000000..1e2a9d85 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/acacia_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/acacia" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo.json new file mode 100644 index 00000000..6c9fd930 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/bamboo" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_hanging.json new file mode 100644 index 00000000..c5302b1b --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/bamboo" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall.json new file mode 100644 index 00000000..bf726f10 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/bamboo" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall_hanging.json new file mode 100644 index 00000000..d3a46453 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/bamboo_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/bamboo" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_hanging.json new file mode 100644 index 00000000..71a4b708 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/birch" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_wall_hanging.json new file mode 100644 index 00000000..13b215a5 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/birch_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/birch" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry.json new file mode 100644 index 00000000..406c6318 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign", + "textures": { + "sign": "entity/signs/cherry" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_hanging.json new file mode 100644 index 00000000..6ff4c5b7 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/cherry" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall.json new file mode 100644 index 00000000..b3b07061 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall.json @@ -0,0 +1,6 @@ +{ + "parent": "sign/sign_wall", + "textures": { + "sign": "entity/signs/cherry" + } +} diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall_hanging.json new file mode 100644 index 00000000..aeef94bd --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/cherry_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/cherry" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_hanging.json new file mode 100644 index 00000000..a6c9286a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/crimson" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_wall_hanging.json new file mode 100644 index 00000000..20889940 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/crimson_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/crimson" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_hanging.json new file mode 100644 index 00000000..506c4440 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/dark_oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_wall_hanging.json new file mode 100644 index 00000000..21c1ebd5 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/dark_oak_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/dark_oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/hanging.json new file mode 100644 index 00000000..52d90ee3 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/hanging.json @@ -0,0 +1,115 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "texture_size": [ + 64, + 32 + ], + "textures": { + "wood": "entity/signs/hanging/oak" + }, + "elements": [ + { + "name": "Sign", + "from": [ + 1, + 0, + 7 + ], + "to": [ + 15, + 10, + 9 + ], + "faces": { + "north": { + "uv": [ + 4.5, + 7, + 8, + 12 + ], + "texture": "#wood" + }, + "east": { + "uv": [ + 4, + 7, + 4.5, + 12 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 0.5, + 7, + 4, + 12 + ], + "texture": "#wood" + }, + "west": { + "uv": [ + 0, + 7, + 0.5, + 12 + ], + "texture": "#wood" + }, + "up": { + "uv": [ + 4, + 6, + 0.5, + 7 + ], + "rotation": 180, + "texture": "#wood" + }, + "down": { + "uv": [ + 4, + 7, + 7.5, + 6 + ], + "texture": "#wood" + } + } + }, + { + "from": [ + 2, + 10, + 8 + ], + "to": [ + 14, + 16, + 8 + ], + "faces": { + "north": { + "uv": [ + 3.5, + 3, + 6.5, + 6 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 3.5, + 3, + 6.5, + 6 + ], + "texture": "#wood" + } + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_hanging.json new file mode 100644 index 00000000..db141f6d --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/jungle" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_wall_hanging.json new file mode 100644 index 00000000..aefe92f3 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/jungle_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/jungle" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_hanging.json new file mode 100644 index 00000000..e84c41f2 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/mangrove" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_wall_hanging.json new file mode 100644 index 00000000..e5feb72e --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/mangrove_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/mangrove" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_hanging.json new file mode 100644 index 00000000..7437c82f --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_wall_hanging.json new file mode 100644 index 00000000..3c8d9e5e --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/oak_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/oak" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_hanging.json new file mode 100644 index 00000000..3dee635d --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/spruce" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_wall_hanging.json new file mode 100644 index 00000000..71e66b9c --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/spruce_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/spruce" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/wall_hanging.json new file mode 100644 index 00000000..424ffe37 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/wall_hanging.json @@ -0,0 +1,347 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "ambientocclusion": false, + "texture_size": [ + 64, + 32 + ], + "textures": { + "wood": "entity/signs/hanging/oak" + }, + "elements": [ + { + "name": "Sign", + "from": [ + 1, + 0, + 7 + ], + "to": [ + 15, + 10, + 9 + ], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ] + }, + "faces": { + "north": { + "uv": [ + 4.5, + 7, + 8, + 12 + ], + "texture": "#wood" + }, + "east": { + "uv": [ + 4, + 7, + 4.5, + 12 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 0.5, + 7, + 4, + 12 + ], + "texture": "#wood" + }, + "west": { + "uv": [ + 0, + 7, + 0.5, + 12 + ], + "texture": "#wood" + }, + "up": { + "uv": [ + 4, + 6, + 0.5, + 7 + ], + "rotation": 180, + "texture": "#wood" + }, + "down": { + "uv": [ + 4, + 7, + 7.5, + 6 + ], + "texture": "#wood" + } + } + }, + { + "name": "Hanger", + "from": [ + 0, + 14, + 6 + ], + "to": [ + 16, + 16, + 10 + ], + "rotation": { + "angle": 0, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ] + }, + "faces": { + "north": { + "uv": [ + 6, + 2, + 10, + 3 + ], + "texture": "#wood" + }, + "east": { + "uv": [ + 0, + 2, + 1, + 3 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 1, + 2, + 5, + 3 + ], + "texture": "#wood" + }, + "west": { + "uv": [ + 0, + 2, + 1, + 3 + ], + "texture": "#wood" + }, + "up": { + "uv": [ + 1, + 0, + 5, + 2 + ], + "rotation": 180, + "texture": "#wood" + }, + "down": { + "uv": [ + 5, + 0, + 9, + 2 + ], + "texture": "#wood" + } + } + }, + { + "name": "ChainA1", + "from": [ + 4.8, + 10, + 10.5 + ], + "to": [ + 6.2, + 14, + 10.5 + ], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ], + "rescale": true + }, + "faces": { + "north": { + "uv": [ + 1.5, + 3, + 2.25, + 6 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 1.5, + 3, + 2.25, + 6 + ], + "texture": "#wood" + } + } + }, + { + "name": "ChainB2", + "from": [ + 10.5, + 10, + 4.8 + ], + "to": [ + 10.5, + 14, + 6.2 + ], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ], + "rescale": true + }, + "faces": { + "east": { + "uv": [ + 0, + 3, + 0.75, + 6 + ], + "texture": "#wood" + }, + "west": { + "uv": [ + 0, + 3, + 0.75, + 6 + ], + "texture": "#wood" + } + } + }, + { + "name": "ChainB1", + "from": [ + 9.8, + 10, + 5.5 + ], + "to": [ + 11.2, + 14, + 5.5 + ], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ], + "rescale": true + }, + "faces": { + "north": { + "uv": [ + 1.5, + 3, + 2.25, + 6 + ], + "texture": "#wood" + }, + "south": { + "uv": [ + 1.5, + 3, + 2.25, + 6 + ], + "texture": "#wood" + } + } + }, + { + "name": "ChainA2", + "from": [ + 5.5, + 10, + 9.8 + ], + "to": [ + 5.5, + 14, + 11.2 + ], + "shade": false, + "rotation": { + "angle": -45, + "axis": "y", + "origin": [ + 8, + 8, + 8 + ], + "rescale": true + }, + "faces": { + "east": { + "uv": [ + 0, + 3, + 0.75, + 6 + ], + "texture": "#wood" + }, + "west": { + "uv": [ + 0, + 3, + 0.75, + 6 + ], + "texture": "#wood" + } + } + } + ] +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_hanging.json new file mode 100644 index 00000000..015ba2c0 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/hanging", + "textures": { + "wood": "entity/signs/hanging/warped" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_wall_hanging.json b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_wall_hanging.json new file mode 100644 index 00000000..8870c317 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockModels/sign/warped_wall_hanging.json @@ -0,0 +1,7 @@ +{ + "credit": "Made with Blockbench by TyBraniff for Bluemaps support.", + "parent": "sign/wall_hanging", + "textures": { + "wood": "entity/signs/hanging/warped" + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_hanging_sign.json new file mode 100644 index 00000000..18a25013 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/acacia_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/acacia_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/acacia_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/acacia_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/acacia_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/acacia_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/acacia_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/acacia_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/acacia_hanging" + }, + "rotation=9": { + "model": "sign/acacia_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/acacia_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/acacia_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/acacia_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/acacia_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/acacia_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/acacia_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_wall_hanging_sign.json new file mode 100644 index 00000000..edbae40d --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/acacia_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/acacia_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/acacia_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/acacia_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/acacia_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_hanging_sign.json new file mode 100644 index 00000000..5ff1854b --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/bamboo_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/bamboo_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/bamboo_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/bamboo_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/bamboo_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/bamboo_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/bamboo_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/bamboo_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/bamboo_hanging" + }, + "rotation=9": { + "model": "sign/bamboo_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/bamboo_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/bamboo_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/bamboo_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/bamboo_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/bamboo_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/bamboo_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_sign.json new file mode 100644 index 00000000..1041460a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/bamboo" + }, + "rotation=1": { + "model": "sign/bamboo", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/bamboo", + "y": 45 + }, + "rotation=3": { + "model": "sign/bamboo", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/bamboo", + "y": 90 + }, + "rotation=5": { + "model": "sign/bamboo", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/bamboo", + "y": 135 + }, + "rotation=7": { + "model": "sign/bamboo", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/bamboo", + "y": 180 + }, + "rotation=9": { + "model": "sign/bamboo", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/bamboo", + "y": 225 + }, + "rotation=11": { + "model": "sign/bamboo", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/bamboo", + "y": 270 + }, + "rotation=13": { + "model": "sign/bamboo", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/bamboo", + "y": 315 + }, + "rotation=15": { + "model": "sign/bamboo", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_hanging_sign.json new file mode 100644 index 00000000..3bd24804 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/bamboo_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/bamboo_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/bamboo_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/bamboo_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_sign.json new file mode 100644 index 00000000..8b5ce481 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/bamboo_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/bamboo_wall" + }, + "facing=west": { + "model": "sign/bamboo_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/bamboo_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/bamboo_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_hanging_sign.json new file mode 100644 index 00000000..6052d4f7 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/birch_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/birch_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/birch_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/birch_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/birch_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/birch_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/birch_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/birch_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/birch_hanging" + }, + "rotation=9": { + "model": "sign/birch_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/birch_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/birch_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/birch_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/birch_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/birch_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/birch_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_wall_hanging_sign.json new file mode 100644 index 00000000..656e8093 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/birch_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/birch_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/birch_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/birch_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/birch_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_hanging_sign.json new file mode 100644 index 00000000..32ce33dc --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/cherry_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/cherry_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/cherry_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/cherry_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/cherry_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/cherry_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/cherry_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/cherry_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/cherry_hanging" + }, + "rotation=9": { + "model": "sign/cherry_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/cherry_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/cherry_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/cherry_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/cherry_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/cherry_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/cherry_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_sign.json new file mode 100644 index 00000000..4e562a26 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/cherry" + }, + "rotation=1": { + "model": "sign/cherry", + "y": 22.5 + }, + "rotation=2": { + "model": "sign/cherry", + "y": 45 + }, + "rotation=3": { + "model": "sign/cherry", + "y": 67.5 + }, + "rotation=4": { + "model": "sign/cherry", + "y": 90 + }, + "rotation=5": { + "model": "sign/cherry", + "y": 112.5 + }, + "rotation=6": { + "model": "sign/cherry", + "y": 135 + }, + "rotation=7": { + "model": "sign/cherry", + "y": 157.5 + }, + "rotation=8": { + "model": "sign/cherry", + "y": 180 + }, + "rotation=9": { + "model": "sign/cherry", + "y": 202.5 + }, + "rotation=10": { + "model": "sign/cherry", + "y": 225 + }, + "rotation=11": { + "model": "sign/cherry", + "y": 247.5 + }, + "rotation=12": { + "model": "sign/cherry", + "y": 270 + }, + "rotation=13": { + "model": "sign/cherry", + "y": 292.5 + }, + "rotation=14": { + "model": "sign/cherry", + "y": 315 + }, + "rotation=15": { + "model": "sign/cherry", + "y": 337.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_hanging_sign.json new file mode 100644 index 00000000..3e0a2d04 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/cherry_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/cherry_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/cherry_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/cherry_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_sign.json new file mode 100644 index 00000000..1b13342c --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/cherry_wall_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "sign/cherry_wall" + }, + "facing=west": { + "model": "sign/cherry_wall", + "y": 90 + }, + "facing=north": { + "model": "sign/cherry_wall", + "y": 180 + }, + "facing=east": { + "model": "sign/cherry_wall", + "y": 270 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_hanging_sign.json new file mode 100644 index 00000000..6e4131f2 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/crimson_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/crimson_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/crimson_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/crimson_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/crimson_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/crimson_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/crimson_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/crimson_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/crimson_hanging" + }, + "rotation=9": { + "model": "sign/crimson_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/crimson_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/crimson_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/crimson_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/crimson_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/crimson_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/crimson_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_wall_hanging_sign.json new file mode 100644 index 00000000..63c560ae --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/crimson_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/crimson_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/crimson_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/crimson_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/crimson_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_hanging_sign.json new file mode 100644 index 00000000..a2bc0458 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/dark_oak_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/dark_oak_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/dark_oak_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/dark_oak_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/dark_oak_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/dark_oak_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/dark_oak_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/dark_oak_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/dark_oak_hanging" + }, + "rotation=9": { + "model": "sign/dark_oak_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/dark_oak_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/dark_oak_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/dark_oak_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/dark_oak_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/dark_oak_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/dark_oak_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_wall_hanging_sign.json new file mode 100644 index 00000000..138154f9 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/dark_oak_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/dark_oak_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/dark_oak_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/dark_oak_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/dark_oak_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_hanging_sign.json new file mode 100644 index 00000000..9f1f9eeb --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/jungle_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/jungle_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/jungle_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/jungle_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/jungle_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/jungle_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/jungle_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/jungle_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/jungle_hanging" + }, + "rotation=9": { + "model": "sign/jungle_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/jungle_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/jungle_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/jungle_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/jungle_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/jungle_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/jungle_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_wall_hanging_sign.json new file mode 100644 index 00000000..3bdb8191 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/jungle_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/jungle_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/jungle_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/jungle_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/jungle_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_hanging_sign.json new file mode 100644 index 00000000..ff977160 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/mangrove_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/mangrove_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/mangrove_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/mangrove_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/mangrove_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/mangrove_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/mangrove_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/mangrove_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/mangrove_hanging" + }, + "rotation=9": { + "model": "sign/mangrove_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/mangrove_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/mangrove_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/mangrove_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/mangrove_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/mangrove_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/mangrove_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_wall_hanging_sign.json new file mode 100644 index 00000000..9d1d019a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/mangrove_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/mangrove_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/mangrove_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/mangrove_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/mangrove_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_hanging_sign.json new file mode 100644 index 00000000..01e66da8 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/oak_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/oak_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/oak_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/oak_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/oak_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/oak_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/oak_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/oak_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/oak_hanging" + }, + "rotation=9": { + "model": "sign/oak_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/oak_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/oak_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/oak_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/oak_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/oak_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/oak_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_wall_hanging_sign.json new file mode 100644 index 00000000..9af80947 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/oak_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/oak_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/oak_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/oak_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/oak_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_hanging_sign.json new file mode 100644 index 00000000..ee9509f6 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/spruce_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/spruce_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/spruce_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/spruce_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/spruce_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/spruce_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/spruce_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/spruce_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/spruce_hanging" + }, + "rotation=9": { + "model": "sign/spruce_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/spruce_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/spruce_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/spruce_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/spruce_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/spruce_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/spruce_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_wall_hanging_sign.json new file mode 100644 index 00000000..0b9ec25a --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/spruce_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/spruce_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/spruce_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/spruce_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/spruce_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_hanging_sign.json new file mode 100644 index 00000000..93764856 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_hanging_sign.json @@ -0,0 +1,67 @@ +{ + "variants": { + "rotation=0": { + "model": "sign/warped_hanging", + "y": 180 + }, + "rotation=1": { + "model": "sign/warped_hanging", + "y": 202.5 + }, + "rotation=2": { + "model": "sign/warped_hanging", + "y": 225 + }, + "rotation=3": { + "model": "sign/warped_hanging", + "y": 247.5 + }, + "rotation=4": { + "model": "sign/warped_hanging", + "y": 270 + }, + "rotation=5": { + "model": "sign/warped_hanging", + "y": 292.5 + }, + "rotation=6": { + "model": "sign/warped_hanging", + "y": 315 + }, + "rotation=7": { + "model": "sign/warped_hanging", + "y": 337.5 + }, + "rotation=8": { + "model": "sign/warped_hanging" + }, + "rotation=9": { + "model": "sign/warped_hanging", + "y": 22.5 + }, + "rotation=10": { + "model": "sign/warped_hanging", + "y": 45 + }, + "rotation=11": { + "model": "sign/warped_hanging", + "y": 67.5 + }, + "rotation=12": { + "model": "sign/warped_hanging", + "y": 90 + }, + "rotation=13": { + "model": "sign/warped_hanging", + "y": 112.5 + }, + "rotation=14": { + "model": "sign/warped_hanging", + "y": 135 + }, + "rotation=15": { + "model": "sign/warped_hanging", + "y": 157.5 + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_wall_hanging_sign.json b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_wall_hanging_sign.json new file mode 100644 index 00000000..378e80f8 --- /dev/null +++ b/prismarine-viewer/viewer/prepare/data/1.20/blockStates/sign/warped_wall_hanging_sign.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=east": { + "model": "sign/warped_wall_hanging", + "y": 90 + }, + "facing=south": { + "model": "sign/warped_wall_hanging", + "y": 180 + }, + "facing=west": { + "model": "sign/warped_wall_hanging", + "y": 270 + }, + "facing=north": { + "model": "sign/warped_wall_hanging" + } + } +} \ No newline at end of file diff --git a/prismarine-viewer/viewer/prepare/modelsBuilder.ts b/prismarine-viewer/viewer/prepare/modelsBuilder.ts index 2a0cac57..b6e5268f 100644 --- a/prismarine-viewer/viewer/prepare/modelsBuilder.ts +++ b/prismarine-viewer/viewer/prepare/modelsBuilder.ts @@ -161,7 +161,7 @@ function prepareModel (model: BlockModel, texturesJson) { const getFinalTexture = (originalBlockName) => { // texture name e.g. blocks/anvil_base - const cleanBlockName = cleanupBlockName(originalBlockName); + const cleanBlockName = cleanupBlockName(originalBlockName) return { ...texturesJson[cleanBlockName], /* __debugName: cleanBlockName */ } } @@ -187,10 +187,12 @@ function prepareModel (model: BlockModel, texturesJson) { for (const sideName of Object.keys(elem.faces)) { const face = elem.faces[sideName] + const textureRaw = face.texture.charAt(0) === '#' + ? finalTextures![face.texture.slice(1)] + : getFinalTexture(face.texture) + if (!textureRaw) throw new Error(`Texture ${face.texture} in ${JSON.stringify(model.textures)} not found`) const finalTexture = deepCopy( - face.texture.charAt(0) === '#' - ? finalTextures![face.texture.slice(1)] - : getFinalTexture(face.texture) + textureRaw ) const _from = elem.from diff --git a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts index b343e595..e64b7cff 100644 --- a/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts +++ b/prismarine-viewer/viewer/prepare/moreGeneratedBlocks.ts @@ -4,9 +4,10 @@ import { McAssets } from './modelsBuilder' import path from 'path' import fs from 'fs' import { fileURLToPath } from 'url' +import { versionToNumber } from './utils' // todo refactor -const twoTileTextures: string[] = [] +const handledBlocks = ['water', 'lava', 'barrier'] const origSizeTextures: string[] = [] let currentImage: Jimp let currentBlockName: string @@ -121,115 +122,6 @@ const handleShulkerBox = async (dataBase: string, match: RegExpExecArray) => { await addSimpleCubeWithSides(shulkerBoxTextures) } -const handleSign = async (dataBase: string, match: RegExpExecArray) => { - const states = getBlockStates(currentBlockName) - if (!states) return - - const [, signMaterial = ''] = match - currentImage = await Jimp.read(`${dataBase}entity/${signMaterial ? `signs/${signMaterial}` : 'sign'}.png`) - // todo cache - const signTextures = { - // todo correct mapping - // todo alg to fit to the side - signboard_side: justCrop(0, 2, 2, 12), - face: justCrop(2, 2, 24, 12), - up: justCrop(2, 0, 24, 2), - support: justCrop(0, 16, 2, 14) - } - const blockTextures = await getBlockTexturesFromJimp(signTextures, true) - - const isWall = currentBlockName.includes('wall_') - const isHanging = currentBlockName.includes('hanging_') - const rotationState = states.find(state => state.name === 'rotation') - const faceTexture = { texture: blockTextures.face.texture, uv: blockTextures.face.uv } - if (isWall || isHanging) { - // todo isHanging - if (!isHanging) { - const facingState = states.find(state => state.name === 'facing')! - const facingMap = { - south: 0, - west: 90, - north: 180, - east: 270 - } - - currentMcAssets.blocksStates[currentBlockName] = { - "variants": Object.fromEntries( - facingState.values!.map((_val, i) => { - const val = _val as string - return [`facing=${val}`, { - "model": currentBlockName, - y: facingMap[val], - }] - }) - ) - } - currentMcAssets.blocksModels[currentBlockName] = { - elements: [ - { - // signboard - "from": [0, 4.5, 0], - "to": [16, 11.5, 1.5], - faces: { - south: faceTexture, - east: blockTextures.signboard_side, - west: blockTextures.signboard_side, - up: blockTextures.up, - down: blockTextures.up, - }, - } - ], - } - } - } else if (rotationState) { - currentMcAssets.blocksStates[currentBlockName] = { - "variants": Object.fromEntries( - Array.from({ length: 16 }).map((_val, i) => { - return [`rotation=${i}`, { - "model": currentBlockName, - y: i * (45 / 2), - }] - }) - ) - } - - const supportTexture = blockTextures.support - // TODO fix models.ts, apply textures for signs correctly! - // const supportTexture = { texture: supportTextureImg, uv: [0, 0, 16, 16] } - currentMcAssets.blocksModels[currentBlockName] = { - elements: [ - { - // support post - "from": [7.5, 0, 7.5], - "to": [8.5, 9, 8.5], - faces: { - // todo 14 - north: supportTexture, - east: supportTexture, - south: supportTexture, - west: supportTexture, - } - }, - { - // signboard - "from": [0, 9, 7.25], - "to": [16, 16, 8.75], - faces: { - north: faceTexture, - south: faceTexture, - east: blockTextures.signboard_side, - west: blockTextures.signboard_side, - up: blockTextures.up, - down: blockTextures.up, - }, - } - ], - } - } - twoTileTextures.push(blockTextures.face.texture) - twoTileTextures.push(blockTextures.up.texture) -} - // TODO! should not be there! move to data with signs! const chestModels = { chest: { @@ -405,10 +297,10 @@ const handleChest = async (dataBase: string, match: RegExpExecArray) => { async function loadBlockModelTextures (dataBase: string, blockModel: any) { for (const key in blockModel.textures) { - const texture: string = blockModel.textures[key] - currentImage = await Jimp.read(dataBase + texture + '.png') + let texture: string = blockModel.textures[key] + const useAssetsPath = !!texture.match(/^[0-9.]+\//) blockModel.textures.particle = texture - generatedImageTextures[texture] = `data:image/png;base64,${fs.readFileSync(path.join(dataBase, texture + '.png'), 'base64')}` + generatedImageTextures[texture] = `data:image/png;base64,${fs.readFileSync(path.join(dataBase, useAssetsPath ? '..' : '', texture + '.png'), 'base64')}` origSizeTextures[texture] = true } } @@ -416,11 +308,6 @@ async function loadBlockModelTextures (dataBase: string, blockModel: any) { const handlers = [ [/(.+)_shulker_box$/, handleShulkerBox], [/^shulker_box$/, handleShulkerBox], - [/^sign$/, handleSign], - [/^standing_sign$/, handleSign], - [/^wall_sign$/, handleSign], - [/(.+)_wall_sign$/, handleSign], - [/(.+)_sign$/, handleSign], [/^(?:(ender|trapped)_)?chest$/, handleChest], // [/(^|(.+)_)bed$/, handleBed], // no-op just suppress warning @@ -439,25 +326,58 @@ export const tryHandleBlockEntity = async (dataBase, blockName) => { } } -const handleExternalData = async (dataBase: string, version: string) => { - const [major, minor] = version.split(".") - const dataVer = `${major}.${minor}` - const baseDir = path.join(__dirname, 'data', dataVer) - if (!fs.existsSync(baseDir)) return +async function readAllBlockStates (blockStatesDir: string) { + const files = fs.readdirSync(blockStatesDir) + for (const file of files) { + if (file.endsWith('.json')) { + const state = JSON.parse(fs.readFileSync(path.join(blockStatesDir, file), 'utf-8')) + const name = file.replace('.json', '') + currentMcAssets.blocksStates[name] = state + handledBlocks.push(name) + } else { + await readAllBlockStates(path.join(blockStatesDir, file)) + } + } +} - const blockModelsDir = path.join(baseDir, 'blockModels') - const allBlockModels = fs.readdirSync(blockModelsDir).map(x => x.replace('.json', '')) - for (const blockModel of allBlockModels) { - const model = JSON.parse(fs.readFileSync(path.join(blockModelsDir, blockModel + '.json'), 'utf-8')) - currentMcAssets.blocksModels[blockModel] = model - await loadBlockModelTextures(dataBase, model) +async function readAllBlockModels (dataBase: string, blockModelsDir: string, completePath: string) { + const actualPath = completePath.length ? completePath + "/" : "" + const files = fs.readdirSync(blockModelsDir) + for (const file of files) { + if (file.endsWith('.json')) { + const model = JSON.parse(fs.readFileSync(path.join(blockModelsDir, file), 'utf-8')) + const name = actualPath + file.replace('.json', '') + currentMcAssets.blocksModels[name] = model + await loadBlockModelTextures(dataBase, model) + } else { + await readAllBlockModels(dataBase, path.join(blockModelsDir, file), actualPath + file) + } + } +} + +const handleExternalData = async (assetsPathRoot: string, version: string) => { + const currentVersionNumber = versionToNumber(version) + const versions = fs.readdirSync(path.join(__dirname, 'data'), { withFileTypes: true }) + .filter(x => x.isDirectory()) + .map(x => x.name) + .sort((a, b) => versionToNumber(b) - versionToNumber(a)) + + const allAssetsVersions = fs.readdirSync(assetsPathRoot, { withFileTypes: true }) + .filter(x => x.isDirectory()) + .map(x => x.name) + .sort((a, b) => versionToNumber(b) - versionToNumber(a)) + + const getAssetsVersion = (version: string) => { + return allAssetsVersions[version] ?? allAssetsVersions.find(x => x.startsWith(version)) } - const blockStatesDir = path.join(baseDir, 'blockStates') - const allBlockStates = fs.readdirSync(blockStatesDir).map(x => x.replace('.json', '')) - for (const blockState of allBlockStates) { - const state = JSON.parse(fs.readFileSync(path.join(blockStatesDir, blockState + '.json'), 'utf-8')) - currentMcAssets.blocksStates[blockState] = state + for (const curVer of versions) { + const baseDir = path.join(__dirname, 'data', curVer) + if (versionToNumber(curVer) > currentVersionNumber) continue + + const assetsVersion = getAssetsVersion(curVer) + await readAllBlockStates(path.join(baseDir, 'blockStates')) + await readAllBlockModels(path.join(assetsPathRoot, assetsVersion), path.join(baseDir, 'blockModels'), "") } } @@ -466,7 +386,6 @@ export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { const allTheBlocks = mcData.blocksArray.map(x => x.name) currentMcAssets = mcAssets - const handledBlocks = ['water', 'lava', 'barrier'] // todo const ignoredBlocks = ['skull', 'structure_void', 'banner', 'bed', 'end_portal'] @@ -481,7 +400,7 @@ export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { } } - await handleExternalData(mcAssets.directory, mcAssets.version) + await handleExternalData(path.join(mcAssets.directory, '..'), mcAssets.version) const warnings: string[] = [] for (const [name, model] of Object.entries(mcAssets.blocksModels)) { @@ -498,5 +417,5 @@ export const prepareMoreGeneratedBlocks = async (mcAssets: McAssets) => { } export const getAdditionalTextures = () => { - return { generated: generatedImageTextures, twoTileTextures, origSizeTextures } + return { generated: generatedImageTextures, origSizeTextures } } From 2d4b89651cdd8ff4ad9268d51aeb1c90f01b8968 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Jun 2024 21:17:07 +0300 Subject: [PATCH 0146/1097] format, remove useless comment --- .../viewer/lib/worldrendererThree.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/prismarine-viewer/viewer/lib/worldrendererThree.ts b/prismarine-viewer/viewer/lib/worldrendererThree.ts index 095e5a94..9a76474b 100644 --- a/prismarine-viewer/viewer/lib/worldrendererThree.ts +++ b/prismarine-viewer/viewer/lib/worldrendererThree.ts @@ -22,7 +22,7 @@ export class WorldRendererThree extends WorldRendererCommon { return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).tilesCount, 0) } - constructor(public scene: THREE.Scene, public renderer: THREE.WebGLRenderer, public config: WorldRendererConfig) { + constructor (public scene: THREE.Scene, public renderer: THREE.WebGLRenderer, public config: WorldRendererConfig) { super(config) this.starField = new StarField(scene) } @@ -181,13 +181,12 @@ export class WorldRendererThree extends WorldRendererCommon { const mesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), new THREE.MeshBasicMaterial({ map: tex, transparent: true, })) mesh.renderOrder = 999 - // todo @sa2urami shouldnt all this be done in worker? - const lineHeight = 7 / 16; + const lineHeight = 7 / 16 const scaleFactor = isHanging ? 1.3 : 1 mesh.scale.set(1 * scaleFactor, lineHeight * scaleFactor, 1 * scaleFactor) const thickness = (isHanging ? 2 : 1.5) / 16 - const wallSpacing = 0.25 / 16; + const wallSpacing = 0.25 / 16 if (isWall && !isHanging) { mesh.position.set(0, 0, -0.5 + thickness + wallSpacing + 0.0001) } else { @@ -199,9 +198,9 @@ export class WorldRendererThree extends WorldRendererCommon { rotation * (isWall ? 90 : 45 / 2) ), 0) group.add(mesh) - const height = (isHanging ? 10 : 8)/16 + const height = (isHanging ? 10 : 8) / 16 const heightOffset = (isHanging ? 0 : isWall ? 4.333 : 9.333) / 16 - const textPosition = height/2 + heightOffset + const textPosition = height / 2 + heightOffset group.position.set(position.x + 0.5, position.y + textPosition, position.z + 0.5) return group } @@ -322,7 +321,7 @@ class StarField { } } - constructor(private scene: THREE.Scene) { + constructor (private scene: THREE.Scene) { } addToScene () { @@ -386,7 +385,7 @@ class StarField { const version = parseInt(THREE.REVISION.replace(/\D+/g, '')) class StarfieldMaterial extends THREE.ShaderMaterial { - constructor() { + constructor () { super({ uniforms: { time: { value: 0.0 }, fade: { value: 1.0 } }, vertexShader: /* glsl */ ` From 4f20e2481947d813317b3888e75e77b0b85f39dc Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 12 Jun 2024 21:14:48 +0300 Subject: [PATCH 0147/1097] up flying squid --- package.json | 2 +- pnpm-lock.yaml | 79 ++++++++++++++++++++++++-------------------------- 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 7bbde636..f5f55c7f 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "esbuild-plugin-polyfill-node": "^0.3.0", "express": "^4.18.2", "filesize": "^10.0.12", - "flying-squid": "npm:@zardoy/flying-squid@^0.0.24", + "flying-squid": "npm:@zardoy/flying-squid@^0.0.26", "fs-extra": "^11.1.1", "google-drive-browserfs": "github:zardoy/browserfs#google-drive", "iconify-icon": "^1.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 38a9ebb6..3cbab433 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,8 +104,8 @@ importers: specifier: ^10.0.12 version: 10.0.12 flying-squid: - specifier: npm:@zardoy/flying-squid@^0.0.24 - version: '@zardoy/flying-squid@0.0.24(encoding@0.1.13)' + specifier: npm:@zardoy/flying-squid@^0.0.26 + version: '@zardoy/flying-squid@0.0.26(encoding@0.1.13)' fs-extra: specifier: ^11.1.1 version: 11.1.1 @@ -386,7 +386,7 @@ importers: version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-chunk: specifier: github:zardoy/prismarine-chunk - version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) prismarine-schematic: specifier: ^1.2.0 version: 1.2.3 @@ -3054,8 +3054,8 @@ packages: resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==} engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'} - '@zardoy/flying-squid@0.0.24': - resolution: {integrity: sha512-C+VNHyh9yYB7aG9OL6r9NR5bF73fyRQ0rHhkvvz901hLBZI3+5nOPdcA6XwJm9XX9BYStXbLTHp6shmo20JRHQ==} + '@zardoy/flying-squid@0.0.26': + resolution: {integrity: sha512-JUGrr+9I4vgXrgjop5iRpulRhWUgRbPC1j+xPapgICtJPEGuekpXIOOBjAL+X7yu7I5IcrmtG4XCjvTKcC0lIQ==} engines: {node: '>=8'} hasBin: true @@ -6718,13 +6718,8 @@ packages: prismarine-chat@1.9.1: resolution: {integrity: sha512-x7WWa5MNhiLZSO6tw+YyKpzquFZ+DNISVgiV6K3SU0GsishMXe+nto02WhF/4AuFerKdugm9u1d/r4C4zSkJOg==} - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16} - version: 1.35.0 - engines: {node: '>=14'} - - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a} version: 1.35.0 engines: {node: '>=14'} @@ -6747,6 +6742,10 @@ packages: resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29} version: 2.7.0 + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20} + version: 2.8.0 + prismarine-realms@1.3.2: resolution: {integrity: sha512-5apl9Ru8veTj5q2OozRc4GZOuSIcs3yY4UEtALiLKHstBe8bRw8vNlaz4Zla3jsQ8yP/ul1b1IJINTRbocuA6g==} @@ -6764,9 +6763,9 @@ packages: prismarine-windows@2.9.0: resolution: {integrity: sha512-fm4kOLjGFPov7TEJRmXHoiPabxIQrG36r2mDjlNxfkcLfMHFb3/1ML6mp4iRQa7wL0GK4DIAyiBqCWoeWDxARg==} - prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465} - version: 3.6.2 + prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7} + version: 3.6.3 engines: {node: '>=8.0.0'} process-nextick-args@2.0.1: @@ -11931,7 +11930,7 @@ snapshots: '@types/emscripten': 1.39.8 tslib: 1.14.1 - '@zardoy/flying-squid@0.0.24(encoding@0.1.13)': + '@zardoy/flying-squid@0.0.26(encoding@0.1.13)': dependencies: '@tootallnate/once': 2.0.0 change-case: 4.1.2 @@ -11946,13 +11945,13 @@ snapshots: mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 - prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0) + prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20(minecraft-data@3.65.0) prismarine-windows: 2.9.0 - prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 rambda: 9.2.0 random-seed: 0.3.0 range: 0.0.3 @@ -13212,7 +13211,7 @@ snapshots: diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687: dependencies: minecraft-data: 3.65.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) random-seed: 0.3.0 vec3: 0.1.8 @@ -15779,7 +15778,7 @@ snapshots: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-chat: 1.10.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -15787,7 +15786,7 @@ snapshots: prismarine-recipe: 1.3.1(prismarine-registry@1.7.0) prismarine-registry: 1.7.0 prismarine-windows: 2.9.0 - prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 protodef: 1.15.0 typed-emitter: 1.4.0 vec3: 0.1.8 @@ -15802,7 +15801,7 @@ snapshots: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-chat: 1.10.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -15810,7 +15809,7 @@ snapshots: prismarine-recipe: 1.3.1(prismarine-registry@1.7.0) prismarine-registry: 1.7.0 prismarine-windows: 2.9.0 - prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 protodef: 1.15.0 typed-emitter: 1.4.0 vec3: 0.1.8 @@ -16526,20 +16525,7 @@ snapshots: prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/eb39a905761a36f733a456110e6b49d655bf5c16(minecraft-data@3.65.0): - dependencies: - prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 - prismarine-nbt: 2.5.0 - prismarine-registry: 1.7.0 - smart-buffer: 4.2.0 - uint4: 0.1.2 - vec3: 0.1.8 - xxhash-wasm: 0.4.2 - transitivePeerDependencies: - - minecraft-data - - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0): + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 @@ -16580,13 +16566,24 @@ snapshots: prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0): dependencies: - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/f32234a724a5c2482ffbaf85edc5e91c7ab9b38f(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) prismarine-nbt: 2.5.0 uint4: 0.1.2 vec3: 0.1.8 transitivePeerDependencies: - minecraft-data + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20(minecraft-data@3.65.0): + dependencies: + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-nbt: 2.5.0 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 + uint4: 0.1.2 + vec3: 0.1.8 + transitivePeerDependencies: + - minecraft-data + prismarine-realms@1.3.2(encoding@0.1.13): dependencies: debug: 4.3.4(supports-color@8.1.1) @@ -16609,7 +16606,7 @@ snapshots: minecraft-data: 3.65.0 prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 prismarine-nbt: 2.2.1 - prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465 + prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 vec3: 0.1.8 prismarine-windows@2.9.0: @@ -16618,7 +16615,7 @@ snapshots: prismarine-registry: 1.7.0 typed-emitter: 2.1.0 - prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/6ae6f009d38460de284f8c226c665f04cbad9465: + prismarine-world@https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7: dependencies: vec3: 0.1.8 From 5be093a25f88dae99d216416b6f4cd64bc06ecd2 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 13 Jun 2024 03:46:59 +0300 Subject: [PATCH 0148/1097] feat: support world saves for all versions of Minecraft Java! --- package.json | 2 +- pnpm-lock.yaml | 100 +++++++----------- .../viewer/lib/worldDataEmitter.ts | 2 +- src/createLocalServer.ts | 2 +- src/getCollisionShapes.ts | 6 +- src/globals.d.ts | 4 +- src/loadSave.ts | 10 +- src/react/MainMenu.tsx | 2 +- src/soundSystem.ts | 10 +- src/water.ts | 2 +- 10 files changed, 61 insertions(+), 79 deletions(-) diff --git a/package.json b/package.json index f5f55c7f..37e24dbb 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "esbuild-plugin-polyfill-node": "^0.3.0", "express": "^4.18.2", "filesize": "^10.0.12", - "flying-squid": "npm:@zardoy/flying-squid@^0.0.26", + "flying-squid": "npm:@zardoy/flying-squid@^0.0.27", "fs-extra": "^11.1.1", "google-drive-browserfs": "github:zardoy/browserfs#google-drive", "iconify-icon": "^1.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3cbab433..052069c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,8 +104,8 @@ importers: specifier: ^10.0.12 version: 10.0.12 flying-squid: - specifier: npm:@zardoy/flying-squid@^0.0.26 - version: '@zardoy/flying-squid@0.0.26(encoding@0.1.13)' + specifier: npm:@zardoy/flying-squid@^0.0.27 + version: '@zardoy/flying-squid@0.0.27(encoding@0.1.13)' fs-extra: specifier: ^11.1.1 version: 11.1.1 @@ -150,7 +150,7 @@ importers: version: 6.1.1 prismarine-provider-anvil: specifier: github:zardoy/prismarine-provider-anvil#everything - version: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0) + version: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/2663cad29c8f231c299f63e31c5040b6c1872bcc(minecraft-data@3.65.0) prosemirror-example-setup: specifier: ^1.2.2 version: 1.2.2 @@ -302,7 +302,7 @@ importers: version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/200902aca941475e7feb610070e662b172a000b5(@types/react@18.2.20)(react@18.2.0) mineflayer: specifier: github:zardoy/mineflayer - version: https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192(encoding@0.1.13) + version: https://codeload.github.com/zardoy/mineflayer/tar.gz/f80ba0f8ebbcc15d6c44ade84007f8b4a0ee08ec(encoding@0.1.13) mineflayer-pathfinder: specifier: ^2.4.4 version: 2.4.4 @@ -383,10 +383,10 @@ importers: version: 1.3.6 prismarine-block: specifier: github:zardoy/prismarine-block#next-era - version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + version: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-chunk: specifier: github:zardoy/prismarine-chunk - version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + version: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-schematic: specifier: ^1.2.0 version: 1.2.3 @@ -3054,8 +3054,8 @@ packages: resolution: {integrity: sha512-6xm38yGVIa6mKm/DUCF2zFFJhERh/QWp1ufm4cNUvxsONBmfPg8uZ9pZBdOmF6qFGr/HlT6ABBkCSx/dlEtvWg==} engines: {node: '>=12 <14 || 14.2 - 14.9 || >14.10.0'} - '@zardoy/flying-squid@0.0.26': - resolution: {integrity: sha512-JUGrr+9I4vgXrgjop5iRpulRhWUgRbPC1j+xPapgICtJPEGuekpXIOOBjAL+X7yu7I5IcrmtG4XCjvTKcC0lIQ==} + '@zardoy/flying-squid@0.0.27': + resolution: {integrity: sha512-8QlPCyLqNQYxsGBMBNNGbfc1HdRPO/t3nBr5NzINEridj772DEbgGHxl252rjZWWELt/3t/k3m6e4k9qS7/ZdA==} engines: {node: '>=8'} hasBin: true @@ -4097,8 +4097,8 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687: - resolution: {tarball: https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687} + diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015: + resolution: {tarball: https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015} version: 1.3.0 diff-sequences@29.6.3: @@ -6067,8 +6067,8 @@ packages: resolution: {integrity: sha512-QMMNPx4IyZE7ydAzjvGLQLCnQNUOfkk1qVZKxTTS9q3qPTAewz4GhsVUBtbQ8LSbHthe5RcQ1Sgxs4wlIma/Qw==} engines: {node: '>=18'} - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192: - resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192} + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/f80ba0f8ebbcc15d6c44ade84007f8b4a0ee08ec: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/f80ba0f8ebbcc15d6c44ade84007f8b4a0ee08ec} version: 4.20.1 engines: {node: '>=18'} @@ -6708,18 +6708,15 @@ packages: minecraft-data: 3.65.0 prismarine-registry: ^1.1.0 - prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0} + prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8} version: 1.17.1 prismarine-chat@1.10.1: resolution: {integrity: sha512-XukYcuueuhDxzEXG7r8BZyt6jOObrPPB4JESCgb+/XenB9nExoSHF8eTQWWj8faKPLqm1dRQaYwFJlNBlJZJUw==} - prismarine-chat@1.9.1: - resolution: {integrity: sha512-x7WWa5MNhiLZSO6tw+YyKpzquFZ+DNISVgiV6K3SU0GsishMXe+nto02WhF/4AuFerKdugm9u1d/r4C4zSkJOg==} - - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a} + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3} version: 1.35.0 engines: {node: '>=14'} @@ -6738,12 +6735,8 @@ packages: prismarine-physics@1.8.0: resolution: {integrity: sha512-gbM+S+bmVtOKVv+Z0WGaHMeEeBHISIDsRDRlv8sr0dex3ZJRhuq8djA02CBreguXtI18ZKh6q3TSj2qDr45NHA==} - prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29} - version: 2.7.0 - - prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20: - resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20} + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/2663cad29c8f231c299f63e31c5040b6c1872bcc: + resolution: {tarball: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/2663cad29c8f231c299f63e31c5040b6c1872bcc} version: 2.8.0 prismarine-realms@1.3.2: @@ -11930,12 +11923,12 @@ snapshots: '@types/emscripten': 1.39.8 tslib: 1.14.1 - '@zardoy/flying-squid@0.0.26(encoding@0.1.13)': + '@zardoy/flying-squid@0.0.27(encoding@0.1.13)': dependencies: '@tootallnate/once': 2.0.0 change-case: 4.1.2 colors: 1.4.0 - diamond-square: https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687 + diamond-square: https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015 emit-then: 2.0.0 exit-hook: 2.2.1 flatmap: 0.0.3 @@ -11945,11 +11938,11 @@ snapshots: mkdirp: 2.1.6 node-gzip: 1.1.2 node-rsa: 1.1.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 - prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20(minecraft-data@3.65.0) + prismarine-provider-anvil: https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/2663cad29c8f231c299f63e31c5040b6c1872bcc(minecraft-data@3.65.0) prismarine-windows: 2.9.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 rambda: 9.2.0 @@ -13208,10 +13201,11 @@ snapshots: dependencies: dequal: 2.0.3 - diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687: + diamond-square@https://codeload.github.com/zardoy/diamond-square/tar.gz/4bbe28dcad35403abaa925055e91f601a61b9015: dependencies: minecraft-data: 3.65.0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) + prismarine-registry: 1.7.0 random-seed: 0.3.0 vec3: 0.1.8 @@ -15764,7 +15758,7 @@ snapshots: mineflayer-pathfinder@2.4.4: dependencies: minecraft-data: 3.65.0 - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.2.1 @@ -15776,9 +15770,9 @@ snapshots: minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-chat: 1.10.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -15794,14 +15788,14 @@ snapshots: - encoding - supports-color - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/06061e07fe6b9716cb1801d4c1bf232581977192(encoding@0.1.13): + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/f80ba0f8ebbcc15d6c44ade84007f8b4a0ee08ec(encoding@0.1.13): dependencies: minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=2uxevyasyasdavsxuehfavgkjq)(encoding@0.1.13) prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-chat: 1.10.1 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-entity: 2.3.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 @@ -16503,11 +16497,11 @@ snapshots: minecraft-data: 3.65.0 prismarine-registry: 1.7.0 - prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0: + prismarine-block@https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8: dependencies: minecraft-data: 3.65.0 prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-chat: 1.9.1 + prismarine-chat: 1.10.1 prismarine-item: 1.14.0 prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 @@ -16518,17 +16512,10 @@ snapshots: prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 - prismarine-chat@1.9.1: - dependencies: - mojangson: 2.0.4 - prismarine-item: 1.14.0 - prismarine-nbt: 2.5.0 - prismarine-registry: 1.7.0 - - prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0): + prismarine-chunk@https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0): dependencies: prismarine-biome: 1.3.0(minecraft-data@3.65.0)(prismarine-registry@1.7.0) - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-nbt: 2.5.0 prismarine-registry: 1.7.0 smart-buffer: 4.2.0 @@ -16564,19 +16551,10 @@ snapshots: prismarine-nbt: 2.5.0 vec3: 0.1.8 - prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/02d81b0eba6ab1c362862970954f9a3c150c9a29(minecraft-data@3.65.0): + prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/2663cad29c8f231c299f63e31c5040b6c1872bcc(minecraft-data@3.65.0): dependencies: - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) - prismarine-nbt: 2.5.0 - uint4: 0.1.2 - vec3: 0.1.8 - transitivePeerDependencies: - - minecraft-data - - prismarine-provider-anvil@https://codeload.github.com/zardoy/prismarine-provider-anvil/tar.gz/422aed5db94f341c3807f1a918c7b83c9ebcfe20(minecraft-data@3.65.0): - dependencies: - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 - prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/45f0da31a6ab7107204f2b0a5d56dccb6059025a(minecraft-data@3.65.0) + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 + prismarine-chunk: https://codeload.github.com/zardoy/prismarine-chunk/tar.gz/9662306deea57d8d0ba0a2a3f3f7adb95f0131e3(minecraft-data@3.65.0) prismarine-nbt: 2.5.0 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 uint4: 0.1.2 @@ -16604,7 +16582,7 @@ snapshots: prismarine-schematic@1.2.3: dependencies: minecraft-data: 3.65.0 - prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/ada4ec3fdfbbc1cc20ab01d0e23f0718a77cc1a0 + prismarine-block: https://codeload.github.com/zardoy/prismarine-block/tar.gz/dd4954fff3b334f8ce063d18e39b2e9414ece5b8 prismarine-nbt: 2.2.1 prismarine-world: https://codeload.github.com/zardoy/prismarine-world/tar.gz/187a87f6d71cba12881a7bbaa510ed9085bf6da7 vec3: 0.1.8 diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index 3a8fbd40..ed578040 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -83,7 +83,7 @@ export class WorldDataEmitter extends EventEmitter { get (_target, posKey, receiver) { if (typeof posKey !== 'string') return const [x, y, z] = posKey.split(',').map(Number) - return bot.world.getBlock(new Vec3(x, y, z)).entity + return bot.world.getBlock(new Vec3(x, y, z))?.entity }, })) this.emitter.emit('renderDistance', this.viewDistance) diff --git a/src/createLocalServer.ts b/src/createLocalServer.ts index 44bc2187..d0beac9a 100644 --- a/src/createLocalServer.ts +++ b/src/createLocalServer.ts @@ -14,4 +14,4 @@ export const startLocalServer = (serverOptions) => { // features that flying-squid doesn't support at all // todo move & generate in flying-squid -export const unsupportedLocalServerFeatures = ['transactionPacketExists', 'teleportUsesOwnPacket', 'dimensionDataIsAvailable'] +export const unsupportedLocalServerFeatures = ['transactionPacketExists', 'teleportUsesOwnPacket'] diff --git a/src/getCollisionShapes.ts b/src/getCollisionShapes.ts index 0faf5b6a..4ee0e802 100644 --- a/src/getCollisionShapes.ts +++ b/src/getCollisionShapes.ts @@ -1,4 +1,4 @@ -import { adoptBlockOrItemNamesFromLatest } from 'flying-squid/dist/blockRenames' +import { getRenamedData } from 'flying-squid/dist/blockRenames' import collisionShapesInit from '../generated/latestBlockCollisionsShapes.json' import outputInteractionShapesJson from './interactionShapesGenerated.json' @@ -6,7 +6,7 @@ import outputInteractionShapesJson from './interactionShapesGenerated.json' window.globalGetCollisionShapes = (version) => { // todo use the same in resourcepack const versionFrom = collisionShapesInit.version - const renamedBlocks = adoptBlockOrItemNamesFromLatest('blocks', Object.keys(collisionShapesInit.blocks), versionFrom, version) + const renamedBlocks = getRenamedData('blocks', Object.keys(collisionShapesInit.blocks), versionFrom, version) const collisionShapes = { ...collisionShapesInit, blocks: Object.fromEntries(Object.entries(collisionShapesInit.blocks).map(([, shape], i) => [renamedBlocks[i], shape])) @@ -17,7 +17,7 @@ window.globalGetCollisionShapes = (version) => { export default () => { customEvents.on('gameLoaded', () => { // todo also remap block states (e.g. redstone)! - const renamedBlocksInteraction = adoptBlockOrItemNamesFromLatest('blocks', Object.keys(outputInteractionShapesJson), '1.20.2', bot.version) + const renamedBlocksInteraction = getRenamedData('blocks', Object.keys(outputInteractionShapesJson), '1.20.2', bot.version) const interactionShapes = { ...outputInteractionShapesJson, ...Object.fromEntries(Object.entries(outputInteractionShapesJson).map(([block, shape], i) => [renamedBlocksInteraction[i], shape])) diff --git a/src/globals.d.ts b/src/globals.d.ts index 6a38a21d..05b29a14 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -3,7 +3,9 @@ declare const THREE: typeof import('three') // todo make optional declare const bot: Omit & { - world: import('prismarine-world').world.WorldSync + world: Omit & { + getBlock: (pos: import('vec3').Vec3) => import('prismarine-block').Block | null + } _client: Omit & { write: typeof import('./generatedClientPackets').clientWrite on: typeof import('./generatedServerPackets').clientOn diff --git a/src/loadSave.ts b/src/loadSave.ts index af9d078c..7ca454ff 100644 --- a/src/loadSave.ts +++ b/src/loadSave.ts @@ -1,15 +1,16 @@ import fs from 'fs' import path from 'path' -import { supportedVersions } from 'flying-squid/dist/lib/version' import * as nbt from 'prismarine-nbt' import { proxy } from 'valtio' import { gzip } from 'node-gzip' +import { versionToNumber } from 'prismarine-viewer/viewer/prepare/utils' import { options } from './optionsStorage' import { nameToMcOfflineUUID, disconnect } from './flyingSquidUtils' import { existsViaStats, forceCachedDataPaths, forceRedirectPaths, mkdirRecursive } from './browserfs' import { isMajorVersionGreater } from './utils' import { activeModalStacks, insertActiveModalStack, miscUiState } from './globalState' +import supportedVersions from './supportedVersions.mjs' // todo include name of opened handle (zip)! // additional fs metadata @@ -91,13 +92,12 @@ export const loadSave = async (root = '/world') => { const newVersion = '1.8.8' version = newVersion } - // const lastSupportedVersion = supportedVersions.at(-1)! - const lastTestedVersion = '1.18.2' + const lastSupportedVersion = supportedVersions.at(-1)! const firstSupportedVersion = supportedVersions[0] const lowerBound = isMajorVersionGreater(firstSupportedVersion, version) - const upperBound = isMajorVersionGreater(version, lastTestedVersion) + const upperBound = versionToNumber(version) > versionToNumber(lastSupportedVersion) if (lowerBound || upperBound) { - version = prompt(`Version ${version} is not supported, supported versions are ${supportedVersions.join(', ')}, what try to use instead?`, lowerBound ? firstSupportedVersion : lastTestedVersion) + version = prompt(`Version ${version} is not supported, supported versions are ${supportedVersions.join(', ')}, what try to use instead?`, lowerBound ? firstSupportedVersion : lastSupportedVersion) if (!version) return } if (levelDat.WorldGenSettings) { diff --git a/src/react/MainMenu.tsx b/src/react/MainMenu.tsx index 3e3170f4..43908645 100644 --- a/src/react/MainMenu.tsx +++ b/src/react/MainMenu.tsx @@ -103,7 +103,7 @@ export default ({ connectToServerAction, mapsProvider, singleplayerAction, optio icon='pixelarticons:folder' onClick={openFileAction} initialTooltip={{ - content: 'Load any 1.8-1.16 Java world' + (haveDirectoryPicker() ? '' : ' (zip)'), + content: 'Load any Java world save' + (haveDirectoryPicker() ? '' : ' (zip)!'), placement: 'bottom-start', }} /> diff --git a/src/soundSystem.ts b/src/soundSystem.ts index a2cc1f70..e7fdaee7 100644 --- a/src/soundSystem.ts +++ b/src/soundSystem.ts @@ -144,10 +144,12 @@ subscribeKey(miscUiState, 'gameLoaded', async () => { // movement happening if (Date.now() - lastStepSound > 300) { const blockUnder = bot.world.getBlock(bot.entity.position.offset(0, -1, 0)) - const stepSound = getStepSound(blockUnder) - if (stepSound) { - await playHardcodedSound(stepSound, undefined, 0.6)// todo not sure why 0.6 - lastStepSound = Date.now() + if (blockUnder) { + const stepSound = getStepSound(blockUnder) + if (stepSound) { + await playHardcodedSound(stepSound, undefined, 0.6)// todo not sure why 0.6 + lastStepSound = Date.now() + } } } } diff --git a/src/water.ts b/src/water.ts index 9f8ec557..d8b4b41c 100644 --- a/src/water.ts +++ b/src/water.ts @@ -19,7 +19,7 @@ customEvents.on('gameLoaded', () => { } bot.on('physicsTick', () => { // todo - const _inWater = bot.world.getBlock(bot.entity.position.offset(0, 1, 0)).name === 'water' + const _inWater = bot.world.getBlock(bot.entity.position.offset(0, 1, 0))?.name === 'water' if (_inWater !== inWater) { inWater = _inWater updateInWater() From 216b1712c2dd418636d9fcc9c6e632137555e2d9 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 13 Jun 2024 19:47:48 +0300 Subject: [PATCH 0149/1097] more basic tests. test joining to a local java vanilla server, movement! --- .eslintrc.json | 17 +++++++++ .gitignore | 1 + cypress/e2e/index.spec.ts | 57 ++++++++++++++++++++++++++++- cypress/e2e/shared.ts | 3 ++ cypress/plugins/index.js | 9 ++++- cypress/plugins/server.properties | 61 +++++++++++++++++++++++++++++++ cypress/plugins/startServer.ts | 45 +++++++++++++++++++++++ index.html | 2 +- src/index.ts | 7 +++- src/react/Chat.tsx | 3 +- src/worldInteractions.ts | 3 +- 11 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 cypress/plugins/server.properties create mode 100644 cypress/plugins/startServer.ts diff --git a/.eslintrc.json b/.eslintrc.json index 98388260..a91015d2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -96,5 +96,22 @@ "unicorn/filename-case": "off", "max-depth": "off" }, + "overrides": [ + { + "files": [ + "*.js" + ], + "rules": { + "space-before-function-paren": [ + "error", + { + "anonymous": "always", + "named": "never", + "asyncArrow": "always" + } + ] + } + } + ], "root": true } diff --git a/.gitignore b/.gitignore index 240b751a..3a188862 100644 --- a/.gitignore +++ b/.gitignore @@ -17,5 +17,6 @@ out .vercel generated storybook-static +server-jar src/react/npmReactComponents.ts diff --git a/cypress/e2e/index.spec.ts b/cypress/e2e/index.spec.ts index 05b50211..ec7d84e7 100644 --- a/cypress/e2e/index.spec.ts +++ b/cypress/e2e/index.spec.ts @@ -1,4 +1,6 @@ +/* eslint-disable max-nested-callbacks */ /// +import supportedVersions from '../../src/supportedVersions.mjs' import { setOptions, cleanVisit, visit } from './shared' // todo use ssl @@ -12,7 +14,7 @@ const compareRenderedFlatWorld = () => { } const testWorldLoad = () => { - cy.document().then({ timeout: 20_000 }, doc => { + return cy.document().then({ timeout: 20_000 }, doc => { return new Cypress.Promise(resolve => { doc.addEventListener('cypress-world-ready', resolve) }) @@ -36,7 +38,7 @@ it('Loads & renders singleplayer', () => { testWorldLoad() }) -it('Joins to server', () => { +it('Joins to local flying-squid server', () => { visit('/?ip=localhost&version=1.16.1') window.localStorage.version = '' // todo replace with data-test @@ -47,9 +49,60 @@ it('Joins to server', () => { testWorldLoad() }) +it('Joins to local latest Java vanilla server', () => { + const version = supportedVersions.at(-1)! + cy.task('startServer', [version, 25_590]).then(() => { + visit('/?ip=localhost:25590&username=bot') + cy.get('[data-test-id="connect-qs"]').click() + testWorldLoad().then(() => { + let x = 0 + let z = 0 + cy.window().then((win) => { + x = win.bot.entity.position.x + z = win.bot.entity.position.z + }) + cy.document().trigger('keydown', { code: 'KeyW' }) + cy.wait(1500).then(() => { + cy.document().trigger('keyup', { code: 'KeyW' }) + cy.window().then(async (win) => { + // eslint-disable-next-line prefer-destructuring + const bot: typeof __type_bot = win.bot + // todo use f3 stats instead + if (bot.entity.position.x === x && bot.entity.position.z === z) { + throw new Error('Player not moved') + } + + bot.chat('Hello') // todo assert + bot.chat('/gamemode creative') + // bot.on('message', () => { + void bot.creative.setInventorySlot(bot.inventory.hotbarStart, new win.PrismarineItem(1, 1, 0)) + // }) + await bot.lookAt(bot.entity.position.offset(1, 0, 1)) + }).then(() => { + cy.document().trigger('mousedown', { button: 2, isTrusted: true, force: true }) // right click + cy.document().trigger('mouseup', { button: 2, isTrusted: true, force: true }) + cy.wait(1000) + }) + }) + }) + }) +}) + it('Loads & renders zip world', () => { cleanVisit() cy.get('[data-test-id="select-file-folder"]').click({ shiftKey: true }) cy.get('input[type="file"]').selectFile('cypress/superflat.zip', { force: true }) testWorldLoad() }) + + +it.skip('Loads & renders world from folder', () => { + cleanVisit() + // dragndrop folder + cy.get('[data-test-id="select-file-folder"]').click() + cy.get('input[type="file"]').selectFile('server-jar/world', { + force: true, + // action: 'drag-drop', + }) + testWorldLoad() +}) diff --git a/cypress/e2e/shared.ts b/cypress/e2e/shared.ts index 9292a8d5..47518f1b 100644 --- a/cypress/e2e/shared.ts +++ b/cypress/e2e/shared.ts @@ -3,6 +3,9 @@ import { AppOptions } from '../../src/optionsStorage' export const cleanVisit = (url?) => { cy.clearLocalStorage() visit(url) + window.localStorage.options = { + chatOpacity: 0 + } } export const visit = (url = '/') => { window.localStorage.cypress = 'true' diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js index 35dc2989..e55f5d26 100644 --- a/cypress/plugins/index.js +++ b/cypress/plugins/index.js @@ -2,11 +2,13 @@ const { cypressEsbuildPreprocessor } = require('cypress-esbuild-preprocessor') const { initPlugin } = require('cypress-plugin-snapshots/plugin') const polyfill = require('esbuild-plugin-polyfill-node') +const { startMinecraftServer } = require('./startServer') module.exports = (on, config) => { initPlugin(on, config) on('file:preprocessor', cypressEsbuildPreprocessor({ esbuildOptions: { + sourcemap: true, plugins: [ polyfill.polyfillNode({ polyfills: { @@ -17,10 +19,15 @@ module.exports = (on, config) => { }, })) on('task', { - log (message) { + log(message) { console.log(message) return null }, }) + on('task', { + async startServer([version, port]) { + return startMinecraftServer(version, port) + } + }) return config } diff --git a/cypress/plugins/server.properties b/cypress/plugins/server.properties new file mode 100644 index 00000000..5873a1aa --- /dev/null +++ b/cypress/plugins/server.properties @@ -0,0 +1,61 @@ +#Minecraft server properties +allow-flight=false +allow-nether=true +broadcast-console-to-ops=true +broadcast-rcon-to-ops=true +difficulty=peaceful +enable-command-block=false +enable-jmx-monitoring=false +enable-query=false +enable-rcon=false +enable-status=true +enforce-secure-profile=true +enforce-whitelist=false +entity-broadcast-range-percentage=100 +force-gamemode=false +function-permission-level=2 +gamemode=survival +generate-structures=true +generator-settings={} +hardcore=false +hide-online-players=false +initial-disabled-packs= +initial-enabled-packs=vanilla +level-name=world +level-seed= +level-type=flat +log-ips=true +max-build-height=256 +max-chained-neighbor-updates=1000000 +max-players=20 +max-tick-time=60000 +max-world-size=29999984 +motd=A Minecraft Server +network-compression-threshold=256 +online-mode=false +op-permission-level=4 +player-idle-timeout=0 +prevent-proxy-connections=false +pvp=true +query.port=25565 +rate-limit=0 +rcon.password= +rcon.port=25575 +require-resource-pack=false +resource-pack= +resource-pack-id= +resource-pack-prompt= +resource-pack-sha1= +server-ip= +server-port=25565 +simulation-distance=10 +snooper-enabled=true +spawn-animals=true +spawn-monsters=true +spawn-npcs=true +spawn-protection=16 +sync-chunk-writes=true +text-filtering-config= +use-native-transport=true +view-distance=10 +white-list=false diff --git a/cypress/plugins/startServer.ts b/cypress/plugins/startServer.ts new file mode 100644 index 00000000..ecf0d210 --- /dev/null +++ b/cypress/plugins/startServer.ts @@ -0,0 +1,45 @@ +import { ChildProcess, spawn } from 'child_process' +import * as fs from 'fs' +import * as path from 'path' +import { promisify } from 'util' +import { downloadServer } from 'minecraft-wrap' +import * as waitOn from 'wait-on' + +let prevProcess: ChildProcess | null = null +export const startMinecraftServer = async (version: string, port: number) => { + if (prevProcess) return null + const jar = `./server-jar/${version}.jar` + + const start = () => { + // if (prevProcess) { + // prevProcess.kill() + // } + + prevProcess = spawn('java', ['-jar', path.basename(jar), 'nogui', '--port', `${port}`], { + stdio: 'inherit', + cwd: path.dirname(jar), + }) + } + + let coldStart = false + if (fs.existsSync(jar)) { + start() + } else { + coldStart = true + promisify(downloadServer)(version, jar).then(() => { + // add eula.txt + fs.writeFileSync(path.join(path.dirname(jar), 'eula.txt'), 'eula=true') + // copy cypress/plugins/server.properties + fs.copyFileSync(path.join(__dirname, 'server.properties'), path.join(path.dirname(jar), 'server.properties')) + // copy ops.json + fs.copyFileSync(path.join(__dirname, 'ops.json'), path.join(path.dirname(jar), 'ops.json')) + start() + }) + } + + return new Promise((res) => { + waitOn({ resources: [`tcp:localhost:${port}`] }, () => { + setTimeout(() => res(null), coldStart ? 6500 : 2000) // todo retry instead of timeout + }) + }) +} diff --git a/index.html b/index.html index 6d3b326b..62e109cd 100644 --- a/index.html +++ b/index.html @@ -14,7 +14,7 @@
Loading...
-
A true Minecraft client in your browser!
+
A true Minecraft client in your browser!
` diff --git a/src/index.ts b/src/index.ts index fe584b4d..72f270d4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,6 +17,7 @@ import './scaleInterface' import itemsPng from 'prismarine-viewer/public/textures/items.png' import { initWithRenderer } from './topRightStats' import PrismarineBlock from 'prismarine-block' +import PrismarineItem from 'prismarine-item' import { options, watchValue } from './optionsStorage' import './reactUi.jsx' @@ -580,6 +581,7 @@ async function connect (connectOptions: ConnectOptions) { errorAbortController.abort() const mcData = MinecraftData(bot.version) window.PrismarineBlock = PrismarineBlock(mcData.version.minecraftVersion!) + window.PrismarineItem = PrismarineItem(mcData.version.minecraftVersion!) window.loadedData = mcData window.Vec3 = Vec3 window.pathfinder = pathfinder @@ -825,9 +827,12 @@ listenGlobalEvents() watchValue(miscUiState, async s => { if (s.appLoaded) { // fs ready const qs = new URLSearchParams(window.location.search) + const moreServerOptions = {} as Record + if (qs.has('version')) moreServerOptions.version = qs.get('version') if (qs.get('singleplayer') === '1') { loadSingleplayer({}, { - worldFolder: undefined + worldFolder: undefined, + ...moreServerOptions }) } if (qs.get('loadSave')) { diff --git a/src/react/Chat.tsx b/src/react/Chat.tsx index b05f9930..981878c8 100644 --- a/src/react/Chat.tsx +++ b/src/react/Chat.tsx @@ -1,6 +1,5 @@ import { proxy, subscribe } from 'valtio' import { useEffect, useMemo, useRef, useState } from 'react' -import { isCypress } from '../standaloneUtils' import { MessageFormatPart } from '../botUtils' import { MessagePart } from './MessageFormatted' import './Chat.css' @@ -200,7 +199,7 @@ export default ({ messages, opacity = 1, fetchCompletionItems, opened, sendMessa return ( <> -
diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index 9772c9b4..ca749560 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -7,6 +7,7 @@ import ServersList from './ServersList' import AddServerOrConnect, { BaseServerInfo } from './AddServerOrConnect' import { useDidUpdateEffect } from './utils' import { useIsModalActive } from './utilsApp' +import { showOptionsModal } from './SelectOption' interface StoreServerItem extends BaseServerInfo { lastJoined?: number @@ -46,6 +47,15 @@ type AdditionalDisplayData = { icon?: string } +export interface AuthenticatedAccount { + // type: 'microsoft' + username: string + cachedTokens?: { + data: any + expiresOn: number + } +} + const getInitialServersList = () => { if (localStorage['serversList']) return JSON.parse(localStorage['serversList']) as StoreServerItem[] @@ -62,7 +72,6 @@ const getInitialServersList = () => { if (localStorage['server']) { const legacyLastJoinedServer: StoreServerItem = { ip: localStorage['server'], - passwordOverride: localStorage['password'], versionOverride: localStorage['version'], lastJoined: Date.now() } @@ -104,16 +113,21 @@ const getInitialProxies = () => { return proxies } -export const updateLoadedServerData = (callback: (data: StoreServerItem) => StoreServerItem) => { +export const updateLoadedServerData = (callback: (data: StoreServerItem) => StoreServerItem, index = miscUiState.loadedServerIndex) => { + if (!index) return // function assumes component is not mounted to avoid sync issues after save - const { loadedServerIndex } = miscUiState - if (!loadedServerIndex) return const servers = getInitialServersList() - const server = servers[loadedServerIndex] - servers[loadedServerIndex] = callback(server) + const server = servers[index] + servers[index] = callback(server) setNewServersList(servers) } +export const updateAuthenticatedAccountData = (callback: (data: AuthenticatedAccount[]) => AuthenticatedAccount[]) => { + const accounts = JSON.parse(localStorage['authenticatedAccounts'] || '[]') as AuthenticatedAccount[] + const newAccounts = callback(accounts) + localStorage['authenticatedAccounts'] = JSON.stringify(newAccounts) +} + // todo move to base const normalizeIp = (ip: string) => ip.replace(/https?:\/\//, '').replace(/\/(:|$)/, '') @@ -122,6 +136,11 @@ const Inner = () => { const [selectedProxy, setSelectedProxy] = useState(localStorage.getItem('selectedProxy') ?? proxies?.[0] ?? '') const [serverEditScreen, setServerEditScreen] = useState(null) // true for add const [defaultUsername, setDefaultUsername] = useState(localStorage['username'] ?? (`mcrafter${Math.floor(Math.random() * 1000)}`)) + const [authenticatedAccounts, setAuthenticatedAccounts] = useState(JSON.parse(localStorage['authenticatedAccounts'] || '[]')) + + useEffect(() => { + localStorage.setItem('authenticatedAccounts', JSON.stringify(authenticatedAccounts)) + }, [authenticatedAccounts]) useEffect(() => { localStorage.setItem('username', defaultUsername) @@ -215,6 +234,7 @@ const Inner = () => { } setServerEditScreen(null) }} + accounts={authenticatedAccounts.map(a => a.username)} initialData={!serverEditScreen || serverEditScreen === true ? undefined : serverEditScreen} onQsConnect={(info) => { const connectOptions: ConnectOptions = { @@ -222,7 +242,6 @@ const Inner = () => { server: normalizeIp(info.ip), proxy: info.proxyOverride || selectedProxy, botVersion: info.versionOverride, - password: info.passwordOverride, ignoreQs: true, } dispatchEvent(new CustomEvent('connect', { detail: connectOptions })) @@ -249,14 +268,22 @@ const Inner = () => { if (!username) return setDefaultUsername(username) } + let authenticatedAccount: AuthenticatedAccount | true | undefined + if (overrides.authenticatedAccountOverride) { + if (overrides.authenticatedAccountOverride === true) { + authenticatedAccount = true + } else { + authenticatedAccount = authenticatedAccounts.find(a => a.username === overrides.authenticatedAccountOverride) ?? true + } + } const options = { username, server: normalizeIp(ip), proxy: overrides.proxyOverride || selectedProxy, botVersion: overrides.versionOverride ?? /* legacy */ overrides['version'], - password: overrides.passwordOverride, ignoreQs: true, autoLoginPassword: server?.autoLogin?.[username], + authenticatedAccount, onSuccessfulPlay () { if (shouldSave && !serversList.some(s => s.ip === ip)) { const newServersList: StoreServerItem[] = [...serversList, { @@ -294,6 +321,11 @@ const Inner = () => { }} username={defaultUsername} setUsername={setDefaultUsername} + onProfileClick={async () => { + const username = await showOptionsModal('Select authenticated account to remove', authenticatedAccounts.map(a => a.username)) + if (!username) return + setAuthenticatedAccounts(old => old.filter(a => a.username !== username)) + }} onWorldAction={(action, index) => { const server = serversList[index] if (!server) return diff --git a/src/react/SignInMessage.stories.tsx b/src/react/SignInMessage.stories.tsx new file mode 100644 index 00000000..16528700 --- /dev/null +++ b/src/react/SignInMessage.stories.tsx @@ -0,0 +1,18 @@ +import type { Meta, StoryObj } from '@storybook/react' +import SignInMessage from './SignInMessage' + +const meta: Meta<{ open }> = { + component: SignInMessage as any, + render ({ open }) { + return + }, +} + +export default meta +type Story = StoryObj<{ open }> + +export const Primary: Story = { + args: { + }, +} diff --git a/src/react/SignInMessage.tsx b/src/react/SignInMessage.tsx new file mode 100644 index 00000000..2ec38816 --- /dev/null +++ b/src/react/SignInMessage.tsx @@ -0,0 +1,107 @@ +import { useState } from 'react' +import { useUtilsEffect } from '@zardoy/react-util' +import PixelartIcon from './PixelartIcon' +import Screen from './Screen' +import Button from './Button' + +export default ({ + code = 'ABCD-EFGH-IJKL-MNOP', + loginLink = 'https://aka.ms/devicelogin', + connectingServer = 'mc.example.comsdlfjsklfjsfjdskfjsj', + warningText = true, + expiresEnd = Date.now() + 1000 * 60 * 5, + setSaveToken = (() => { }) as ((state: boolean) => void) | undefined, + defaultSaveToken = true, + onCancel = () => { }, + directLink = 'https://aka.ms/devicelogin' +}) => { + if (connectingServer.length > 30) connectingServer = connectingServer.slice(0, 30) + '...' + const [timeLeft, setTimeLeft] = useState(``) + + useUtilsEffect(({ interval }) => { + interval(1000, () => { + const timeLeft = Math.max(0, Math.ceil((expiresEnd - Date.now()) / 1000)) + const minutes = Math.floor(timeLeft / 60) + const seconds = timeLeft % 60 + setTimeLeft(`${minutes}:${seconds.toString().padStart(2, '0')}`) + if (timeLeft <= 0) setTimeLeft('Code expired!') + }) + }, []) + + return + + + +} diff --git a/src/react/SignInMessageProvider.tsx b/src/react/SignInMessageProvider.tsx new file mode 100644 index 00000000..68ea83aa --- /dev/null +++ b/src/react/SignInMessageProvider.tsx @@ -0,0 +1,32 @@ +import { proxy, ref, useSnapshot } from 'valtio' +import SignInMessage from './SignInMessage' +import { lastConnectOptions } from './AppStatusProvider' + +export const signInMessageState = proxy({ + code: '', + link: '', + expiresOn: 0, + shouldSaveToken: true, + abortController: ref(new AbortController()), +}) + +export default () => { + const { code, expiresOn, link, shouldSaveToken } = useSnapshot(signInMessageState) + + if (!code) return null + + return { + signInMessageState.shouldSaveToken = state + }} + connectingServer={lastConnectOptions.value?.server ?? ''} + onCancel={() => { + signInMessageState.abortController.abort() + }} + directLink={`http://microsoft.com/link?otc=${code}`} + /> +} diff --git a/src/react/globals.d.ts b/src/react/globals.d.ts index 108fae54..7b0f64bb 100644 --- a/src/react/globals.d.ts +++ b/src/react/globals.d.ts @@ -32,9 +32,9 @@ declare module '*.svg' { interface PromiseConstructor { withResolvers (): { - resolve: (value: T) => void; - reject: (reason: any) => void; - promise: Promise; + resolve: (value: T) => void + reject: (reason: any) => void + promise: Promise } } @@ -44,6 +44,7 @@ declare namespace JSX { icon: string style?: React.CSSProperties class?: string + onClick?: (e) => void } } } diff --git a/src/reactUi.tsx b/src/reactUi.tsx index f140326e..34a567cd 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -40,6 +40,7 @@ import KeybindingsScreenProvider from './react/KeybindingsScreenProvider' import HeldMapUi from './react/HeldMapUi' import BedTime from './react/BedTime' import NoModalFoundProvider from './react/NoModalFoundProvider' +import SignInMessageProvider from './react/SignInMessageProvider' const RobustPortal = ({ children, to }) => { return createPortal({children}, to) @@ -173,6 +174,7 @@ const App = () => { + {/* */} @@ -191,7 +193,7 @@ const App = () => { const PerComponentErrorBoundary = ({ children }) => { return children.map((child, i) => { const componentNameClean = (child.type.name || child.type.displayName || 'Unknown').replaceAll(/__|_COMPONENT/g, '') - showNotification(`UI component ${componentNameClean} crashed!`, 'Please report this. Use console to see more info.', true, undefined) + showNotification(`UI component ${componentNameClean} crashed!`, 'Please report this. Use console for more.', true, undefined) return null }}>{child}) } diff --git a/src/yggdrasilReplacement.ts b/src/yggdrasilReplacement.ts new file mode 100644 index 00000000..e0cab6f0 --- /dev/null +++ b/src/yggdrasilReplacement.ts @@ -0,0 +1,27 @@ +export const server = ({ host: sessionServer }) => { + return { + async join (accessToken, sessionSelectedProfileId, serverId, sharedSecret, publicKey, cb) { + try { + const result = await fetch(`${sessionServer}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + accessToken, + selectedProfile: sessionSelectedProfileId, + serverId, + sharedSecret, + publicKey, + }), + }) + if (!result.ok) { + throw new Error(`Request failed ${await result.text()}`) + } + cb(null) + } catch (err) { + cb(err) + } + } + } +} From 324c08ef436ec66672d544109eacc08d27dd2dcc Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 7 Jul 2024 00:32:04 +0300 Subject: [PATCH 0185/1097] finally update dockerfile to a working one! uses 6gb of ram to build btw. image size: 2.4gb, ~200mb when running --- .dockerignore | 2 -- Dockerfile | 19 ++++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.dockerignore b/.dockerignore index 285d1303..38ca0016 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,3 @@ -# we dont want default config to be loaded in the dockerfile, but rather using a volume -config.json # build stuff node_modules public \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index aa9eb3dc..086240b5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,22 @@ -FROM node:14-alpine +FROM node:18-alpine # Without git installing the npm packages fails RUN apk add git RUN mkdir /app WORKDIR /app COPY . /app -RUN npm install -RUN npm run build +# install python and other dependencies +RUN apk add python3 make g++ cairo-dev pango-dev jpeg-dev giflib-dev librsvg-dev +# install pnpm +RUN npm i -g pnpm@9.0.4 +RUN pnpm install +# only for prod +RUN pnpm run build +# --- +EXPOSE 8080 +# uncomment for development +# EXPOSE 9090 +# VOLUME /app/src +# VOLUME /app/prismarine-viewer +# ENTRYPOINT ["pnpm", "run", "run-all"] +# only for prod ENTRYPOINT ["npm", "run", "prod-start"] From d80b71ede74a110debac25c1ea5b45f802b5d41d Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 6 Jul 2024 23:20:40 +0300 Subject: [PATCH 0186/1097] add demo to npm readme file --- README.NPM.MD | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.NPM.MD b/README.NPM.MD index c036adba..c44492c6 100644 --- a/README.NPM.MD +++ b/README.NPM.MD @@ -1,9 +1,13 @@ # Minecraft React +Minecraft UI components for React. + ```bash -yarn add minecraft-react +pnpm i minecraft-react ``` +![demo](https://github-production-user-asset-6210df.s3.amazonaws.com/46503702/346295584-80f3ed4a-cab6-45d2-8896-5e20233cc9b1.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVCODYLSA53PQK4ZA%2F20240706%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240706T195400Z&X-Amz-Expires=300&X-Amz-Signature=5b063823a57057c4042c15edd1db3edd107e00940fd0e66a2ba1df4e564a2809&X-Amz-SignedHeaders=host&actor_id=46503702&key_id=0&repo_id=432411890) + ## Usage ```jsx From d1d0959cb40af0e7872f12996db1ce6ce1f364e1 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 7 Jul 2024 01:12:25 +0300 Subject: [PATCH 0187/1097] feat: add Sonar bypass making possible to join to projects like ruhypixel.net wip: packets replay feature! --- pnpm-lock.yaml | 8 ++++---- src/index.ts | 14 ++++++++++++-- src/inventoryWindows.ts | 4 ++-- src/optionsGuiScheme.tsx | 22 ++++++++++++++++++++++ src/react/AppStatusProvider.tsx | 7 ++++++- src/react/ServersListProvider.tsx | 2 ++ src/react/SignInMessage.tsx | 2 ++ 7 files changed, 50 insertions(+), 9 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98618ba5..cf890476 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -311,7 +311,7 @@ importers: version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/c50afc54e39817f7e4d313ce0f6fdaad71e7e4f4(@types/react@18.2.20)(react@18.2.0) mineflayer: specifier: github:zardoy/mineflayer - version: https://codeload.github.com/zardoy/mineflayer/tar.gz/a4b1b4ba7f8c972cee9c0a16eb1191ff4d21fe23(encoding@0.1.13) + version: https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479(encoding@0.1.13) mineflayer-pathfinder: specifier: ^2.4.4 version: 2.4.4 @@ -6089,8 +6089,8 @@ packages: resolution: {integrity: sha512-QMMNPx4IyZE7ydAzjvGLQLCnQNUOfkk1qVZKxTTS9q3qPTAewz4GhsVUBtbQ8LSbHthe5RcQ1Sgxs4wlIma/Qw==} engines: {node: '>=18'} - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/a4b1b4ba7f8c972cee9c0a16eb1191ff4d21fe23: - resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/a4b1b4ba7f8c972cee9c0a16eb1191ff4d21fe23} + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479} version: 4.20.1 engines: {node: '>=18'} @@ -15831,7 +15831,7 @@ snapshots: - encoding - supports-color - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/a4b1b4ba7f8c972cee9c0a16eb1191ff4d21fe23(encoding@0.1.13): + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479(encoding@0.1.13): dependencies: minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13) diff --git a/src/index.ts b/src/index.ts index 5fd50ce3..e73e8240 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,6 +42,7 @@ import * as THREE from 'three' import MinecraftData, { versionsByMinecraftVersion } from 'minecraft-data' import debug from 'debug' import { defaultsDeep } from 'lodash-es' +import initializePacketsReplay from './packetsReplay' import { initVR } from './vr' import { @@ -97,6 +98,7 @@ import { ref, subscribe } from 'valtio' import { signInMessageState } from './react/SignInMessageProvider' import { updateAuthenticatedAccountData, updateLoadedServerData } from './react/ServersListProvider' import { versionToNumber } from 'prismarine-viewer/viewer/prepare/utils' +import packetsPatcher from './packetsPatcher' window.debug = debug window.THREE = THREE @@ -108,6 +110,8 @@ window.beforeRenderFrame = [] void registerServiceWorker() watchFov() initCollisionShapes() +initializePacketsReplay() +packetsPatcher() // Create three.js context, add to page let renderer: THREE.WebGLRenderer @@ -361,6 +365,7 @@ async function connect (connectOptions: ConnectOptions) { } const renderDistance = singleplayer ? renderDistanceSingleplayer : multiplayerRenderDistance + let updateDataAfterJoin = () => { } let localServer try { const serverOptions = defaultsDeep({}, connectOptions.serverOverrides ?? {}, options.localServerOptions, defaultServerOptions) @@ -506,9 +511,13 @@ async function connect (connectOptions: ConnectOptions) { } return accounts }) - updateLoadedServerData(s => ({ ...s, authenticatedAccountOverride: client.username }), connectOptions.serverIndex) + updateDataAfterJoin = () => { + updateLoadedServerData(s => ({ ...s, authenticatedAccountOverride: client.username }), connectOptions.serverIndex) + } } else { - updateLoadedServerData(s => ({ ...s, authenticatedAccountOverride: undefined }), connectOptions.serverIndex) + updateDataAfterJoin = () => { + updateLoadedServerData(s => ({ ...s, authenticatedAccountOverride: undefined }), connectOptions.serverIndex) + } } setLoadingScreenStatus('Authentication successful. Logging in to server') } finally { @@ -660,6 +669,7 @@ async function connect (connectOptions: ConnectOptions) { setLoadingScreenStatus('Placing blocks (starting viewer)') localStorage.lastConnectOptions = JSON.stringify(connectOptions) connectOptions.onSuccessfulPlay?.() + updateDataAfterJoin() if (connectOptions.autoLoginPassword) { bot.chat(`/login ${connectOptions.autoLoginPassword}`) } diff --git a/src/inventoryWindows.ts b/src/inventoryWindows.ts index 5f7fc0a5..fd213509 100644 --- a/src/inventoryWindows.ts +++ b/src/inventoryWindows.ts @@ -328,9 +328,9 @@ export const getItemNameRaw = (item: Pick return parsed as MessageFormatPart } } catch (err) { - return [{ + return { text: customName - }] + } } } diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index d7636392..76799a60 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -9,6 +9,7 @@ import Slider from './react/Slider' import { getScreenRefreshRate, setLoadingScreenStatus } from './utils' import { openFilePicker, resetLocalStorageWithoutWorld } from './browserfs' import { getResourcePackName, resourcePackState, uninstallTexturePack } from './texturePack' +import { downloadPacketsReplay, packetsReplaceSessionState } from './packetsReplay' export const guiOptionsScheme: { @@ -309,6 +310,27 @@ export const guiOptionsScheme: { if (confirm('Are you sure you want to reset all settings?')) resetLocalStorageWithoutWorld() }}>Reset all settings }, + }, + { + custom () { + return Developer + }, + }, + { + custom () { + const { active } = useSnapshot(packetsReplaceSessionState) + return + }, + }, + { + custom () { + const { active } = useSnapshot(packetsReplaceSessionState) + return + }, } ], } diff --git a/src/react/AppStatusProvider.tsx b/src/react/AppStatusProvider.tsx index 0b12390c..c905be12 100644 --- a/src/react/AppStatusProvider.tsx +++ b/src/react/AppStatusProvider.tsx @@ -5,6 +5,7 @@ import { resetLocalStorageWorld } from '../browserfs' import { fsState } from '../loadSave' import { guessProblem } from '../errorLoadingScreenHelpers' import { ConnectOptions } from '../connect' +import { downloadPacketsReplay, packetsReplaceSessionState } from '../packetsReplay' import AppStatus from './AppStatus' import DiveTransition from './DiveTransition' import { useDidUpdateEffect } from './utils' @@ -32,6 +33,7 @@ export const lastConnectOptions = { export default () => { const { isError, lastStatus, maybeRecoverable, status, hideDots, descriptionHint } = useSnapshot(appStatusState) + const { active: replayActive } = useSnapshot(packetsReplaceSessionState) const isOpen = useIsModalActive('app-status') @@ -103,7 +105,10 @@ export default () => { } } : undefined} actionsSlot={ - displayAuthButton &&
+
{code}
+
+ Waiting... {timeLeft} +
+
+ {warningText &&
+ Join only vanilla servers! This client is detectable and may result in a ban by anti-cheat plugins. +
} + {setSaveToken && } +
}, ], parameters: { @@ -23,6 +23,6 @@ const preview: Preview = { }, }, }, -}; +} -export default preview; +export default preview diff --git a/README.MD b/README.MD index ad120dbf..9a4ba24a 100644 --- a/README.MD +++ b/README.MD @@ -4,14 +4,14 @@ A true Minecraft client running in your browser! A port of the original game to the web, written in JavaScript using modern web technologies. -If you encounter any bugs or usability issues, please report them! +If you encounter any bugs or usability issues, please report them! For development, see [development](#development--debugging). You can try this out at [mcraft.fun](https://mcraft.fun/), [pcm.gg](https://pcm.gg) (short link) [mcon.vercel.app](https://mcon.vercel.app/) or the GitHub pages deploy. Every commit from the `develop` (default) branch is deployed to [s.mcraft.fun](https://s.mcraft.fun/) - so it's usually newer, but might be less stable. ### Big Features - Open any zip world file or even folder in read-write mode! -- Connect to cracked servers* (it's possible because of proxy servers, see below) +- Connect to Java servers running in both offline (cracked) and online mode* (it's possible because of proxy servers, see below) - Singleplayer mode with simple world generations! - Works offline - Play with friends over internet! (P2P is powered by Peer.js discovery servers) @@ -39,9 +39,9 @@ Whatever offline mode you used (zip, folder, just single player), you can always ### Servers -You can play almost on any server, supporting offline connections. +You can play almost on any Java server, vanilla servers are fully supported. See the [Mineflayer](https://github.com/PrismarineJS/mineflayer) repo for the list of supported versions (should support majority of versions). -There is a builtin proxy, but you can also host a your one! Just clone the repo, run `pnpm i` (following CONTRIBUTING.MD) and run `pnpm prod-start`, then you can specify `http://localhost:8080` in the proxy field. +There is a builtin proxy, but you can also host your one! Just clone the repo, run `pnpm i` (following CONTRIBUTING.MD) and run `pnpm prod-start`, then you can specify `http://localhost:8080` in the proxy field. MS account authentication will be supported soon. ### Rendering @@ -67,9 +67,9 @@ There are many many settings, that are not exposed in the UI yet. You can find o To open the console, press `F12`, or if you are on mobile, you can type `#debug` in the URL (browser address bar), it wont't reload the page, but you will see a button to open the console. This way you can change advanced settings and see all errors or warnings. Also this way you can access global variables (described below). -### Debugging +### Development & Debugging -It should be easy to build/start the project locally. See [CONTRIBUTING.MD](./CONTRIBUTING.md) for more info. +It should be easy to build/start the project locally. See [CONTRIBUTING.MD](./CONTRIBUTING.md) for more info. Also you can look at Dockerfile for reference. There is world renderer playground ([link](https://mcon.vercel.app/playground.html)). diff --git a/esbuild.mjs b/esbuild.mjs index 28b233bf..1f075a62 100644 --- a/esbuild.mjs +++ b/esbuild.mjs @@ -85,6 +85,9 @@ const buildOptions = { '.vert': 'text', '.frag': 'text', '.obj': 'text', + '.woff': 'dataurl', + '.woff2': 'dataurl', + '.ttf': 'dataurl', }, write: false, // todo would be better to enable? diff --git a/package.json b/package.json index 5bf32a69..07e9ff0b 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,6 @@ "flying-squid": "npm:@zardoy/flying-squid@^0.0.33", "fs-extra": "^11.1.1", "google-drive-browserfs": "github:zardoy/browserfs#google-drive", - "iconify-icon": "^1.0.8", "jszip": "^3.10.1", "lodash-es": "^4.17.21", "minecraft-assets": "^1.12.2", @@ -77,6 +76,7 @@ "net-browserify": "github:zardoy/prismarinejs-net-browserify", "node-gzip": "^1.1.2", "peerjs": "^1.5.0", + "pixelarticons": "^1.8.1", "pretty-bytes": "^6.1.1", "prismarine-provider-anvil": "github:zardoy/prismarine-provider-anvil#everything", "prosemirror-example-setup": "^1.2.2", @@ -169,7 +169,8 @@ }, "patchedDependencies": { "minecraft-protocol@1.47.0": "patches/minecraft-protocol@1.47.0.patch", - "three@0.154.0": "patches/three@0.154.0.patch" + "three@0.154.0": "patches/three@0.154.0.patch", + "pixelarticons@1.8.1": "patches/pixelarticons@1.8.1.patch" } }, "packageManager": "pnpm@9.0.4" diff --git a/patches/pixelarticons@1.8.1.patch b/patches/pixelarticons@1.8.1.patch new file mode 100644 index 00000000..10044536 --- /dev/null +++ b/patches/pixelarticons@1.8.1.patch @@ -0,0 +1,27 @@ +diff --git a/fonts/pixelart-icons-font.css b/fonts/pixelart-icons-font.css +index 3b2ebe839370d96bf93ef5ca94a827f07e49378d..103ab4d6b9f3b5c9f41d1407e3cbf4ac392fbf41 100644 +--- a/fonts/pixelart-icons-font.css ++++ b/fonts/pixelart-icons-font.css +@@ -1,16 +1,13 @@ + @font-face { + font-family: "pixelart-icons-font"; +- src: url('pixelart-icons-font.eot?t=1711815892278'); /* IE9*/ +- src: url('pixelart-icons-font.eot?t=1711815892278#iefix') format('embedded-opentype'), /* IE6-IE8 */ ++ src: + url("pixelart-icons-font.woff2?t=1711815892278") format("woff2"), + url("pixelart-icons-font.woff?t=1711815892278") format("woff"), + url('pixelart-icons-font.ttf?t=1711815892278') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ +- url('pixelart-icons-font.svg?t=1711815892278#pixelart-icons-font') format('svg'); /* iOS 4.1- */ + } + + [class^="pixelart-icons-font-"], [class*=" pixelart-icons-font-"] { + font-family: 'pixelart-icons-font' !important; +- font-size:24px; + font-style:normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +@@ -503,4 +500,3 @@ + .pixelart-icons-font-zap:before { content: "\ebe4"; } + .pixelart-icons-font-zoom-in:before { content: "\ebe5"; } + .pixelart-icons-font-zoom-out:before { content: "\ebe6"; } +- diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf890476..2208e681 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ patchedDependencies: minecraft-protocol@1.47.0: hash: 7otpchsbv7hxsuis4rrrwdtbve path: patches/minecraft-protocol@1.47.0.patch + pixelarticons@1.8.1: + hash: cclg2qo6d4yjs4evj64nr2mbwa + path: patches/pixelarticons@1.8.1.patch three@0.154.0: hash: sj7ocb4p23jym6bkfgueanti2e path: patches/three@0.154.0.patch @@ -115,9 +118,6 @@ importers: google-drive-browserfs: specifier: github:zardoy/browserfs#google-drive version: browserfs@https://codeload.github.com/zardoy/browserfs/tar.gz/ab58ae8ef00e3a31db01909e365e6cb5188436e0 - iconify-icon: - specifier: ^1.0.8 - version: 1.0.8 jszip: specifier: ^3.10.1 version: 3.10.1 @@ -148,6 +148,9 @@ importers: peerjs: specifier: ^1.5.0 version: 1.5.0 + pixelarticons: + specifier: ^1.8.1 + version: 1.8.1(patch_hash=cclg2qo6d4yjs4evj64nr2mbwa) pretty-bytes: specifier: ^6.1.1 version: 6.1.1 @@ -1723,9 +1726,6 @@ packages: '@humanwhocodes/object-schema@1.2.1': resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - '@iconify/types@2.0.0': - resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -5158,9 +5158,6 @@ packages: hyphenate-style-name@1.0.4: resolution: {integrity: sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==} - iconify-icon@1.0.8: - resolution: {integrity: sha512-jvbUKHXf8EnGGArmhlP2IG8VqQLFFyTvTqb9LVL2TKTh7/eCCD1o2HHE9thpbJJb6B8hzhcFb6rOKhvo7reNKA==} - iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -6633,6 +6630,9 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + pixelarticons@1.8.1: + resolution: {integrity: sha512-4taoDCleft9RtzVHLA73VDnRBwJNqlwbW8ShO6S0G9b+bM5ArGe1MVFW9xpromuPvQgVUYCSjRxNAQuNtADqyA==} + pixelmatch@4.0.2: resolution: {integrity: sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==} hasBin: true @@ -9985,8 +9985,6 @@ snapshots: '@humanwhocodes/object-schema@1.2.1': {} - '@iconify/types@2.0.0': {} - '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -14722,10 +14720,6 @@ snapshots: hyphenate-style-name@1.0.4: {} - iconify-icon@1.0.8: - dependencies: - '@iconify/types': 2.0.0 - iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -16433,6 +16427,8 @@ snapshots: pirates@4.0.6: {} + pixelarticons@1.8.1(patch_hash=cclg2qo6d4yjs4evj64nr2mbwa): {} + pixelmatch@4.0.2: dependencies: pngjs: 3.4.0 diff --git a/scripts/genPixelartTypes.ts b/scripts/genPixelartTypes.ts new file mode 100644 index 00000000..e7c9649a --- /dev/null +++ b/scripts/genPixelartTypes.ts @@ -0,0 +1,16 @@ +import fs from 'fs' + +const icons = fs.readdirSync('node_modules/pixelarticons/svg') + +const addIconPath = '../../node_modules/pixelarticons/svg/' + +let str = 'export type PixelartIconsGenerated = {\n' +for (const icon of icons) { + const name = icon.replace('.svg', '') + // jsdoc + const jsdocImage = '![image](' + addIconPath + icon + ')' + str += ` /** ${jsdocImage} */\n` + str += ` '${name}': string;\n` +} +str += '}\n' +fs.writeFileSync('./src/react/pixelartIcons.generated.ts', str, 'utf8') diff --git a/src/index.ts b/src/index.ts index e73e8240..e34e81ab 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,6 @@ import './importsWorkaround' import './styles.css' import './globals' -import 'iconify-icon' import './devtools' import './entities' import './globalDomListeners' diff --git a/src/packetsPatcher.ts b/src/packetsPatcher.ts index f877d6ed..587c41c9 100644 --- a/src/packetsPatcher.ts +++ b/src/packetsPatcher.ts @@ -2,13 +2,13 @@ // todo these fixes should be ported to mineflayer export default () => { - customEvents.on('mineflayerBotCreated', () => { - bot._client.on('packet', (data, meta) => { - if (meta.name === 'map_chunk') { - if (data.groundUp && data.bitMap === 1 && data.chunkData.every(x => x === 0)) { - data.chunkData = Buffer.from(Array.from({ length: 12_544 }).fill(0) as any) - } - } - }) + customEvents.on('mineflayerBotCreated', () => { + bot._client.on('packet', (data, meta) => { + if (meta.name === 'map_chunk') { + if (data.groundUp && data.bitMap === 1 && data.chunkData.every(x => x === 0)) { + data.chunkData = Buffer.from(Array.from({ length: 12_544 }).fill(0) as any) + } + } }) + }) } diff --git a/src/react/Button.tsx b/src/react/Button.tsx index 20dc0801..10ff2fb0 100644 --- a/src/react/Button.tsx +++ b/src/react/Button.tsx @@ -2,6 +2,7 @@ import classNames from 'classnames' import { createContext, FC, Ref, useContext } from 'react' import buttonCss from './button.module.css' import SharedHudVars from './SharedHudVars' +import PixelartIcon from './PixelartIcon' // testing in storybook from deathscreen @@ -17,7 +18,7 @@ const ButtonContext = createContext({ onClick () { }, }) -export const ButtonProvider: FC<{children, onClick}> = ({ children, onClick }) => { +export const ButtonProvider: FC<{ children, onClick }> = ({ children, onClick }) => { return {children} } @@ -39,7 +40,7 @@ export default (({ label, icon, children, inScreen, rootRef, type = 'button', .. return diff --git a/src/react/ConceptCommandsGui.stories.tsx b/src/react/ConceptCommandsGui.stories.tsx index 89cb6eff..4f3586d4 100644 --- a/src/react/ConceptCommandsGui.stories.tsx +++ b/src/react/ConceptCommandsGui.stories.tsx @@ -11,7 +11,6 @@ const Button2 = ({ title, icon }) => {
{title}
- {/* { // const sessionEndpoint = 'http://localhost:3000/session' let authEndpoint = '' let sessionEndpoint = '' + if (!proxyBaseUrl.startsWith('http')) proxyBaseUrl = `${isPageSecure() ? 'https' : 'http'}://${proxyBaseUrl}` + const url = proxyBaseUrl + '/api/vm/net/connect' + let result: Response + try { + result = await fetch(url) + } catch (err) { + throw new Error(`Selected proxy server ${proxyBaseUrl} most likely is down`) + } try { - if (!proxyBaseUrl.startsWith('http')) proxyBaseUrl = `${isPageSecure() ? 'https' : 'http'}://${proxyBaseUrl}` - const url = proxyBaseUrl + '/api/vm/net/connect' - const result = await fetch(url) const json = await result.json() authEndpoint = urlWithBase(json.capabilities.authEndpoint, proxyBaseUrl) sessionEndpoint = urlWithBase(json.capabilities.sessionEndpoint, proxyBaseUrl) diff --git a/src/react/AppStatus.tsx b/src/react/AppStatus.tsx index 10cc5793..9ebecf93 100644 --- a/src/react/AppStatus.tsx +++ b/src/react/AppStatus.tsx @@ -28,6 +28,7 @@ export default ({ status, isError, hideDots = false, lastStatus = '', backAction return ( diff --git a/src/react/Chat.css b/src/react/Chat.css index 41917783..cba0a1aa 100644 --- a/src/react/Chat.css +++ b/src/react/Chat.css @@ -24,6 +24,13 @@ div.chat-wrapper { left: 1px; box-sizing: border-box; background-color: rgba(0, 0, 0, 0); + display: flex; + align-items: center; + gap: 1px; +} + +.chat-input-wrapper form { + display: flex; } .chat-input { @@ -103,7 +110,8 @@ div.chat-wrapper { } .input-mobile #chatinput { - height: 20px; + height: 24px; + font-size: 13px; } .display-mobile { diff --git a/src/react/Chat.tsx b/src/react/Chat.tsx index 89b2aa8b..60467171 100644 --- a/src/react/Chat.tsx +++ b/src/react/Chat.tsx @@ -4,6 +4,8 @@ import { MessageFormatPart } from '../botUtils' import { MessagePart } from './MessageFormatted' import './Chat.css' import { isIos, reactKeyForMessage } from './utils' +import Button from './Button' +import { pixelartIcons } from './PixelartIcon' export type Message = { parts: MessageFormatPart[], @@ -221,6 +223,8 @@ export default ({
diff --git a/src/react/EnterFullscreenButton.tsx b/src/react/EnterFullscreenButton.tsx index ad78ddad..3901b9ae 100644 --- a/src/react/EnterFullscreenButton.tsx +++ b/src/react/EnterFullscreenButton.tsx @@ -1,6 +1,11 @@ import { useEffect, useState } from 'react' +import { useSnapshot } from 'valtio' +import { activeModalStack, miscUiState } from '../globalState' import Button from './Button' import { useUsingTouch } from './utilsApp' +import { pixelartIcons } from './PixelartIcon' + +const hideOnModals = new Set(['chat']) export default () => { const [fullScreen, setFullScreen] = useState(false) @@ -9,16 +14,23 @@ export default () => { setFullScreen(!!document.fullscreenElement) }) }, []) + const { gameLoaded } = useSnapshot(miscUiState) + + const activeStack = useSnapshot(activeModalStack) + + const inMainMenu = activeStack.length === 0 && !gameLoaded const usingTouch = useUsingTouch() - if (!usingTouch || !document.documentElement.requestFullscreen || fullScreen) return null + const hideButton = activeStack.some(x => hideOnModals.has(x.reactType)) + + if (hideButton || !usingTouch || !document.documentElement.requestFullscreen || fullScreen) return null return + {!lockConnect && <> + + }
} From d02008c2ef4bfff93fad0edbeaffca3d60399bcc Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 11 Jul 2024 18:33:16 +0300 Subject: [PATCH 0199/1097] fix(regression): signs lighting was compltely broken --- prismarine-viewer/viewer/lib/mesher/models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prismarine-viewer/viewer/lib/mesher/models.ts b/prismarine-viewer/viewer/lib/mesher/models.ts index ab77d516..c978c240 100644 --- a/prismarine-viewer/viewer/lib/mesher/models.ts +++ b/prismarine-viewer/viewer/lib/mesher/models.ts @@ -624,7 +624,7 @@ export function getSectionGeometry (sx, sy, sz, world: World) { delete attr.t_uvs attr.positions = new Float32Array(attr.positions) as any - attr.normals = new Int8Array(attr.normals) as any + attr.normals = new Float32Array(attr.normals) as any attr.colors = new Float32Array(attr.colors) as any attr.uvs = new Float32Array(attr.uvs) as any From d0205a970b823ed49e4a01dea237e175a096d777 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 11 Jul 2024 20:08:10 +0300 Subject: [PATCH 0200/1097] up mineflayer for better vehicle move --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 45ebdda4..9d370f17 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -314,7 +314,7 @@ importers: version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/c50afc54e39817f7e4d313ce0f6fdaad71e7e4f4(@types/react@18.2.20)(react@18.2.0) mineflayer: specifier: github:zardoy/mineflayer - version: https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479(encoding@0.1.13) + version: https://codeload.github.com/zardoy/mineflayer/tar.gz/c03c76ef2acfc747bfe8cd1e290106c81f399848(encoding@0.1.13) mineflayer-pathfinder: specifier: ^2.4.4 version: 2.4.4 @@ -6086,8 +6086,8 @@ packages: resolution: {integrity: sha512-QMMNPx4IyZE7ydAzjvGLQLCnQNUOfkk1qVZKxTTS9q3qPTAewz4GhsVUBtbQ8LSbHthe5RcQ1Sgxs4wlIma/Qw==} engines: {node: '>=18'} - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479: - resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479} + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/c03c76ef2acfc747bfe8cd1e290106c81f399848: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/c03c76ef2acfc747bfe8cd1e290106c81f399848} version: 4.20.1 engines: {node: '>=18'} @@ -15825,7 +15825,7 @@ snapshots: - encoding - supports-color - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/dddc683544317f117172077a9245a07be1b12479(encoding@0.1.13): + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/c03c76ef2acfc747bfe8cd1e290106c81f399848(encoding@0.1.13): dependencies: minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13) From 07002a743748899f58767011c3bf99da2658c63b Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 13 Jul 2024 05:49:38 +0300 Subject: [PATCH 0201/1097] fix: remove entities from the scene on login packet (usually on the world switch) --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9d370f17..9deb9a7e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -314,7 +314,7 @@ importers: version: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/c50afc54e39817f7e4d313ce0f6fdaad71e7e4f4(@types/react@18.2.20)(react@18.2.0) mineflayer: specifier: github:zardoy/mineflayer - version: https://codeload.github.com/zardoy/mineflayer/tar.gz/c03c76ef2acfc747bfe8cd1e290106c81f399848(encoding@0.1.13) + version: https://codeload.github.com/zardoy/mineflayer/tar.gz/7f65e46a048f1bc2b57775d84b32400dce707321(encoding@0.1.13) mineflayer-pathfinder: specifier: ^2.4.4 version: 2.4.4 @@ -6086,8 +6086,8 @@ packages: resolution: {integrity: sha512-QMMNPx4IyZE7ydAzjvGLQLCnQNUOfkk1qVZKxTTS9q3qPTAewz4GhsVUBtbQ8LSbHthe5RcQ1Sgxs4wlIma/Qw==} engines: {node: '>=18'} - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/c03c76ef2acfc747bfe8cd1e290106c81f399848: - resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/c03c76ef2acfc747bfe8cd1e290106c81f399848} + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/7f65e46a048f1bc2b57775d84b32400dce707321: + resolution: {tarball: https://codeload.github.com/zardoy/mineflayer/tar.gz/7f65e46a048f1bc2b57775d84b32400dce707321} version: 4.20.1 engines: {node: '>=18'} @@ -15825,7 +15825,7 @@ snapshots: - encoding - supports-color - mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/c03c76ef2acfc747bfe8cd1e290106c81f399848(encoding@0.1.13): + mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/7f65e46a048f1bc2b57775d84b32400dce707321(encoding@0.1.13): dependencies: minecraft-data: 3.65.0 minecraft-protocol: https://codeload.github.com/PrismarineJS/node-minecraft-protocol/tar.gz/495eed56ab230b2615596590064671356d86a2dc(patch_hash=7otpchsbv7hxsuis4rrrwdtbve)(encoding@0.1.13) From 04b5d1ac3f03e5053df6a6142ede7d0c4539d480 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 13 Jul 2024 06:17:47 +0300 Subject: [PATCH 0202/1097] add handled packets stats TODO make auto-updated --- docs-assets/handled-packets.md | 169 +++++++++++++++++++++++++++++++ scripts/updateHandledPackets.mjs | 60 +++++++++++ 2 files changed, 229 insertions(+) create mode 100644 docs-assets/handled-packets.md create mode 100644 scripts/updateHandledPackets.mjs diff --git a/docs-assets/handled-packets.md b/docs-assets/handled-packets.md new file mode 100644 index 00000000..0671987c --- /dev/null +++ b/docs-assets/handled-packets.md @@ -0,0 +1,169 @@ +# Handled Packets + +## Server -> Client + +❌ statistics +❌ advancements +❌ face_player +❌ nbt_query_response +❌ chat_suggestions +❌ trade_list +❌ vehicle_move +❌ open_book +❌ craft_recipe_response +❌ end_combat_event +❌ enter_combat_event +❌ unlock_recipes +❌ camera +❌ update_view_position +❌ update_view_distance +❌ entity_sound_effect +❌ stop_sound +❌ feature_flags +❌ select_advancement_tab +❌ declare_recipes +❌ tags +❌ acknowledge_player_digging +❌ initialize_world_border +❌ world_border_center +❌ world_border_lerp_size +❌ world_border_size +❌ world_border_warning_delay +❌ world_border_warning_reach +❌ simulation_distance +❌ chunk_biomes +❌ damage_event +❌ hurt_animation +✅ spawn_entity +✅ spawn_entity_experience_orb +✅ named_entity_spawn +✅ animation +✅ block_break_animation +✅ tile_entity_data +✅ block_action +✅ block_change +✅ boss_bar +✅ difficulty +✅ tab_complete +✅ declare_commands +✅ multi_block_change +✅ close_window +✅ open_window +✅ window_items +✅ craft_progress_bar +✅ set_slot +✅ set_cooldown +✅ custom_payload +✅ hide_message +✅ kick_disconnect +✅ profileless_chat +✅ entity_status +✅ explosion +✅ unload_chunk +✅ game_state_change +✅ open_horse_window +✅ keep_alive +✅ map_chunk +✅ world_event +✅ world_particles +✅ update_light +✅ login +✅ map +✅ rel_entity_move +✅ entity_move_look +✅ entity_look +✅ open_sign_entity +✅ abilities +✅ player_chat +✅ death_combat_event +✅ player_remove +✅ player_info +✅ position +✅ entity_destroy +✅ remove_entity_effect +✅ resource_pack_send +✅ respawn +✅ entity_head_rotation +✅ held_item_slot +✅ scoreboard_display_objective +✅ entity_metadata +✅ attach_entity +✅ entity_velocity +✅ entity_equipment +✅ experience +✅ update_health +✅ scoreboard_objective +✅ set_passengers +✅ teams +✅ scoreboard_score +✅ spawn_position +✅ update_time +✅ sound_effect +✅ system_chat +✅ playerlist_header +✅ collect +✅ entity_teleport +✅ entity_update_attributes +✅ entity_effect +✅ server_data +✅ clear_titles +✅ action_bar +✅ ping +✅ set_title_subtitle +✅ set_title_text +✅ set_title_time +✅ packet + +## Client -> Server + +❌ query_block_nbt +❌ set_difficulty +❌ query_entity_nbt +❌ pick_item +❌ set_beacon_effect +❌ update_command_block_minecart +❌ update_structure_block +❌ generate_structure +❌ lock_difficulty +❌ craft_recipe_request +❌ displayed_recipe +❌ recipe_book +❌ update_jigsaw_block +❌ spectate +❌ advancement_tab +✅ teleport_confirm +✅ chat_command +✅ chat_message +✅ message_acknowledgement +✅ edit_book +✅ name_item +✅ select_trade +✅ update_command_block +✅ tab_complete +✅ client_command +✅ settings +✅ enchant_item +✅ window_click +✅ close_window +✅ custom_payload +✅ use_entity +✅ keep_alive +✅ position +✅ position_look +✅ look +✅ flying +✅ vehicle_move +✅ steer_boat +✅ abilities +✅ block_dig +✅ entity_action +✅ steer_vehicle +✅ resource_pack_receive +✅ held_item_slot +✅ set_creative_slot +✅ update_sign +✅ arm_animation +✅ block_place +✅ use_item +✅ pong +✅ chat_session_update diff --git a/scripts/updateHandledPackets.mjs b/scripts/updateHandledPackets.mjs new file mode 100644 index 00000000..080eaf44 --- /dev/null +++ b/scripts/updateHandledPackets.mjs @@ -0,0 +1,60 @@ +import fs from 'fs' +import path from 'path' +import minecraftData from 'minecraft-data' + +const lastVersion = minecraftData.versions.pc[0] +// console.log('last proto ver', lastVersion.minecraftVersion) +const allPackets = minecraftData(lastVersion.minecraftVersion).protocol +const getPackets = ({ types }) => { + return Object.keys(types).map(type => type.replace('packet_', '')) +} +// todo test against all versions +const allFromServerPackets = getPackets(allPackets.play.toClient) +const allToServerPackets = getPackets(allPackets.play.toServer).filter(x => !['packet'].includes(x)) + +const buildFile = './dist/index.js' + +const file = fs.readFileSync(buildFile, 'utf8') + +const packetsReceiveRegex = /client\.on\("(\w+)"/g +const packetsReceiveSend = /client\.write\("(\w+)"/g + +let allSupportedReceive = [...new Set([...file.matchAll(packetsReceiveRegex)].map(x => x[1]))] +let allSupportedSend = [...new Set([...file.matchAll(packetsReceiveSend)].map(x => x[1]))] + +let md = '# Handled Packets\n' + +md += '\n## Server -> Client\n\n' +let notSupportedRows = [] +let supportedRows = [] +for (const packet of allFromServerPackets) { + const includes = allSupportedReceive.includes(packet); + (includes ? supportedRows : notSupportedRows).push(packet) +} + +for (const row of notSupportedRows) { + md += `❌ ${row}\n` +} +for (const row of supportedRows) { + md += `✅ ${row}\n` +} + +md += '\n' + +notSupportedRows = [] +supportedRows = [] + +md += '## Client -> Server\n\n' +for (const packet of allToServerPackets) { + const includes = allSupportedSend.includes(packet); + (includes ? supportedRows : notSupportedRows).push(packet) +} + +for (const row of notSupportedRows) { + md += `❌ ${row}\n` +} +for (const row of supportedRows) { + md += `✅ ${row}\n` +} + +fs.writeFileSync('./docs-assets/handled-packets.md', md) From 6c5f72e1f286f2b73f8b940d117b9cec4b197ae1 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 13 Jul 2024 20:31:27 +0300 Subject: [PATCH 0203/1097] feat: implement pitch which was required for note blocks to work properly --- prismarine-viewer/viewer/lib/viewer.ts | 5 +++-- src/soundSystem.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/prismarine-viewer/viewer/lib/viewer.ts b/prismarine-viewer/viewer/lib/viewer.ts index c95127f2..504c4637 100644 --- a/prismarine-viewer/viewer/lib/viewer.ts +++ b/prismarine-viewer/viewer/lib/viewer.ts @@ -32,7 +32,7 @@ export class Viewer { this.world.camera = camera } - constructor(public renderer: THREE.WebGLRenderer, worldConfig = defaultWorldRendererConfig) { + constructor (public renderer: THREE.WebGLRenderer, worldConfig = defaultWorldRendererConfig) { // https://discourse.threejs.org/t/updates-to-color-management-in-three-js-r152/50791 THREE.ColorManagement.enabled = false renderer.outputColorSpace = THREE.LinearSRGBColorSpace @@ -118,7 +118,7 @@ export class Viewer { this.world.updateCamera(pos?.offset(0, yOffset, 0) ?? null, yaw, pitch) } - playSound (position: Vec3, path: string, volume = 1) { + playSound (position: Vec3, path: string, volume = 1, pitch = 1) { if (!this.audioListener) { this.audioListener = new THREE.AudioListener() this.camera.add(this.audioListener) @@ -134,6 +134,7 @@ export class Viewer { sound.setBuffer(buffer) sound.setRefDistance(20) sound.setVolume(volume) + sound.setPlaybackRate(pitch) // set the pitch this.scene.add(sound) // set sound position sound.position.set(position.x, position.y, position.z) diff --git a/src/soundSystem.ts b/src/soundSystem.ts index e7fdaee7..d49b6a8c 100644 --- a/src/soundSystem.ts +++ b/src/soundSystem.ts @@ -50,7 +50,7 @@ subscribeKey(miscUiState, 'gameLoaded', async () => { const isMuted = options.mutedSounds.includes(soundKey) || options.volume === 0 if (position) { if (!isMuted) { - viewer.playSound(position, url, soundVolume * Math.max(Math.min(volume, 1), 0) * (options.volume / 100)) + viewer.playSound(position, url, soundVolume * Math.max(Math.min(volume, 1), 0) * (options.volume / 100), Math.max(Math.min(pitch ?? 1, 2), 0.5)) } if (getDistance(bot.entity.position, position) < 4 * 16) { lastPlayedSounds.lastServerPlayed[soundKey] ??= { count: 0, last: 0 } From b13ef443bb84d4f2f84a4d11bc0f25ffc8d4840c Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 13 Jul 2024 21:30:44 +0300 Subject: [PATCH 0204/1097] feat: rework sound system. Now sounds are 100% implemented for all current & future supported versions --- prismarine-viewer/viewer/prepare/utils.ts | 14 ++++++ src/globals.d.ts | 2 +- src/soundSystem.ts | 53 ++++++++++++----------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/prismarine-viewer/viewer/prepare/utils.ts b/prismarine-viewer/viewer/prepare/utils.ts index a33909a9..958273f3 100644 --- a/prismarine-viewer/viewer/prepare/utils.ts +++ b/prismarine-viewer/viewer/prepare/utils.ts @@ -2,3 +2,17 @@ export const versionToNumber = (ver: string) => { const [x, y = '0', z = '0'] = ver.split('.') return +`${x.padStart(2, '0')}${y.padStart(2, '0')}${z.padStart(2, '0')}` } + +export const versionToMajor = (version: string) => { + const [x, y = '0'] = version.split('.') + return `${x.padStart(2, '0')}.${y.padStart(2, '0')}` +} + +export const versionsMapToMajor = (versionsMap: Record) => { + const majorVersions = {} as Record + for (const [ver, data] of Object.entries(versionsMap)) { + const major = versionToMajor(ver) + majorVersions[major] = data + } + return majorVersions +} diff --git a/src/globals.d.ts b/src/globals.d.ts index 05b29a14..f8699f21 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -17,7 +17,7 @@ declare const worldView: import('prismarine-viewer/viewer/lib/worldDataEmitter') declare const localServer: import('flying-squid/dist/index').FullServer & { options } | undefined /** all currently loaded mc data */ declare const mcData: Record -declare const loadedData: import('minecraft-data').IndexedData +declare const loadedData: import('minecraft-data').IndexedData & { sounds: Record } declare const customEvents: import('typed-emitter').default<{ /** Singleplayer load requested */ singleplayer (): void diff --git a/src/soundSystem.ts b/src/soundSystem.ts index d49b6a8c..0187a9b0 100644 --- a/src/soundSystem.ts +++ b/src/soundSystem.ts @@ -1,6 +1,6 @@ import { subscribeKey } from 'valtio/utils' import { Vec3 } from 'vec3' -import { versionToNumber } from 'prismarine-viewer/viewer/prepare/utils' +import { versionToMajor, versionToNumber, versionsMapToMajor } from 'prismarine-viewer/viewer/prepare/utils' import { loadScript } from 'prismarine-viewer/viewer/lib/utils' import type { Block } from 'prismarine-block' import { miscUiState } from './globalState' @@ -22,32 +22,26 @@ subscribeKey(miscUiState, 'gameLoaded', async () => { return } - // todo also use major versioned hardcoded sounds - const soundsMap = allSoundsMap[bot.version] + const allSoundsMajor = versionsMapToMajor(allSoundsMap) + const soundsMap = allSoundsMajor[versionToMajor(bot.version)] ?? Object.values(allSoundsMajor)[0] - if (!soundsMap || !miscUiState.gameLoaded || !soundsMap) { + if (!soundsMap || !miscUiState.gameLoaded || !loadedData.sounds) { return } - const soundsPerId = Object.fromEntries(Object.entries(soundsMap).map(([id, sound]) => [+id.split(';')[0], sound])) + // const soundsPerId = Object.fromEntries(Object.entries(soundsMap).map(([id, sound]) => [+id.split(';')[0], sound])) const soundsPerName = Object.fromEntries(Object.entries(soundsMap).map(([id, sound]) => [id.split(';')[1], sound])) - const soundIdToName = Object.fromEntries(Object.entries(soundsMap).map(([id, sound]) => [+id.split(';')[0], id.split(';')[1]])) - const playGeneralSound = async (soundId: string, soundString: string | undefined, position?: Vec3, volume = 1, pitch?: number) => { - if (!soundString) { - console.warn('Unknown sound received from server to play', soundId) - return - } + const playGeneralSound = async (soundKey: string, position?: Vec3, volume = 1, pitch?: number) => { if (!options.volume) return - const parts = soundString.split(';') - const soundVolume = +parts[0]! - const soundName = parts[1]! - // console.log('pitch', pitch) - const versionedSound = getVersionedSound(bot.version, soundName, Object.entries(soundsLegacyMap)) + const soundStaticData = soundsPerName[soundKey]?.split(';') + if (!soundStaticData) return + const soundVolume = +soundStaticData[0]! + const soundPath = soundStaticData[1]! + const versionedSound = getVersionedSound(bot.version, soundPath, Object.entries(soundsLegacyMap)) // todo test versionedSound - const url = allSoundsMeta.baseUrl.replace(/\/$/, '') + (versionedSound ? `/${versionedSound}` : '') + '/minecraft/sounds/' + soundName + '.' + allSoundsMeta.format - const soundKey = soundIdToName[+soundId] ?? soundId - const isMuted = options.mutedSounds.includes(soundKey) || options.volume === 0 + const url = allSoundsMeta.baseUrl.replace(/\/$/, '') + (versionedSound ? `/${versionedSound}` : '') + '/minecraft/sounds/' + soundPath + '.' + allSoundsMeta.format + const isMuted = options.mutedSounds.includes(soundKey) || options.mutedSounds.includes(soundPath) || options.volume === 0 if (position) { if (!isMuted) { viewer.playSound(position, url, soundVolume * Math.max(Math.min(volume, 1), 0) * (options.volume / 100), Math.max(Math.min(pitch ?? 1, 2), 0.5)) @@ -67,17 +61,24 @@ subscribeKey(miscUiState, 'gameLoaded', async () => { } } } - const playHardcodedSound = async (soundId: string, position?: Vec3, volume = 1, pitch?: number) => { - const sound = soundsPerName[soundId] - await playGeneralSound(soundId, sound, position, volume, pitch) + const playHardcodedSound = async (soundKey: string, position?: Vec3, volume = 1, pitch?: number) => { + await playGeneralSound(soundKey, position, volume, pitch) } bot.on('soundEffectHeard', async (soundId, position, volume, pitch) => { - console.debug('soundEffectHeard', soundId, volume) await playHardcodedSound(soundId, position, volume, pitch) }) - bot.on('hardcodedSoundEffectHeard', async (soundId, soundCategory, position, volume, pitch) => { - const sound = soundsPerId[soundId] - await playGeneralSound(soundId.toString(), sound, position, volume, pitch) + bot.on('hardcodedSoundEffectHeard', async (soundIdNum, soundCategory, position, volume, pitch) => { + const fixOffset = versionToNumber('1.20.4') === versionToNumber(bot.version) ? -1 : 0 + const soundKey = loadedData.sounds[soundIdNum + fixOffset]?.name + if (soundKey === undefined) return + await playGeneralSound(soundKey, position, volume, pitch) + }) + // workaround as mineflayer doesn't support soundEvent + bot._client.on('sound_effect', async (packet) => { + const soundResource = packet['soundEvent']?.resource as string | undefined + if (packet.soundId !== 0 || !soundResource) return + const pos = new Vec3(packet.x / 8, packet.y / 8, packet.z / 8) + await playHardcodedSound(soundResource.replace('minecraft:', ''), pos, packet.volume, packet.pitch) }) bot.on('entityHurt', async (entity) => { if (entity.id === bot.entity.id) { From 698779f6b5302165dd3dff731de0b223ac837513 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 13 Jul 2024 21:31:29 +0300 Subject: [PATCH 0205/1097] fix: toggle entity visiiblity even after it's creation --- prismarine-viewer/viewer/lib/entities.js | 10 +++++----- prismarine-viewer/viewer/lib/worldDataEmitter.ts | 9 ++++++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/prismarine-viewer/viewer/lib/entities.js b/prismarine-viewer/viewer/lib/entities.js index 94f06e0c..d36b6936 100644 --- a/prismarine-viewer/viewer/lib/entities.js +++ b/prismarine-viewer/viewer/lib/entities.js @@ -405,14 +405,14 @@ export class Entities extends EventEmitter { } //@ts-ignore + // set visibility const isInvisible = entity.metadata?.[0] & 0x20 - if (isInvisible) { - for (const child of this.entities[entity.id].children.find(c => c.name === 'mesh').children) { - if (child.name !== 'nametag') { - child.visible = false - } + for (const child of this.entities[entity.id].children.find(c => c.name === 'mesh').children) { + if (child.name !== 'nametag') { + child.visible = !isInvisible } } + // --- // not player const displayText = entity.metadata?.[3] && this.parseEntityLabel(entity.metadata[2]) if (entity.name !== 'player' && displayText) { diff --git a/prismarine-viewer/viewer/lib/worldDataEmitter.ts b/prismarine-viewer/viewer/lib/worldDataEmitter.ts index 5df5cc73..761509c2 100644 --- a/prismarine-viewer/viewer/lib/worldDataEmitter.ts +++ b/prismarine-viewer/viewer/lib/worldDataEmitter.ts @@ -44,7 +44,14 @@ export class WorldDataEmitter extends EventEmitter { listenToBot (bot: typeof __type_bot) { const emitEntity = (e) => { if (!e || e === bot.entity) return - this.emitter.emit('entity', { ...e, pos: e.position, username: e.username }) + this.emitter.emit('entity', { + ...e, + pos: e.position, + username: e.username, + // set debugTree (obj) { + // e.debugTree = obj + // } + }) } this.eventListeners[bot.username] = { From 512bc09477aa96352f4d19a165a7e110d5c76f81 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 14 Jul 2024 01:55:41 +0300 Subject: [PATCH 0206/1097] make main docker build 5x smaller, add only proxy dockerfile --- Dockerfile | 32 +++++++++++++++++++++----------- Dockerfile.proxy | 11 +++++++++++ README.MD | 15 +++++++++++---- 3 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 Dockerfile.proxy diff --git a/Dockerfile b/Dockerfile index 086240b5..0ae1c6e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,32 @@ -FROM node:18-alpine +# ---- Build Stage ---- +FROM node:18-alpine AS build # Without git installing the npm packages fails -RUN apk add git -RUN mkdir /app +RUN apk add --no-cache git python3 make g++ cairo-dev pango-dev jpeg-dev giflib-dev librsvg-dev WORKDIR /app COPY . /app -# install python and other dependencies -RUN apk add python3 make g++ cairo-dev pango-dev jpeg-dev giflib-dev librsvg-dev # install pnpm RUN npm i -g pnpm@9.0.4 RUN pnpm install -# only for prod -RUN pnpm run build -# --- -EXPOSE 8080 -# uncomment for development + +# TODO for development # EXPOSE 9090 # VOLUME /app/src # VOLUME /app/prismarine-viewer # ENTRYPOINT ["pnpm", "run", "run-all"] + # only for prod -ENTRYPOINT ["npm", "run", "prod-start"] +RUN pnpm run build + +# ---- Run Stage ---- +FROM node:18-alpine +RUN apk add git +WORKDIR /app +# Copy build artifacts from the build stage +COPY --from=build /app/dist /app/dist +COPY server.js /app/server.js +# Install express +RUN npm i -g pnpm@9.0.4 +RUN npm init -yp +RUN pnpm i express github:zardoy/prismarinejs-net-browserify compression cors +EXPOSE 8080 +ENTRYPOINT ["node", "server.js"] diff --git a/Dockerfile.proxy b/Dockerfile.proxy new file mode 100644 index 00000000..746eef72 --- /dev/null +++ b/Dockerfile.proxy @@ -0,0 +1,11 @@ +# ---- Run Stage ---- +FROM node:18-alpine +RUN apk add git +WORKDIR /app +COPY server.js /app/server.js +# Install server dependencies +RUN npm i -g pnpm@9.0.4 +RUN npm init -yp +RUN pnpm i express github:zardoy/prismarinejs-net-browserify compression cors +EXPOSE 8080 +ENTRYPOINT ["node", "server.js"] diff --git a/README.MD b/README.MD index 9a4ba24a..7576f6ba 100644 --- a/README.MD +++ b/README.MD @@ -44,6 +44,13 @@ See the [Mineflayer](https://github.com/PrismarineJS/mineflayer) repo for the li There is a builtin proxy, but you can also host your one! Just clone the repo, run `pnpm i` (following CONTRIBUTING.MD) and run `pnpm prod-start`, then you can specify `http://localhost:8080` in the proxy field. MS account authentication will be supported soon. +### Docker Files + +- [Main Dockerfile](./Dockerfile) - for production build & offline/private usage. Includes full web-app + proxy server for connecting to Minecraft servers. +- [Proxy Dockerfile](./Dockerfile.proxy) - for proxy server only - that one you would be able to specify in the proxy field on the client (`docker build . -f Dockerfile.proxy -t minecraft-web-proxy`) + +In case of using docker, you don't have to follow preparation steps from CONTRIBUTING.MD, like installing Node.js, pnpm, etc. + ### Rendering #### Three.js Renderer @@ -55,10 +62,6 @@ MS account authentication will be supported soon. -### Things that are not planned yet - -- Mods, plugins (basically JARs) support, shaders - since they all are related to specific game pipelines - ### Advanced Settings There are many many settings, that are not exposed in the UI yet. You can find or change them by opening the browser console and typing `options`. You can also change them by typing `options. = `. @@ -131,6 +134,10 @@ Press `Y` to set query parameters to url of your current game state. - [Peer.js](https://peerjs.com/) - P2P networking (when you open to wan) - [Three.js](https://threejs.org/) - Helping in 3D rendering +### Things that are not planned yet + +- Mods, plugins (basically JARs) support, shaders - since they all are related to specific game pipelines + ### Alternatives - [https://github.com/ClassiCube/ClassiCube](ClassiCube - Better C# Rewrite) [DEMO](https://www.classicube.net/server/play/?warned=true) From b49e9880906f269b1be6456abcdb24f78e45f21e Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 16 Jul 2024 10:35:01 +0300 Subject: [PATCH 0207/1097] fix: inventory didn't update after dropping an item --- src/controls.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/controls.ts b/src/controls.ts index a3a22029..98cc6afb 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -353,7 +353,7 @@ contro.on('trigger', ({ command }) => { document.exitPointerLock?.() openPlayerInventory() break - case 'general.drop': + case 'general.drop': { // if (bot.heldItem/* && ctrl */) bot.tossStack(bot.heldItem) bot._client.write('block_dig', { 'status': 4, @@ -365,7 +365,14 @@ contro.on('trigger', ({ command }) => { 'face': 0, sequence: 0 }) + const slot = bot.inventory.hotbarStart + bot.quickBarSlot + const item = bot.inventory.slots[slot] + if (item) { + item.count-- + bot.inventory.updateSlot(slot, item.count > 0 ? item : null!) + } break + } case 'general.chat': showModal({ reactType: 'chat' }) break From 9ee67cc8270e79e5b2d9025a30148bb083e8c36d Mon Sep 17 00:00:00 2001 From: Wolf2323 Date: Tue, 16 Jul 2024 10:37:01 +0200 Subject: [PATCH 0208/1097] fix: ignoring exception ResizeObserver loop exceptions (#161) --- src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/index.ts b/src/index.ts index e34e81ab..2a190785 100644 --- a/src/index.ts +++ b/src/index.ts @@ -330,6 +330,9 @@ async function connect (connectOptions: ConnectOptions) { } const handleError = (err) => { console.error(err) + if (err === 'ResizeObserver loop completed with undelivered notifications.') { + return + } errorAbortController.abort() if (isCypress()) throw err miscUiState.hasErrors = true From cda1d59d3bd59580d91f4107a8b4a8bfae57c976 Mon Sep 17 00:00:00 2001 From: Wolf2323 Date: Tue, 16 Jul 2024 11:05:57 +0200 Subject: [PATCH 0209/1097] improved query parameters handling (#162) Co-authored-by: Vitaly --- README.MD | 25 ++++++++++------- src/react/AddServerOrConnect.tsx | 46 +++++++++++++++++++------------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/README.MD b/README.MD index 7576f6ba..cafa3ac9 100644 --- a/README.MD +++ b/README.MD @@ -110,19 +110,26 @@ world chunks have a *yellow* border, hostile mobs have a *red* outline, passive Press `Y` to set query parameters to url of your current game state. -- `?ip=` - Display connect screen to the server on load -- `?username=` - Set the username for server -- `?proxy=` - Set the proxy server address to use for server -- `?version=` - Set the version for server -- `?lockConnect=true` - Disable cancel / save buttons, useful for integrates iframes +There are some parameters you can set in the url to archive some specific behaviors: + +Server specific: +- `?ip=` - Display connect screen to the server on load with predefined server ip. `:` is optional and can be added to the ip. +- `?name=` - Set the server name for saving to the server list +- `?version=` - Set the version for the server +- `?proxy=` - Set the proxy server address to use for the server +- `?username=` - Set the username for the server +- `?lockConnect=true` - Only works then `ip` parameter is set. Disables cancel/save buttons and all inputs in the connect screen already set as parameters. Useful for integrates iframes. - `?reconnect=true` - Reconnect to the server on page reloads. Available in **dev mode only** and very useful on server testing. + +Single player specific: - `?loadSave=` - Load the save on load with the specified folder name (not title) - `?singleplayer=1` - Create empty world on load. Nothing will be saved -- `?noSave=true` - Disable auto save on unload / disconnect / export. Only manual save with `/save` command will work - - +- `?version=` - Set the version for the singleplayer world (when used with `?singleplayer=1`) +- `?noSave=true` - Disable auto save on unload / disconnect / export whenever a world is loaded. Only manual save with `/save` command will work. - `?map=` - Load the map from ZIP. You can use any url, but it must be CORS enabled. -- `?setting=:` - Set the and lock the setting on load. You can set multiple settings by separating them with `&` e.g. `?setting=autoParkour:true&setting=renderDistance:4` + +General: +- `?setting=:` - Set and lock the setting on load. You can set multiple settings by separating them with `&` e.g. `?setting=autoParkour:true&setting=renderDistance:4` ### Notable Things that Power this Project diff --git a/src/react/AddServerOrConnect.tsx b/src/react/AddServerOrConnect.tsx index 729f1ec2..535e3ee9 100644 --- a/src/react/AddServerOrConnect.tsx +++ b/src/react/AddServerOrConnect.tsx @@ -30,19 +30,25 @@ const ELEMENTS_WIDTH = 190 export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQs, onQsConnect, defaults, accounts, authenticatedAccounts }: Props) => { const qsParams = parseQs ? new URLSearchParams(window.location.search) : undefined + const qsParamName = qsParams?.get('name') + const qsParamIp = qsParams?.get('ip') + const qsParamVersion = qsParams?.get('version') + const qsParamProxy = qsParams?.get('proxy') + const qsParamUsername = qsParams?.get('username') + const qsParamLockConnect = qsParams?.get('lockConnect') - const [serverName, setServerName] = React.useState(initialData?.name ?? qsParams?.get('name') ?? '') + const qsIpParts = qsParamIp?.split(':') + const ipParts = initialData?.ip.split(':') - const ipWithoutPort = initialData?.ip.split(':')[0] - const port = initialData?.ip.split(':')[1] + const [serverName, setServerName] = React.useState(initialData?.name ?? qsParamName ?? '') + const [serverIp, setServerIp] = React.useState(ipParts?.[0] ?? qsIpParts?.[0] ?? '') + const [serverPort, setServerPort] = React.useState(ipParts?.[1] ?? qsIpParts?.[1] ?? '') + const [versionOverride, setVersionOverride] = React.useState(initialData?.versionOverride ?? /* legacy */ initialData?.['version'] ?? qsParamVersion ?? '') + const [proxyOverride, setProxyOverride] = React.useState(initialData?.proxyOverride ?? qsParamProxy ?? '') + const [usernameOverride, setUsernameOverride] = React.useState(initialData?.usernameOverride ?? qsParamUsername ?? '') + const lockConnect = qsParamLockConnect === 'true' - const [serverIp, setServerIp] = React.useState(ipWithoutPort ?? qsParams?.get('ip') ?? '') - const [serverPort, setServerPort] = React.useState(port ?? '') - const [versionOverride, setVersionOverride] = React.useState(initialData?.versionOverride ?? /* legacy */ initialData?.['version'] ?? qsParams?.get('version') ?? '') - const [proxyOverride, setProxyOverride] = React.useState(initialData?.proxyOverride ?? qsParams?.get('proxy') ?? '') - const [usernameOverride, setUsernameOverride] = React.useState(initialData?.usernameOverride ?? qsParams?.get('username') ?? '') const smallWidth = useIsSmallWidth() - const lockConnect = qsParams?.get('lockConnect') === 'true' const initialAccount = initialData?.authenticatedAccountOverride const [accountIndex, setAccountIndex] = React.useState(initialAccount === true ? -2 : initialAccount ? (accounts?.includes(initialAccount) ? accounts.indexOf(initialAccount) : -2) : -1) @@ -61,7 +67,7 @@ export default ({ onBack, onConfirm, title = 'Add a Server', initialData, parseQ authenticatedAccountOverride, } - return + return
-
- setServerName(value)} placeholder='Defaults to IP' /> -
- setServerIp(value)} /> - setServerPort(value)} placeholder='25565' /> + {!lockConnect && <> +
+ setServerName(value)} placeholder='Defaults to IP' /> +
+ } + setServerIp(value)} /> + setServerPort(value)} placeholder='25565' />
Overrides:
- setVersionOverride(value)} placeholder='Optional, but recommended to specify' /> - setProxyOverride(value)} placeholder={defaults?.proxyOverride} /> - setUsernameOverride(value)} placeholder={defaults?.usernameOverride} disabled={!noAccountSelected} /> + setVersionOverride(value)} placeholder='Optional, but recommended to specify' /> + setProxyOverride(value)} placeholder={defaults?.proxyOverride} /> + setUsernameOverride(value)} placeholder={defaults?.usernameOverride} />